mirror of
https://github.com/esphome/esphome.git
synced 2026-09-17 18:18:43 +00:00
80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
"""A modbus_controller cannot poll the broadcast address (0) unless allow_broadcast_read says the
|
|
device answers it."""
|
|
|
|
import pytest
|
|
|
|
from esphome import config_validation as cv
|
|
from esphome.components import modbus
|
|
from esphome.components.modbus_controller import CONFIG_SCHEMA
|
|
from esphome.const import CONF_ADDRESS
|
|
from esphome.types import ConfigType
|
|
|
|
|
|
def _controller(address: int, **extra: object) -> ConfigType:
|
|
return CONFIG_SCHEMA({modbus.CONF_MODBUS_ID: "bus", CONF_ADDRESS: address, **extra})
|
|
|
|
|
|
def test_address_zero_rejected_by_default() -> None:
|
|
with pytest.raises(cv.Invalid, match="broadcast address"):
|
|
_controller(0)
|
|
|
|
|
|
def test_address_zero_accepted_with_allow_broadcast_read() -> None:
|
|
config = _controller(0, **{modbus.CONF_ALLOW_BROADCAST_READ: True})
|
|
assert config[CONF_ADDRESS] == 0
|
|
assert config[modbus.CONF_ALLOW_BROADCAST_READ] is True
|
|
|
|
|
|
def test_allow_broadcast_read_defaults_false() -> None:
|
|
assert _controller(1)[modbus.CONF_ALLOW_BROADCAST_READ] is False
|
|
|
|
|
|
def test_writer_entity_takes_expect_broadcast_write_response() -> None:
|
|
# The write-side option lives on the writing platforms, not the controller.
|
|
from esphome.components.modbus_controller.const import CONF_MODBUS_CONTROLLER_ID
|
|
from esphome.components.modbus_controller.switch import (
|
|
CONFIG_SCHEMA as SWITCH_SCHEMA,
|
|
)
|
|
from esphome.const import CONF_NAME
|
|
|
|
key = modbus.CONF_EXPECT_BROADCAST_WRITE_RESPONSE
|
|
base = {
|
|
CONF_MODBUS_CONTROLLER_ID: "ctl",
|
|
CONF_NAME: "Switch",
|
|
"register_type": "coil",
|
|
CONF_ADDRESS: 0x20,
|
|
}
|
|
assert SWITCH_SCHEMA(base)[key] is False
|
|
assert SWITCH_SCHEMA({**base, CONF_NAME: "Switch 2", key: True})[key] is True
|
|
with pytest.raises(cv.Invalid):
|
|
CONFIG_SCHEMA({modbus.CONF_MODBUS_ID: "bus", CONF_ADDRESS: 1, key: True})
|
|
|
|
|
|
def test_allow_broadcast_read_requires_address_zero() -> None:
|
|
# The option only means something at address 0; elsewhere it would be silently inert.
|
|
with pytest.raises(cv.Invalid, match="only applies to the broadcast address"):
|
|
_controller(5, **{modbus.CONF_ALLOW_BROADCAST_READ: True})
|
|
|
|
|
|
def test_add_command_options_skips_defaults() -> None:
|
|
# The setter is only emitted when an option differs from its C++ default.
|
|
import esphome.codegen as cg
|
|
from esphome.const import CONF_CONTINUOUS
|
|
|
|
var = cg.MockObj("ctl")
|
|
emitted: list = []
|
|
original = cg.add
|
|
cg.add = emitted.append
|
|
try:
|
|
modbus.add_command_options(
|
|
var, "set_read_options", {CONF_CONTINUOUS: False}, direction="read"
|
|
)
|
|
assert emitted == []
|
|
modbus.add_command_options(
|
|
var, "set_read_options", {CONF_CONTINUOUS: True}, direction="read"
|
|
)
|
|
assert len(emitted) == 1
|
|
assert "set_read_options" in str(emitted[0])
|
|
finally:
|
|
cg.add = original
|