Files
esphome/tests/integration/fixtures/uart_mock_modbus_shared_address.yaml
T

161 lines
6.7 KiB
YAML

esphome:
name: uart-mock-modbus-shared
host:
api:
logger:
level: VERBOSE
external_components:
- source:
type: local
path: EXTERNAL_COMPONENT_PATH
# Dummy uart entry to satisfy modbus's DEPENDENCIES = ["uart"]
# The actual UART bus used is the uart_mock component below
uart:
baud_rate: 115200
port: /dev/null
uart_mock:
- id: virtual_uart_dev
baud_rate: 9600
rx_full_threshold: 120
rx_timeout: 2
auto_start: false
debug:
responses:
# Three sensors, one frame. At 0x9001 a U_WORD (1 register) and a U_DWORD (2 registers) share the
# start address but cannot merge, so the range widens to count 2. A third sensor at 0x9002 falls
# inside the widened range and must read its slice of the same response rather than splitting into
# a second overlapping poll. The single expect_tx pins the "one frame on the wire" contract - any
# duplicate or overlapping range would put an extra frame on the bus and fail to match.
- expect_tx: [0x01, 0x03, 0x90, 0x01, 0x00, 0x02, 0xB8, 0xCB] # Read holding 0x9001 count 2 on device 1
inject_rx: [0x01, 0x03, 0x04, 0x03, 0x97, 0x02, 0x91, 0x8B, 0x57] # 0x9001=0x0397, 0x9002=0x0291
# A force_new_range sensor at a HIGH address (0x30) sorts before the plain sensor at a LOW address
# (0x10). The two must poll as separate ranges: the covered branch's lower-bound check prevents the
# 0x10 sensor from being absorbed into the forced 0x30 range with a wrapped byte offset.
- expect_tx: [0x01, 0x03, 0x00, 0x30, 0x00, 0x01, 0x84, 0x05] # Read holding 0x30 count 1 (forced range)
inject_rx: [0x01, 0x03, 0x02, 0x01, 0x11, 0x79, 0xD8] # 0x30 = 0x0111 = 273
- expect_tx: [0x01, 0x03, 0x00, 0x10, 0x00, 0x01, 0x85, 0xCF] # Read holding 0x10 count 1 (own range)
inject_rx: [0x01, 0x03, 0x02, 0x02, 0x22, 0x39, 0x3D] # 0x10 = 0x0222 = 546
# A wide sensor (U_QWORD at 0x100, 4 registers) followed by plain sensors at 0x101 and 0x103.
# None of them merge, so all three poll separately - exactly as before the range refactor. The
# 0x103 sensor sits at the wide range's tail address, so it must not anchor a re-use join on a
# mid-range predecessor and inherit its byte offset.
- expect_tx: [0x01, 0x03, 0x01, 0x00, 0x00, 0x04, 0x45, 0xF5] # Read holding 0x100 count 4
inject_rx: [0x01, 0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x94, 0x3C] # = 100
- expect_tx: [0x01, 0x03, 0x01, 0x01, 0x00, 0x01, 0xD4, 0x36] # Read holding 0x101 count 1
inject_rx: [0x01, 0x03, 0x02, 0x01, 0x41, 0x79, 0xE4] # 0x101 = 0x0141 = 321
- expect_tx: [0x01, 0x03, 0x01, 0x03, 0x00, 0x01, 0x75, 0xF6] # Read holding 0x103 count 1
inject_rx: [0x01, 0x03, 0x02, 0x01, 0xA5, 0x79, 0xAF] # 0x103 = 0x01A5 = 421
# A widened shared-address range at 0x200 plus a sensor at 0x201 carrying its own skip_updates.
# The sensor must keep its own range so the polling rates stay independent; if it were folded into
# the widened range it would decode 0x201 from THAT response (2, not 777) and drag the range's
# rate down to its own.
- expect_tx: [0x01, 0x03, 0x02, 0x00, 0x00, 0x02, 0xC5, 0xB3] # Read holding 0x200 count 2
inject_rx: [0x01, 0x03, 0x04, 0x01, 0x41, 0x00, 0x02, 0x2A, 0x1A] # 0x200=0x0141, 0x201=0x0002
- expect_tx: [0x01, 0x03, 0x02, 0x01, 0x00, 0x01, 0xD4, 0x72] # Read holding 0x201 count 1
inject_rx: [0x01, 0x03, 0x02, 0x03, 0x09, 0x78, 0xB2] # 0x201 = 0x0309 = 777
modbus:
uart_id: virtual_uart_dev
send_wait_time: 200ms
turnaround_time: 10ms
modbus_controller:
- address: 1
id: modbus_controller_ok
max_cmd_retries: 2
update_interval: never
sensor:
# Word sensor at 0x9001 (1 register)
- platform: modbus_controller
name: "shared_word"
address: 0x9001
register_type: holding
value_type: U_WORD
modbus_controller_id: modbus_controller_ok
# Dword sensor at the SAME address 0x9001 (2 registers) - non-mergeable, shares the range start
- platform: modbus_controller
name: "shared_dword"
address: 0x9001
register_type: holding
value_type: U_DWORD
modbus_controller_id: modbus_controller_ok
# Word sensor at 0x9002 - inside the widened range, reads bytes 2-3 of the same response
- platform: modbus_controller
name: "covered_word"
address: 0x9002
register_type: holding
value_type: U_WORD
modbus_controller_id: modbus_controller_ok
# Forced sensor at a high address: sorts first, opens its own isolated range
- platform: modbus_controller
name: "forced_high"
address: 0x30
register_type: holding
value_type: U_WORD
force_new_range: true
modbus_controller_id: modbus_controller_ok
# Plain sensor at a lower address: must get its own range, never absorbed into the forced one
- platform: modbus_controller
name: "plain_low"
address: 0x10
register_type: holding
value_type: U_WORD
modbus_controller_id: modbus_controller_ok
# Wide sensor spanning 0x100-0x103; the two sensors below sit inside its span but do not merge
- platform: modbus_controller
name: "wide_qword"
address: 0x100
register_type: holding
value_type: U_QWORD
modbus_controller_id: modbus_controller_ok
- platform: modbus_controller
name: "inside_wide"
address: 0x101
register_type: holding
value_type: U_WORD
modbus_controller_id: modbus_controller_ok
# At the wide range's tail address: must decode its own poll, not inherit a mid-range byte offset
- platform: modbus_controller
name: "tail_of_wide"
address: 0x103
register_type: holding
value_type: U_WORD
modbus_controller_id: modbus_controller_ok
# Shared address 0x200: the dword widens the range the word opened (or vice versa)
- platform: modbus_controller
name: "rate_word"
address: 0x200
register_type: holding
value_type: U_WORD
modbus_controller_id: modbus_controller_ok
- platform: modbus_controller
name: "rate_dword"
address: 0x200
register_type: holding
value_type: U_DWORD
modbus_controller_id: modbus_controller_ok
# Inside the widened range but with its own skip_updates: must NOT be folded in, or the two sensors
# above would silently drop to this sensor's polling rate
- platform: modbus_controller
name: "own_rate"
address: 0x201
register_type: holding
value_type: U_WORD
skip_updates: 100
modbus_controller_id: modbus_controller_ok
button:
- platform: template
name: "Start Scenario"
id: start_scenario_btn
on_press:
- lambda: |-
id(virtual_uart_dev).start_scenario();
id(modbus_controller_ok).set_update_interval(1000);
id(modbus_controller_ok).start_poller();