diff --git a/.github/workflows/auto-label-pr.yml b/.github/workflows/auto-label-pr.yml index ce7bbd64ec..0e8ec8e17d 100644 --- a/.github/workflows/auto-label-pr.yml +++ b/.github/workflows/auto-label-pr.yml @@ -26,7 +26,7 @@ jobs: if: github.event.action != 'labeled' || github.event.sender.type != 'Bot' steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Generate a token id: generate-token diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93c2653124..112d1dea4b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: repo: cloudcannon/pagefind - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Set up Hugo uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0 @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Set up Python 3.12 uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c633d435a4..dff43d1803 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -28,7 +28,7 @@ jobs: repo: cloudcannon/pagefind - name: Checkout source code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Set up QEMU uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3 diff --git a/content/components/lvgl/widgets.md b/content/components/lvgl/widgets.md index 06b441e50b..550bde74b4 100644 --- a/content/components/lvgl/widgets.md +++ b/content/components/lvgl/widgets.md @@ -1538,7 +1538,6 @@ The `slider` can be also integrated as {{< docref "/components/number/lvgl" "Num See [Light brightness slider](/cookbook/lvgl#lvgl-cookbook-bright) and [Media player volume slider](/cookbook/lvgl#lvgl-cookbook-volume) for examples which demonstrate how to use a slider to control entities in Home Assistant. -{{< anchor "lvgl-widget-canvas" >}} {{< anchor "lvgl-widget-spinbox" >}} ## `spinbox` @@ -1589,7 +1588,7 @@ The spinbox contains a numeric value (as text) which can be increased or decreas text_align: center range_from: -10 range_to: 40 - step: 0.5 + selected_digit: 2 digits: 3 decimal_places: 1 diff --git a/content/components/modbus.md b/content/components/modbus.md index 3e2b589a4e..d07a0c99c8 100644 --- a/content/components/modbus.md +++ b/content/components/modbus.md @@ -43,13 +43,15 @@ modbus: - **flow_control_pin** (*Optional*, [Pin](/guides/configuration-types#pin)): The pin used to switch flow control. This is useful for RS485 transceivers that do not have automatic flow control switching, - like the common MAX485. + like the common MAX485. If your UART support `flow_control_pin` you should preferentially set it in the `uart` component over the `mobus` component. -- **send_wait_time** (*Optional*, [Time](/guides/configuration-types#time)): Time in milliseconds before the next ModBUS command is sent when an answer from a previous command has not yet started (i.e. when to timeout and assume no response is coming). Defaults to 250 ms. +- **send_wait_time** (*Optional*, [Time](/guides/configuration-types#time)): Time in milliseconds before the next ModBUS command is sent when an answer from a previous command has not yet started (i.e. when to timeout and assume no response is coming). Defaults to 2000 ms. Set this value to the maximum time required for the slowest device on the bus to begin responding (time to first byte). If a device starts responding within this time, the next command will be queued and sent after the response is finished, no matter how long the response. -- **disable_crc** (*Optional*, boolean): Ignores a bad CRC if set to `true`. Defaults to `false` +- **turnaround_time** (*Optional*, [Time](#config-time)): Time in milliseconds before the next ModBUS command is sent after last response is received (i.e. how long to allow all devices to process messages on the bus). Defaults to 600 ms. + Set this value to the maximum time required for the slowest device on the bus to process a message and be ready to process another. Note that all devices hear all messages, so will need to process them even if they don't need to reply. + If devices don't respond sometimes, it can help to increase this value. - **role** (*Optional*, string): The role of this component, `client` or `server`. Defaults to `client`. @@ -57,6 +59,7 @@ modbus: - {{< docref "/components/modbus_controller" >}} - {{< docref "/components/sensor/modbus_controller" >}} +- {{< docref "/components/sensor/modbus_server" >}} - {{< docref "/components/binary_sensor/modbus_controller" >}} - {{< docref "/components/output/modbus_controller" >}} - {{< docref "/components/switch/modbus_controller" >}} diff --git a/content/components/modbus_controller.md b/content/components/modbus_controller.md index c89784dd33..2d183da0de 100644 --- a/content/components/modbus_controller.md +++ b/content/components/modbus_controller.md @@ -7,12 +7,9 @@ params: image: modbus.png --- -The `modbus_controller` component creates a RS485 connection to either: +The `modbus_controller` component creates a RS485 connection to control a Modbus server (slave) device, letting your ESPHome node to act as a Modbus client (master). You can access the coils, inputs, holding, read registers from your devices as sensors, switches, selects, numbers or various other ESPHome components and present them to your favorite Home Automation system. You can even write them as binary or float ouptputs from ESPHome. -- control a Modbus server (slave) device, letting your ESPHome node to act as a Modbus client (master). You can access the coils, inputs, holding, read registers from your devices as sensors, switches, selects, numbers or various other ESPHome components and present them to your favorite Home Automation system. You can even write them as binary or float ouptputs from ESPHome. -- let your ESPHome node act as a Modbus server, allowing a ModBUS client to read data (like sensor values) from your ESPHome node. - -To choose the role, set the `role` attribute of the {{< docref "/components/modbus" >}} upon which this `modbus_controller` component relies. `client` is the default. +Set the `role` attribute of the {{< docref "/components/modbus" >}} upon which this `modbus_controller` component relies to `client`, which is the default. {{< img src="modbus.png" alt="Image" width="25%" class="align-center" >}} @@ -68,44 +65,6 @@ On the bus side, you need 120 Ohm termination resistors at the ends of the bus c - **max_cmd_retries** (*Optional*, integer): How many times a command will be retried if no response is received. It doesn't include the initial transmition. Defaults to 4. -- **server_courtesy_response** (*Optional*): Configuration block to enable the courtesy response feature when the device is acting as a Modbus server. - - - **enabled** (*Optional*, boolean): Whether to enable the courtesy response feature. - Defaults to `false`. - - **register_last_address** (*Optional*, integer): The highest Modbus register address (inclusive) up to which undefined registers are allowed to be read and will be padded with a default value. - Any read request that includes undefined registers within this range will return the value specified by `register_value` instead of triggering an exception. - Defaults to `65535` - - **register_value** (*Optional*, integer): The 16-bit value (range: 0–65535) to return for undefined registers within the address range defined by `register_last_address`. - Defaults to `0`. - -- **server_registers** (*Optional*): A list of registers that are responded to when acting as a server. - - - **address** (**Required**, integer): start address of the first register in a range - - **value_type** (*Optional*): datatype of the mod_bus register data. The default data type for ModBUS is a 16 bit integer in **big endian** format (network byte order, MSB first) - - - `U_WORD` : unsigned 16 bit integer, 1 register, `uint16_t` - - `S_WORD` : signed 16 bit integer, 1 register, `int16_t` - - `U_DWORD` : unsigned 32 bit integer, 2 registers, `uint32_t` - - `S_DWORD` : signed 32 bit integer, 2 registers, `int32_t` - - `U_DWORD_R` : **little endian** unsigned 32 bit integer, 2 registers, `uint32_t` - - `S_DWORD_R` : **little endian** signed 32 bit integer, 2 registers, `int32_t` - - `U_QWORD` : unsigned 64 bit integer, 4 registers, `uint64_t` - - `S_QWORD` : signed 64 bit integer, 4 registers `int64_t` - - `U_QWORD_R` : **little endian** unsigned 64 bit integer, 4 registers, `uint64_t` - - `S_QWORD_R` : **little endian** signed 64 bit integer, 4 registers, `int64_t` - - `FP32` : 32 bit IEEE 754 floating point, 2 registers, `float` - - `FP32_R` : **little endian** 32 bit IEEE 754 floating point, 2 registers, `float` - - Defaults to `U_WORD`. - - - **read_lambda** (**Required**, [lambda](/automations/templates#config-lambda)): - Lambda that returns the value of this register. - - - **write_lambda** (*Optional*, [lambda](/automations/templates#config-lambda)): - Lambda that sets the value of this register. A variable `x` of the appropriate type (`uint16_t`, `int32_t`, etc, see above) is provided with the value, - as well as `address` containing the address of this register. You must return `true` if the operation was successful, `false` otherwise, in which case - a ModBUS exception code `4` will be sent to the client. - Automations: - **on_command_sent** (*Optional*, [Automation](/automations)): An automation to perform when a modbus command has been sent. See [`on_command_sent`](#modbus_controller-on_command_sent) @@ -191,6 +150,8 @@ modbus_controller: modbus_id: modbus_client address: 0x2 update_interval: 5s + +modbus_server: - modbus_id: modbus_server address: 0x4 server_registers: @@ -734,6 +695,7 @@ modbus_controller: - {{< docref "/components/modbus" >}} - {{< docref "/components/sensor/modbus_controller" >}} +- {{< docref "/components/sensor/modbus_server" >}} - {{< docref "/components/binary_sensor/modbus_controller" >}} - {{< docref "/components/output/modbus_controller" >}} - {{< docref "/components/switch/modbus_controller" >}} diff --git a/content/components/modbus_server.md b/content/components/modbus_server.md new file mode 100644 index 0000000000..3a7733756d --- /dev/null +++ b/content/components/modbus_server.md @@ -0,0 +1,131 @@ +--- +description: "Instructions for setting up the Modbus Server component." +title: "Modbus Server" +params: + seo: + description: Instructions for setting up the Modbus Server component. + image: modbus.png +--- + +The `modbus_server` component creates a RS485 connection to let your ESPHome node act as a Modbus server, allowing a ModBUS client to read data (like sensor values) from your ESPHome node. + +You must set the `role` attribute of the {{< docref "/components/modbus" >}} to `server`. + +{{< img src="modbus.png" alt="Image" width="25%" class="align-center" >}} + +## Hardware setup + +You need an RS485 transceiver module: + +{{< img src="rs485.jpg" alt="Image" >}} + +See [How is this RS485 module working?](https://electronics.stackexchange.com/questions/244425/how-is-this-rs485-module-working) on stackexchange for more details. + +The transceiver connects to the UART of the MCU. For ESP32, pin `16` to `TXD` and pin `17` to `RXD` are the default ones but any other pins can be used as well. `3.3V` to `VCC` and naturally `GND` to `GND`. + +On the bus side, you need 120 Ohm termination resistors at the ends of the bus cable as per Modbus standard. Some transceivers have this already soldered onboard, while some slave devices may have them available via a jumper or a DIP switch. + +{{< note >}} +If you are using an ESP8266, serial logging may cause problems reading from UART. For best results, hardware serial is recommended. Software serial may not be able to read all received data if other components spend a lot of time in the `loop()`. + +For hardware serial only a limited set of pins can be used. Either `tx_pin: GPIO1` and `rx_pin: GPIO3` or `tx_pin: GPIO15` and `rx_pin: GPIO13`. + +The disadvantage of using the hardware UART is that you can't use serial logging because the serial logs would be sent to the Modbus device(s) instead, causing errors. + +Serial logging can be disabled by setting `baud_rate: 0`. + +See {{< docref "logger/" >}} for more details + +```yaml +logger: + level: + baud_rate: 0 +``` + +{{< /note >}} + +## Configuration variables + +- **modbus_id** (*Optional*, [ID](#config-id)): Manually specify the ID of the `modbus` hub. + +- **address** (**Required**, [ID](#config-id)): The Modbus address of the server device. + +- **server_courtesy_response** (*Optional*): Configuration block to enable the courtesy response feature when the device is acting as a Modbus server. + + - **enabled** (*Optional*, boolean): Whether to enable the courtesy response feature. + Defaults to `false`. + - **register_last_address** (*Optional*, integer): The highest Modbus register address (inclusive) up to which undefined registers are allowed to be read and will be padded with a default value. + Any read request that includes undefined registers within this range will return the value specified by `register_value` instead of triggering an exception. + Defaults to `65535` + - **register_value** (*Optional*, integer): The 16-bit value (range: 0–65535) to return for undefined registers within the address range defined by `register_last_address`. + Defaults to `0`. + +- **server_registers** (*Optional*): A list of registers that are responded to when acting as a server. + + - **address** (**Required**, integer): start address of the first register in a range + - **value_type** (*Optional*): datatype of the mod_bus register data. The default data type for ModBUS is a 16 bit integer in **big endian** format (network byte order, MSB first) + + - `U_WORD` : unsigned 16 bit integer, 1 register, `uint16_t` + - `S_WORD` : signed 16 bit integer, 1 register, `int16_t` + - `U_DWORD` : unsigned 32 bit integer, 2 registers, `uint32_t` + - `S_DWORD` : signed 32 bit integer, 2 registers, `int32_t` + - `U_DWORD_R` : **little endian** unsigned 32 bit integer, 2 registers, `uint32_t` + - `S_DWORD_R` : **little endian** signed 32 bit integer, 2 registers, `int32_t` + - `U_QWORD` : unsigned 64 bit integer, 4 registers, `uint64_t` + - `S_QWORD` : signed 64 bit integer, 4 registers `int64_t` + - `U_QWORD_R` : **little endian** unsigned 64 bit integer, 4 registers, `uint64_t` + - `S_QWORD_R` : **little endian** signed 64 bit integer, 4 registers, `int64_t` + - `FP32` : 32 bit IEEE 754 floating point, 2 registers, `float` + - `FP32_R` : **little endian** 32 bit IEEE 754 floating point, 2 registers, `float` + + Defaults to `U_WORD`. + + - **read_lambda** (**Required**, [lambda](/automations/templates#config-lambda)): + Lambda that returns the value of this register. + + - **write_lambda** (*Optional*, [lambda](/automations/templates#config-lambda)): + Lambda that sets the value of this register. A variable `x` of the appropriate type (`uint16_t`, `int32_t`, etc, see above) is provided with the value, + as well as `address` containing the address of this register. You must return `true` if the operation was successful, `false` otherwise, in which case + a ModBUS exception code `4` will be sent to the client. + +## Example + +The following code allows a ModBUS client to read a sensor value from your ESPHome node, that the node itself read from some local sensor. + +```yaml +uart: + - id: uart_modbus_server + tx_pin: 25 + rx_pin: 35 + +modbus: + - uart_id: uart_modbus_server + id: modbus_server + role: server + +modbus_server: + - modbus_id: modbus_server + address: 0x4 + server_registers: + - address: 0x0002 + value_type: U_DWORD_R + read_lambda: |- + return id(uptime_sens).state; + +sensor: + - platform: uptime + id: uptime_sens +``` + + +## See Also + +- {{< docref "/components/modbus" >}} +- {{< docref "/components/sensor/modbus_controller" >}} +- {{< docref "/components/binary_sensor/modbus_controller" >}} +- {{< docref "/components/output/modbus_controller" >}} +- {{< docref "/components/switch/modbus_controller" >}} +- {{< docref "/components/number/modbus_controller" >}} +- {{< docref "/components/select/modbus_controller" >}} +- {{< docref "/components/text_sensor/modbus_controller" >}} +- [Modbus RTU Protocol Description](https://www.modbustools.com/modbus.html) diff --git a/content/cookbook/lvgl.md b/content/cookbook/lvgl.md index 0dbaf7b1b9..219982e814 100644 --- a/content/cookbook/lvgl.md +++ b/content/cookbook/lvgl.md @@ -523,7 +523,7 @@ lvgl: width: 50 range_from: 15 range_to: 35 - step: 0.5 + selected_digit: 0 rollover: false digits: 3 decimal_places: 1