mirror of
https://github.com/esphome/esphome.git
synced 2026-08-22 22:26:21 +00:00
149 lines
6.6 KiB
YAML
149 lines
6.6 KiB
YAML
# The modbus_client actions are self-contained hub devices: each takes the hub (auto-resolved when there
|
|
# is a single modbus client hub) and a templatable device address; no component block is needed. The
|
|
# address is not passed back to reply handlers - recompute the configured expression if needed.
|
|
# The hub does not bound retries, so a retry lambda must (here: a counter capped at 3), or a dead
|
|
# device is retried forever. Reset the counter before the send or on a terminal outcome (on_response)
|
|
# so the cap is per transaction, not per device lifetime. Never reset in on_sent: it fires again on
|
|
# every retry, so the cap would never be reached.
|
|
|
|
# The standalone component: a bare hub device with nothing but an address, so a lambda can drive the
|
|
# device directly. Two entries cover both hub-binding paths - the auto-resolved single hub and an
|
|
# explicit modbus_id - and the button below calls them, so the generated device has to be usable
|
|
# rather than merely constructed (an unreferenced one is optimised away entirely).
|
|
modbus_client:
|
|
- id: bare_client
|
|
address: 0x01
|
|
- id: bare_client_explicit_hub
|
|
modbus_id: modbus_bus
|
|
address: 0x02
|
|
|
|
globals:
|
|
- id: read_retries
|
|
type: int
|
|
initial_value: "0"
|
|
- id: combined_retries
|
|
type: int
|
|
initial_value: "0"
|
|
|
|
button:
|
|
# The bare modbus_client devices: no handlers, so nothing reports the outcome - see the component
|
|
# comment. Calls here only pin that the device is bound to its hub and the helpers are reachable.
|
|
- platform: template
|
|
name: "Bare Client"
|
|
on_press:
|
|
- lambda: |-
|
|
id(bare_client).write_single_register(0x10, 42);
|
|
id(bare_client).write_single_coil(0x01, true);
|
|
id(bare_client_explicit_hub).read_holding_registers(0x20, 4);
|
|
const uint16_t rw_vals[] = {1, 2};
|
|
id(bare_client).read_write_multiple_registers(0x0400, 2, 0x0300, rw_vals);
|
|
- platform: template
|
|
name: "Send Read"
|
|
on_press:
|
|
- lambda: "id(read_retries) = 0;"
|
|
- modbus_client.send:
|
|
address: 0x01
|
|
pdu: [0x03, 0x00, 0x10, 0x00, 0x01]
|
|
# on_no_response lambda form: return true to retry. `request` is the timed-out PDU.
|
|
on_no_response: !lambda "return !request.empty() && request[0] == 0x03 && id(read_retries)++ < 3;"
|
|
# Per-send inline reply handlers (fire-and-continue): they run when this send's outcome is known;
|
|
# the targeted address is not passed back - recompute the configured expression if needed.
|
|
# A pdu lambda can hand-assemble bytes or return a modbus::helpers::create_*_pdu() builder result.
|
|
- modbus_client.send:
|
|
address: 0x01
|
|
pdu: !lambda "return modbus::helpers::create_read_pdu(modbus::FunctionCode::READ_HOLDING_REGISTERS, 0x0010, 1);"
|
|
- modbus_client.send:
|
|
address: !lambda "return 1;"
|
|
pdu: !lambda "return {0x03, 0x00, 0x10, 0x00, 0x01};"
|
|
on_sent:
|
|
then:
|
|
- lambda: 'ESP_LOGI("modbus_client.test", "sent fc 0x%X", request.empty() ? 0 : request[0]);'
|
|
on_response:
|
|
then:
|
|
- lambda: |-
|
|
id(combined_retries) = 0;
|
|
ESP_LOGI("modbus_client.test", "got %d bytes", (int) response.size());
|
|
on_error:
|
|
then:
|
|
- lambda: 'ESP_LOGW("modbus_client.test", "fc 0x%X exception %d", request.empty() ? 0 : request[0], (int) exception_code);'
|
|
# on_no_response combined form: run actions on timeout AND decide the retry via nested retry:.
|
|
on_no_response:
|
|
then:
|
|
- lambda: 'ESP_LOGW("modbus_client.test", "no reply for fc 0x%X", request.empty() ? 0 : request[0]);'
|
|
retry: !lambda "return !request.empty() && request[0] == 0x03 && id(combined_retries)++ < 3;"
|
|
on_not_sent:
|
|
then:
|
|
- lambda: 'ESP_LOGW("modbus_client.test", "not sent fc 0x%X", request.empty() ? 0 : request[0]);'
|
|
- platform: template
|
|
name: "Typed Actions"
|
|
on_press:
|
|
- modbus_client.write_single_register:
|
|
address: 0x01
|
|
start_address: 0x0102
|
|
value: !lambda "return 42;"
|
|
on_response:
|
|
then:
|
|
- logger.log: "write acked"
|
|
on_error:
|
|
then:
|
|
- lambda: 'ESP_LOGW("modbus_client.test", "write exception %d", (int) exception_code);'
|
|
- modbus_client.read_holding_registers:
|
|
address: !lambda "return 1;"
|
|
start_address: 0x10
|
|
count: 2
|
|
on_response:
|
|
then:
|
|
- lambda: 'ESP_LOGI("modbus_client.test", "first=%u n=%u", values[0], (unsigned) values.size());'
|
|
on_no_response:
|
|
then:
|
|
- logger.log: "typed read timeout"
|
|
- modbus_client.read_input_registers:
|
|
address: 0x01
|
|
start_address: 0x20
|
|
on_custom_response:
|
|
then:
|
|
- lambda: |-
|
|
ESP_LOGW("modbus_client.test", "non-standard reply: fc 0x%02X, %u byte request",
|
|
response.empty() ? 0 : response[0], (unsigned) request.size());
|
|
- modbus_client.write_single_coil:
|
|
address: 0x01
|
|
start_address: 0x01
|
|
value: true
|
|
- modbus_client.read_coils:
|
|
address: 0x01
|
|
start_address: 0x03
|
|
count: 16
|
|
on_response:
|
|
then:
|
|
- lambda: 'ESP_LOGI("modbus_client.test", "coil0=%d n=%u", bits[0], (unsigned) bits.size());'
|
|
- modbus_client.read_discrete_inputs:
|
|
address: 0x01
|
|
start_address: 0x00
|
|
on_error:
|
|
then:
|
|
- lambda: 'ESP_LOGW("modbus_client.test", "fc 0x%X exception %d", request.empty() ? 0 : request[0], (int) exception_code);'
|
|
- modbus_client.write_multiple_registers:
|
|
address: 0x01
|
|
start_address: 0x0200
|
|
values: !lambda "return {1, 2, 3};"
|
|
on_response:
|
|
then:
|
|
- lambda: 'ESP_LOGI("modbus_client.test", "multi write acked");'
|
|
- modbus_client.write_multiple_coils:
|
|
address: 0x01
|
|
start_address: 0x0010
|
|
values: [true, false, true]
|
|
on_error:
|
|
then:
|
|
- lambda: 'ESP_LOGW("modbus_client.test", "fc 0x%X exception %d", request.empty() ? 0 : request[0], (int) exception_code);'
|
|
- modbus_client.read_write_multiple_registers:
|
|
address: 0x01
|
|
write_address: 0x0300
|
|
values: !lambda "return {1, 2};"
|
|
read_address: 0x0400
|
|
read_count: 2
|
|
on_response:
|
|
then:
|
|
# `values` here is the READ-BACK block, not the written block above
|
|
- lambda: 'ESP_LOGI("modbus_client.test", "rw read0=%u n=%u", values[0], (unsigned) values.size());'
|