mirror of
https://github.com/esphome/esphome.git
synced 2026-09-12 15:57:33 +00:00
Merge branch 'nrf52-pch' into esp8266-native-parallel-extract
This commit is contained in:
@@ -21,6 +21,7 @@ binary_sensor:
|
||||
name: Test Binary Sensor with Lambda
|
||||
register_type: input
|
||||
address: 0x3201
|
||||
reuse_previous_range: false
|
||||
lambda: |-
|
||||
return x;
|
||||
|
||||
@@ -85,6 +86,7 @@ select:
|
||||
name: Test Select with Lambda
|
||||
address: 1001
|
||||
value_type: U_WORD
|
||||
reuse_previous_range: auto
|
||||
optionsmap:
|
||||
"Off": 0
|
||||
"On": 1
|
||||
@@ -140,9 +142,10 @@ sensor:
|
||||
register_type: holding
|
||||
address: 0x9002
|
||||
value_type: U_WORD
|
||||
reuse_previous_range: true
|
||||
lambda: |-
|
||||
return x / 10.0;
|
||||
# Non-mergeable sensor sharing the start address of modbus_sensor1 (different register_count):
|
||||
# Non-mergeable sensor sharing the start address of modbus_sensor1 (different value type width):
|
||||
# must join the same range, never open a second range keyed on the same (address, type).
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: modbus_controller1
|
||||
@@ -187,8 +190,8 @@ sensor:
|
||||
value_type: U_WORD
|
||||
lambda: |-
|
||||
return modbus_controller::get_data<uint16_t>(data, item->offset) * 0.1f;
|
||||
# force_new_range sensors sort before plain ones, so this high-address forced sensor is grouped
|
||||
# first and the lower-address plain sensors above must still get their own ranges.
|
||||
# The deprecated force_new_range migrates to reuse_previous_range: false, so this sensor never
|
||||
# joins a range built before it and the lower-address sensors above keep their own ranges.
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: modbus_controller1
|
||||
id: modbus_sensor_forced_high
|
||||
@@ -224,7 +227,6 @@ text_sensor:
|
||||
name: Test Text Sensor
|
||||
register_type: holding
|
||||
address: 0x9013
|
||||
register_count: 3
|
||||
raw_encode: HEXBYTES
|
||||
response_size: 6
|
||||
- platform: modbus_controller
|
||||
@@ -233,12 +235,13 @@ text_sensor:
|
||||
name: Test Text Sensor with Lambda
|
||||
register_type: holding
|
||||
address: 0x9014
|
||||
register_count: 2
|
||||
response_size: 4
|
||||
lambda: |-
|
||||
return "Modified: " + x;
|
||||
# A register reporting FEWER bytes than 2*register_count (response_size: 3 for 2 registers), followed
|
||||
# by a contiguous sensor: the follower's byte position must track the actual 3 bytes, not underflow.
|
||||
# A register reporting FEWER bytes than two per register (response_size: 3 over 2 registers), followed
|
||||
# by a contiguous reuse:true sensor (auto never joins past a response_size register): the follower's
|
||||
# byte position must track the actual 3 bytes, not underflow.
|
||||
# register_count matches the derived width, so it migrates with a deprecation warning.
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: modbus_controller1
|
||||
id: modbus_text_sensor_narrow
|
||||
@@ -255,4 +258,5 @@ text_sensor:
|
||||
register_type: holding
|
||||
address: 0x9032
|
||||
register_count: 1
|
||||
reuse_previous_range: true
|
||||
raw_encode: HEXBYTES
|
||||
|
||||
@@ -27,8 +27,8 @@ uart_mock:
|
||||
# so these also pin the grouping: an extra or differently shaped read fails the test.
|
||||
- expect_tx: [0x01, 0x01, 0x00, 0x10, 0x00, 0x02, 0xBC, 0x0E] # coils 0x10 count 2
|
||||
inject_rx: [0x01, 0x01, 0x01, 0x01, 0x90, 0x48] # bit0 set, bit1 clear
|
||||
- expect_tx: [0x01, 0x03, 0x01, 0x60, 0x00, 0x01, 0x85, 0xE8] # holding 0x160 count 1
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x01, 0x60, 0xB9, 0xFC] # 352
|
||||
- expect_tx: [0x01, 0x03, 0x01, 0x60, 0x00, 0x02, 0xC5, 0xE9] # holding 0x160 count 2
|
||||
inject_rx: [0x01, 0x03, 0x04, 0x01, 0x60, 0x01, 0x61, 0x3B, 0xA9] # 352, 353
|
||||
- expect_tx: [0x01, 0x03, 0x01, 0x00, 0x00, 0x01, 0x85, 0xF6] # holding 0x100 count 1
|
||||
inject_rx: [0x01, 0x03, 0x04, 0x01, 0x11, 0x02, 0x22, 0x2A, 0xB3] # 4 bytes: 273 then 546
|
||||
- expect_tx: [0x01, 0x03, 0x01, 0x20, 0x00, 0x04, 0x44, 0x3F] # holding 0x120 count 4
|
||||
@@ -49,8 +49,6 @@ uart_mock:
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x33, 0x33, 0xEC, 0xA1] # 13107
|
||||
- expect_tx: [0x01, 0x03, 0x01, 0x70, 0x00, 0x03, 0x05, 0xEC] # holding 0x170 count 3
|
||||
inject_rx: [0x01, 0x03, 0x06, 0x00, 0x2A, 0x1B, 0x2C, 0x03, 0x0D, 0x3E, 0xAB] # 6 bytes
|
||||
- expect_tx: [0x01, 0x03, 0x01, 0x61, 0x00, 0x01, 0xD4, 0x28] # holding 0x161 count 1
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x01, 0x61, 0x78, 0x3C] # 353
|
||||
|
||||
modbus:
|
||||
uart_id: virtual_uart_dev
|
||||
@@ -104,8 +102,9 @@ sensor:
|
||||
value_type: U_DWORD
|
||||
modbus_controller_id: modbus_controller_ok
|
||||
|
||||
# D - a wide (response_size) register followed by a contiguous one: the follower must start after the
|
||||
# bytes the wide register actually returned, not after 2 * register_count.
|
||||
# D - a wide (response_size) register followed by a contiguous reuse:true one (auto never joins past
|
||||
# a response_size register): the follower must start after the bytes the wide register actually
|
||||
# returned, not after two per register.
|
||||
- platform: modbus_controller
|
||||
name: "wide_first"
|
||||
address: 0x130
|
||||
@@ -118,6 +117,7 @@ sensor:
|
||||
address: 0x131
|
||||
register_type: holding
|
||||
value_type: U_WORD
|
||||
reuse_previous_range: true
|
||||
modbus_controller_id: modbus_controller_ok
|
||||
|
||||
# E - a gap: these must never share a range.
|
||||
@@ -195,13 +195,14 @@ sensor:
|
||||
value_type: U_WORD
|
||||
modbus_controller_id: modbus_controller_ok
|
||||
|
||||
# H - a sensor pinned to its own range, followed by a contiguous one.
|
||||
# H - a sensor that never joins the range built before it (reuse_previous_range: false), followed
|
||||
# by a contiguous plain item that extends the new range it started.
|
||||
- platform: modbus_controller
|
||||
name: "forced_first"
|
||||
address: 0x160
|
||||
register_type: holding
|
||||
value_type: U_WORD
|
||||
force_new_range: true
|
||||
reuse_previous_range: false
|
||||
modbus_controller_id: modbus_controller_ok
|
||||
- platform: modbus_controller
|
||||
name: "forced_next"
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
esphome:
|
||||
name: uart-mock-modbus-ranges-test
|
||||
|
||||
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
|
||||
|
||||
# Each expect_tx below pins the exact read request the controller's range builder emits, so this
|
||||
# fixture is a wire-level test of reuse_previous_range (auto/yes/no), gap joins, same-register reuse,
|
||||
# response_size surplus accounting, and RAW/text block reads.
|
||||
uart_mock:
|
||||
- id: virtual_uart_dev
|
||||
baud_rate: 9600
|
||||
rx_full_threshold: 120
|
||||
rx_timeout: 2
|
||||
# auto_start must be false to avoid races: the test presses the
|
||||
# "Start Scenario" button only after subscribing to states.
|
||||
auto_start: false
|
||||
debug:
|
||||
responses:
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x00, 0x00, 0x03, 0x05, 0xCB] # auto adjacency: one read covers 0x00-0x02
|
||||
inject_rx: [0x01, 0x03, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0xFD, 0x74]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x10, 0x00, 0x01, 0x85, 0xCF] # auto gap: 0x10 alone
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x00, 0x04, 0xB9, 0x87]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x13, 0x00, 0x01, 0x75, 0xCF] # auto gap: 0x13 alone
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x00, 0x05, 0x78, 0x47]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x20, 0x00, 0x04, 0x45, 0xC3] # yes across gap: one read 0x20-0x23, gap registers ignored
|
||||
inject_rx: [0x01, 0x03, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x33, 0xD1]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x30, 0x00, 0x01, 0x84, 0x05] # no isolation: 0x30 alone despite adjacency
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x00, 0x0A, 0x38, 0x43]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x31, 0x00, 0x01, 0xD5, 0xC5] # no isolation: 0x31 alone
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x00, 0x0B, 0xF9, 0x83]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x3F, 0x00, 0x01, 0xB4, 0x06] # open NEVER: 0x3F alone (the reuse:false item split off)
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x00, 0x0C, 0xB8, 0x41]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x40, 0x00, 0x02, 0xC5, 0xDF] # open NEVER: 0x40 (reuse: false) still extended by the auto item at 0x41
|
||||
inject_rx: [0x01, 0x03, 0x04, 0x00, 0x0D, 0x00, 0x0E, 0xEA, 0x34]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x50, 0x00, 0x01, 0x84, 0x1B] # same-address reuse: one read, two sensors on 0x50
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x12, 0x34, 0xB5, 0x33]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x60, 0x00, 0x04, 0x44, 0x17] # text block + adjacent word: one read 0x60-0x63
|
||||
inject_rx: [0x01, 0x03, 0x08, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x00, 0x0F, 0x78, 0x0E]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x70, 0x00, 0x02, 0xC5, 0xD0] # response_size surplus: 0x70 answers 4 bytes, reuse:true word at 0x71 shifted along
|
||||
inject_rx: [0x01, 0x03, 0x06, 0x00, 0x10, 0xAA, 0xBB, 0x00, 0x11, 0x71, 0x47]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x90, 0x00, 0x01, 0x84, 0x27] # auto after surplus: 0x90 alone (auto never joins past response_size)
|
||||
inject_rx: [0x01, 0x03, 0x04, 0x00, 0x18, 0xCC, 0xDD, 0xEF, 0x6D]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x91, 0x00, 0x01, 0xD5, 0xE7] # auto after surplus: 0x91 alone
|
||||
inject_rx: [0x01, 0x03, 0x02, 0x00, 0x19, 0x79, 0x8E]
|
||||
- expect_tx: [0x01, 0x03, 0x00, 0x80, 0x00, 0x04, 0x45, 0xE1] # RAW block via response_size: 8 bytes = 4 registers in one read
|
||||
inject_rx: [0x01, 0x03, 0x08, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x6D, 0xDF]
|
||||
|
||||
modbus:
|
||||
uart_id: virtual_uart_dev
|
||||
send_wait_time: 200ms
|
||||
turnaround_time: 10ms
|
||||
|
||||
modbus_controller:
|
||||
- address: 1
|
||||
id: ranges_controller
|
||||
max_cmd_retries: 0
|
||||
# The test triggers a single poll by pressing the "Start Scenario" button
|
||||
update_interval: never
|
||||
|
||||
sensor:
|
||||
# Case 1: three adjacent registers merge into one read (auto default)
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "adjacent_a"
|
||||
register_type: holding
|
||||
address: 0x00
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "adjacent_b"
|
||||
register_type: holding
|
||||
address: 0x01
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "adjacent_c"
|
||||
register_type: holding
|
||||
address: 0x02
|
||||
|
||||
# Case 2: a gap keeps auto items apart
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "gap_a"
|
||||
register_type: holding
|
||||
address: 0x10
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "gap_b"
|
||||
register_type: holding
|
||||
address: 0x13
|
||||
|
||||
# Case 3: reuse_previous_range: true bridges the gap into one read
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "bridge_a"
|
||||
register_type: holding
|
||||
address: 0x20
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "bridge_b"
|
||||
register_type: holding
|
||||
address: 0x23
|
||||
reuse_previous_range: true
|
||||
|
||||
# Case 4: reuse_previous_range: false splits adjacent registers
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "split_a"
|
||||
register_type: holding
|
||||
address: 0x30
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "split_b"
|
||||
register_type: holding
|
||||
address: 0x31
|
||||
reuse_previous_range: false
|
||||
|
||||
# Case 5: a reuse:false item starts its own range but stays open for later auto items
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "open_prev"
|
||||
register_type: holding
|
||||
address: 0x3F
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "open_never"
|
||||
register_type: holding
|
||||
address: 0x40
|
||||
reuse_previous_range: false
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "open_tagalong"
|
||||
register_type: holding
|
||||
address: 0x41
|
||||
|
||||
# Case 6: two sensors on the same register share one read
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "shared_lo"
|
||||
register_type: holding
|
||||
address: 0x50
|
||||
bitmask: 0x00FF
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "shared_hi"
|
||||
register_type: holding
|
||||
address: 0x50
|
||||
bitmask: 0xFF00
|
||||
|
||||
# Case 10 (text block, see text_sensor below) shares the range with this word at 0x63
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "after_text"
|
||||
register_type: holding
|
||||
address: 0x63
|
||||
|
||||
# Case 11: response_size surplus — the device answers 4 bytes for this single register, so the
|
||||
# following sensor's data sits 2 bytes later than its address alone implies. Joining past a
|
||||
# non-standard response_size takes an explicit reuse_previous_range: true.
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "surplus"
|
||||
register_type: holding
|
||||
address: 0x70
|
||||
response_size: 4
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "after_surplus"
|
||||
register_type: holding
|
||||
address: 0x71
|
||||
reuse_previous_range: true
|
||||
|
||||
# Case 13: auto never joins past a response_size register — despite adjacency these poll separately
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "surplus_split"
|
||||
register_type: holding
|
||||
address: 0x90
|
||||
response_size: 4
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "after_surplus_split"
|
||||
register_type: holding
|
||||
address: 0x91
|
||||
|
||||
# Case 12: RAW + response_size reads a block of ceil(8/2) = 4 registers
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "raw_block"
|
||||
register_type: holding
|
||||
address: 0x80
|
||||
value_type: RAW
|
||||
response_size: 8
|
||||
lambda: |-
|
||||
return (float) data.size();
|
||||
|
||||
text_sensor:
|
||||
# Case 10: text sensor reads 3 registers (response_size 6)
|
||||
- platform: modbus_controller
|
||||
modbus_controller_id: ranges_controller
|
||||
name: "text_block"
|
||||
register_type: holding
|
||||
address: 0x60
|
||||
response_size: 6
|
||||
raw_encode: NONE
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: "Start Scenario"
|
||||
id: start_scenario_btn
|
||||
on_press:
|
||||
- lambda: |-
|
||||
id(virtual_uart_dev).start_scenario();
|
||||
id(ranges_controller).set_update_interval(1000);
|
||||
id(ranges_controller).start_poller();
|
||||
@@ -32,9 +32,9 @@ uart_mock:
|
||||
# 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.
|
||||
# A sensor at 0x30 with the deprecated force_new_range (migrates to reuse_previous_range: false)
|
||||
# and a plain sensor at 0x10. The two must poll as separate ranges: the 0x10 sensor must not be
|
||||
# absorbed into the isolated 0x30 range.
|
||||
- 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)
|
||||
@@ -87,7 +87,7 @@ sensor:
|
||||
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
|
||||
# Isolated sensor (deprecated spelling, migrates to reuse_previous_range: false): own range
|
||||
- platform: modbus_controller
|
||||
name: "forced_high"
|
||||
address: 0x30
|
||||
@@ -95,7 +95,7 @@ sensor:
|
||||
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
|
||||
# Plain sensor at a lower address: must get its own range, never absorbed into the isolated one
|
||||
- platform: modbus_controller
|
||||
name: "plain_low"
|
||||
address: 0x10
|
||||
|
||||
@@ -21,7 +21,7 @@ import asyncio
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from aioesphomeapi import ButtonInfo, NumberInfo, SwitchInfo
|
||||
from aioesphomeapi import ButtonInfo, NumberInfo, SwitchInfo, TextSensorState
|
||||
import pytest
|
||||
|
||||
from .state_utils import SensorTracker, find_entity, wait_for_state
|
||||
@@ -1158,3 +1158,78 @@ async def test_uart_mock_modbus_deprecated_write_buffer(
|
||||
assert warn_count == 1, (
|
||||
f"deprecation warning should fire exactly once per entity, got {warn_count}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uart_mock_modbus_ranges(
|
||||
yaml_config: str,
|
||||
run_compiled: RunCompiledFunction,
|
||||
api_client_connected: APIClientConnectedFactory,
|
||||
) -> None:
|
||||
"""Wire-level test of the range builder's reuse_previous_range semantics.
|
||||
|
||||
Every expect_tx in the fixture pins the exact read request the controller emits, so a
|
||||
wrongly merged or split range fails on the mock before any value arrives. Covers: auto
|
||||
adjacency merging, auto gap splitting, reuse:true bridging a gap (with correct data
|
||||
offsets past the gap), reuse:false splitting adjacent registers while staying open for
|
||||
later auto items, two sensors sharing one register, a text block read sized by
|
||||
response_size with a following word, response_size surplus shifting a later reuse:true
|
||||
sensor's bytes while an auto sensor refuses to join past the surplus, and a RAW block
|
||||
read of ceil(response_size / 2) registers.
|
||||
"""
|
||||
|
||||
line_callback, error_log_lines, warning_log_lines = _make_modbus_line_callback()
|
||||
|
||||
expected_values = {
|
||||
"adjacent_a": 1,
|
||||
"adjacent_b": 2,
|
||||
"adjacent_c": 3,
|
||||
"gap_a": 4,
|
||||
"gap_b": 5,
|
||||
"bridge_a": 6,
|
||||
"bridge_b": 9,
|
||||
"split_a": 10,
|
||||
"split_b": 11,
|
||||
"open_prev": 12,
|
||||
"open_never": 13,
|
||||
"open_tagalong": 14,
|
||||
"shared_lo": 0x34,
|
||||
"shared_hi": 0x12,
|
||||
"after_text": 15,
|
||||
"surplus": 16,
|
||||
"after_surplus": 17,
|
||||
"surplus_split": 24,
|
||||
"after_surplus_split": 25,
|
||||
"raw_block": 8, # the RAW lambda publishes data.size(): 4 registers = 8 bytes
|
||||
}
|
||||
tracker = SensorTracker(list(expected_values.keys()))
|
||||
futures = tracker.expect_all(expected_values)
|
||||
|
||||
# The tracker only handles numeric sensors; capture the text block separately.
|
||||
text_future: asyncio.Future = asyncio.get_running_loop().create_future()
|
||||
tracker_on_state = tracker.on_state
|
||||
|
||||
def on_state(state) -> None:
|
||||
if (
|
||||
isinstance(state, TextSensorState)
|
||||
and not state.missing_state
|
||||
and state.state == "ABCDEF"
|
||||
and not text_future.done()
|
||||
):
|
||||
text_future.set_result(True)
|
||||
tracker_on_state(state)
|
||||
|
||||
tracker.on_state = on_state
|
||||
|
||||
async with (
|
||||
run_compiled(yaml_config, line_callback=line_callback),
|
||||
api_client_connected() as client,
|
||||
):
|
||||
await tracker.setup_and_start_scenario(client)
|
||||
await tracker.await_all(futures)
|
||||
# text_block is not tracker-registered (non-numeric), so time out explicitly.
|
||||
try:
|
||||
await asyncio.wait_for(text_future, timeout=5.0)
|
||||
except TimeoutError:
|
||||
pytest.fail("text_block never published 'ABCDEF'")
|
||||
_assert_no_modbus_errors(error_log_lines, warning_log_lines)
|
||||
|
||||
Reference in New Issue
Block a user