Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/auto-label-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions content/components/lvgl/widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions content/components/modbus.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,23 @@ 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`.

## See Also

- {{< 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" >}}
Expand Down
48 changes: 5 additions & 43 deletions content/components/modbus_controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -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" >}}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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" >}}
Expand Down
131 changes: 131 additions & 0 deletions content/components/modbus_server.md
Original file line number Diff line number Diff line change
@@ -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: <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
```


Check failure on line 120 in content/components/modbus_server.md

View workflow job for this annotation

GitHub Actions / Lint

Multiple consecutive blank lines [Expected: 1; Actual: 2]

Check failure on line 120 in content/components/modbus_server.md

View workflow job for this annotation

GitHub Actions / Lint

Multiple consecutive blank lines [Expected: 1; Actual: 2]
## 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)
2 changes: 1 addition & 1 deletion content/cookbook/lvgl.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading