Allow discovery configuration of modbus platforms (#46591)
* Change modbus configuration to new style. The old (frozen) configuration is still supported, but when detected a big warning is issued that it will soon be removed. This allows users to change their configuration at their pace. Clean configuration SCHEMAs and move common modbus parts to MODBUS_SCHEMA (renamed from BASE_SCHEMA). Add BASE_COMPONENT_SCHEMA to ensure common configuration of components. All component define e.g. NAME, move these to a common schema. change components (binary_sensor, sensor, switch) to new config Add test set for modbus itself (old config and discovery_info). Add test of devices discovery_info configuration * Update discovery_info configuration for binary_sensor. * Update discovery_info configuration for sensor. * Update discovery_info configuration for switch. * Review comments. * update due to change in core * flake8 problem. * Correct log message. * add should_poll property. * Fix polling for Modbus binary sensor * Fix polling for Modbus sensor * Fix polling for Modbus switch * Fix switch. * Fix pytest errors. * Update homeassistant/components/modbus/binary_sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/modbus/binary_sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/modbus/modbus.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/modbus/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/modbus/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/modbus/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/modbus/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/modbus/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/modbus/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * ToogleEntity -> SwitchEntity and add abastract * Update homeassistant/components/modbus/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update tests/components/modbus/test_init.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * removed if/else in test. * Remove other if. Co-authored-by: Vladimir Zahradnik <vladimir@zahradnik.io> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
23d7330a2f
commit
ffdfc521b9
14 changed files with 605 additions and 139 deletions
|
@ -146,4 +146,5 @@ async def base_config_test(
|
|||
None,
|
||||
method_discovery=method_discovery,
|
||||
check_config_only=True,
|
||||
config_modbus=config_modbus,
|
||||
)
|
||||
|
|
30
tests/components/modbus/test_init.py
Normal file
30
tests/components/modbus/test_init.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
"""The tests for the Modbus init."""
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.modbus import number
|
||||
|
||||
|
||||
async def test_number_validator():
|
||||
"""Test number validator."""
|
||||
|
||||
# positive tests
|
||||
value = number(15)
|
||||
assert isinstance(value, int)
|
||||
|
||||
value = number(15.1)
|
||||
assert isinstance(value, float)
|
||||
|
||||
value = number("15")
|
||||
assert isinstance(value, int)
|
||||
|
||||
value = number("15.1")
|
||||
assert isinstance(value, float)
|
||||
|
||||
# exception test
|
||||
try:
|
||||
value = number("x15.1")
|
||||
except (vol.Invalid):
|
||||
return
|
||||
|
||||
pytest.fail("Number not throwing exception")
|
70
tests/components/modbus/test_modbus.py
Normal file
70
tests/components/modbus/test_modbus.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
"""The tests for the Modbus sensor component."""
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.modbus.const import (
|
||||
CONF_BAUDRATE,
|
||||
CONF_BYTESIZE,
|
||||
CONF_PARITY,
|
||||
CONF_STOPBITS,
|
||||
MODBUS_DOMAIN as DOMAIN,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONF_DELAY,
|
||||
CONF_HOST,
|
||||
CONF_METHOD,
|
||||
CONF_NAME,
|
||||
CONF_PORT,
|
||||
CONF_TIMEOUT,
|
||||
CONF_TYPE,
|
||||
)
|
||||
|
||||
from .conftest import base_config_test
|
||||
|
||||
|
||||
@pytest.mark.parametrize("do_discovery", [False, True])
|
||||
@pytest.mark.parametrize(
|
||||
"do_options",
|
||||
[
|
||||
{},
|
||||
{
|
||||
CONF_NAME: "modbusTest",
|
||||
CONF_TIMEOUT: 30,
|
||||
CONF_DELAY: 10,
|
||||
},
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"do_config",
|
||||
[
|
||||
{
|
||||
CONF_TYPE: "tcp",
|
||||
CONF_HOST: "modbusTestHost",
|
||||
CONF_PORT: 5501,
|
||||
},
|
||||
{
|
||||
CONF_TYPE: "serial",
|
||||
CONF_BAUDRATE: 9600,
|
||||
CONF_BYTESIZE: 8,
|
||||
CONF_METHOD: "rtu",
|
||||
CONF_PORT: "usb01",
|
||||
CONF_PARITY: "E",
|
||||
CONF_STOPBITS: 1,
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_config_modbus(hass, do_discovery, do_options, do_config):
|
||||
"""Run test for modbus."""
|
||||
config = {
|
||||
DOMAIN: do_config,
|
||||
}
|
||||
config.update(do_options)
|
||||
await base_config_test(
|
||||
hass,
|
||||
None,
|
||||
"",
|
||||
DOMAIN,
|
||||
None,
|
||||
None,
|
||||
method_discovery=do_discovery,
|
||||
config_modbus=config,
|
||||
)
|
|
@ -5,16 +5,25 @@ from homeassistant.components.binary_sensor import DOMAIN as SENSOR_DOMAIN
|
|||
from homeassistant.components.modbus.const import (
|
||||
CALL_TYPE_COIL,
|
||||
CALL_TYPE_DISCRETE,
|
||||
CONF_BINARY_SENSORS,
|
||||
CONF_INPUT_TYPE,
|
||||
CONF_INPUTS,
|
||||
)
|
||||
from homeassistant.const import CONF_ADDRESS, CONF_NAME, CONF_SLAVE, STATE_OFF, STATE_ON
|
||||
from homeassistant.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_NAME,
|
||||
CONF_SLAVE,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
|
||||
from .conftest import base_config_test, base_test
|
||||
|
||||
|
||||
@pytest.mark.parametrize("do_discovery", [False, True])
|
||||
@pytest.mark.parametrize("do_options", [False, True])
|
||||
async def test_config_binary_sensor(hass, do_options):
|
||||
async def test_config_binary_sensor(hass, do_discovery, do_options):
|
||||
"""Run test for binary sensor."""
|
||||
sensor_name = "test_sensor"
|
||||
config_sensor = {
|
||||
|
@ -26,6 +35,7 @@ async def test_config_binary_sensor(hass, do_options):
|
|||
{
|
||||
CONF_SLAVE: 10,
|
||||
CONF_INPUT_TYPE: CALL_TYPE_DISCRETE,
|
||||
CONF_DEVICE_CLASS: "door",
|
||||
}
|
||||
)
|
||||
await base_config_test(
|
||||
|
@ -33,9 +43,9 @@ async def test_config_binary_sensor(hass, do_options):
|
|||
config_sensor,
|
||||
sensor_name,
|
||||
SENSOR_DOMAIN,
|
||||
None,
|
||||
CONF_BINARY_SENSORS,
|
||||
CONF_INPUTS,
|
||||
method_discovery=False,
|
||||
method_discovery=do_discovery,
|
||||
)
|
||||
|
||||
|
||||
|
@ -73,11 +83,11 @@ async def test_all_binary_sensor(hass, do_type, regs, expected):
|
|||
{CONF_NAME: sensor_name, CONF_ADDRESS: 1234, CONF_INPUT_TYPE: do_type},
|
||||
sensor_name,
|
||||
SENSOR_DOMAIN,
|
||||
None,
|
||||
CONF_BINARY_SENSORS,
|
||||
CONF_INPUTS,
|
||||
regs,
|
||||
expected,
|
||||
method_discovery=False,
|
||||
method_discovery=True,
|
||||
scan_interval=5,
|
||||
)
|
||||
assert state == expected
|
||||
|
|
|
@ -6,30 +6,42 @@ from homeassistant.components.modbus.const import (
|
|||
CALL_TYPE_REGISTER_INPUT,
|
||||
CONF_COUNT,
|
||||
CONF_DATA_TYPE,
|
||||
CONF_INPUT_TYPE,
|
||||
CONF_PRECISION,
|
||||
CONF_REGISTER,
|
||||
CONF_REGISTER_TYPE,
|
||||
CONF_REGISTERS,
|
||||
CONF_REVERSE_ORDER,
|
||||
CONF_SCALE,
|
||||
CONF_SENSORS,
|
||||
DATA_TYPE_FLOAT,
|
||||
DATA_TYPE_INT,
|
||||
DATA_TYPE_STRING,
|
||||
DATA_TYPE_UINT,
|
||||
)
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.const import CONF_NAME, CONF_OFFSET, CONF_SLAVE
|
||||
from homeassistant.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_NAME,
|
||||
CONF_OFFSET,
|
||||
CONF_SLAVE,
|
||||
)
|
||||
|
||||
from .conftest import base_config_test, base_test
|
||||
|
||||
|
||||
@pytest.mark.parametrize("do_discovery", [False, True])
|
||||
@pytest.mark.parametrize("do_options", [False, True])
|
||||
async def test_config_sensor(hass, do_options):
|
||||
@pytest.mark.parametrize(
|
||||
"do_type", [CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT]
|
||||
)
|
||||
async def test_config_sensor(hass, do_discovery, do_options, do_type):
|
||||
"""Run test for sensor."""
|
||||
sensor_name = "test_sensor"
|
||||
config_sensor = {
|
||||
CONF_NAME: sensor_name,
|
||||
CONF_REGISTER: 51,
|
||||
CONF_ADDRESS: 51,
|
||||
}
|
||||
if do_options:
|
||||
config_sensor.update(
|
||||
|
@ -41,17 +53,25 @@ async def test_config_sensor(hass, do_options):
|
|||
CONF_SCALE: 1,
|
||||
CONF_REVERSE_ORDER: False,
|
||||
CONF_OFFSET: 0,
|
||||
CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||
CONF_INPUT_TYPE: do_type,
|
||||
CONF_DEVICE_CLASS: "battery",
|
||||
}
|
||||
)
|
||||
if not do_discovery:
|
||||
# bridge difference in configuration
|
||||
config_sensor[CONF_REGISTER] = config_sensor[CONF_ADDRESS]
|
||||
del config_sensor[CONF_ADDRESS]
|
||||
if do_options:
|
||||
config_sensor[CONF_REGISTER_TYPE] = config_sensor[CONF_INPUT_TYPE]
|
||||
del config_sensor[CONF_INPUT_TYPE]
|
||||
await base_config_test(
|
||||
hass,
|
||||
config_sensor,
|
||||
sensor_name,
|
||||
SENSOR_DOMAIN,
|
||||
None,
|
||||
CONF_SENSORS,
|
||||
CONF_REGISTERS,
|
||||
method_discovery=False,
|
||||
method_discovery=do_discovery,
|
||||
)
|
||||
|
||||
|
||||
|
@ -218,7 +238,7 @@ async def test_config_sensor(hass, do_options):
|
|||
(
|
||||
{
|
||||
CONF_COUNT: 2,
|
||||
CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_INPUT,
|
||||
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_INPUT,
|
||||
CONF_DATA_TYPE: DATA_TYPE_UINT,
|
||||
CONF_SCALE: 1,
|
||||
CONF_OFFSET: 0,
|
||||
|
@ -230,7 +250,7 @@ async def test_config_sensor(hass, do_options):
|
|||
(
|
||||
{
|
||||
CONF_COUNT: 2,
|
||||
CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||
CONF_DATA_TYPE: DATA_TYPE_UINT,
|
||||
CONF_SCALE: 1,
|
||||
CONF_OFFSET: 0,
|
||||
|
@ -242,7 +262,7 @@ async def test_config_sensor(hass, do_options):
|
|||
(
|
||||
{
|
||||
CONF_COUNT: 2,
|
||||
CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||
CONF_DATA_TYPE: DATA_TYPE_FLOAT,
|
||||
CONF_SCALE: 1,
|
||||
CONF_OFFSET: 0,
|
||||
|
@ -254,7 +274,7 @@ async def test_config_sensor(hass, do_options):
|
|||
(
|
||||
{
|
||||
CONF_COUNT: 8,
|
||||
CONF_REGISTER_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||
CONF_DATA_TYPE: DATA_TYPE_STRING,
|
||||
CONF_SCALE: 1,
|
||||
CONF_OFFSET: 0,
|
||||
|
@ -270,14 +290,14 @@ async def test_all_sensor(hass, cfg, regs, expected):
|
|||
sensor_name = "modbus_test_sensor"
|
||||
state = await base_test(
|
||||
hass,
|
||||
{CONF_NAME: sensor_name, CONF_REGISTER: 1234, **cfg},
|
||||
{CONF_NAME: sensor_name, CONF_ADDRESS: 1234, **cfg},
|
||||
sensor_name,
|
||||
SENSOR_DOMAIN,
|
||||
None,
|
||||
CONF_SENSORS,
|
||||
CONF_REGISTERS,
|
||||
regs,
|
||||
expected,
|
||||
method_discovery=False,
|
||||
method_discovery=True,
|
||||
scan_interval=5,
|
||||
)
|
||||
assert state == expected
|
||||
|
|
|
@ -3,14 +3,25 @@ import pytest
|
|||
|
||||
from homeassistant.components.modbus.const import (
|
||||
CALL_TYPE_COIL,
|
||||
CALL_TYPE_REGISTER_HOLDING,
|
||||
CALL_TYPE_REGISTER_INPUT,
|
||||
CONF_COILS,
|
||||
CONF_INPUT_TYPE,
|
||||
CONF_REGISTER,
|
||||
CONF_REGISTER_TYPE,
|
||||
CONF_REGISTERS,
|
||||
CONF_STATE_OFF,
|
||||
CONF_STATE_ON,
|
||||
CONF_SWITCHES,
|
||||
CONF_VERIFY_REGISTER,
|
||||
CONF_VERIFY_STATE,
|
||||
)
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_COMMAND_OFF,
|
||||
CONF_COMMAND_ON,
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_NAME,
|
||||
CONF_SLAVE,
|
||||
STATE_OFF,
|
||||
|
@ -20,39 +31,66 @@ from homeassistant.const import (
|
|||
from .conftest import base_config_test, base_test
|
||||
|
||||
|
||||
@pytest.mark.parametrize("do_discovery", [False, True])
|
||||
@pytest.mark.parametrize("do_options", [False, True])
|
||||
@pytest.mark.parametrize("read_type", [CALL_TYPE_COIL, CONF_REGISTER])
|
||||
async def test_config_switch(hass, do_options, read_type):
|
||||
@pytest.mark.parametrize(
|
||||
"read_type", [CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT, CALL_TYPE_COIL]
|
||||
)
|
||||
async def test_config_switch(hass, do_discovery, do_options, read_type):
|
||||
"""Run test for switch."""
|
||||
device_name = "test_switch"
|
||||
|
||||
if read_type == CONF_REGISTER:
|
||||
device_config = {
|
||||
CONF_NAME: device_name,
|
||||
CONF_REGISTER: 1234,
|
||||
CONF_SLAVE: 1,
|
||||
CONF_COMMAND_OFF: 0x00,
|
||||
CONF_COMMAND_ON: 0x01,
|
||||
}
|
||||
array_type = CONF_REGISTERS
|
||||
device_config = {
|
||||
CONF_NAME: device_name,
|
||||
}
|
||||
if not do_discovery:
|
||||
if read_type == CALL_TYPE_COIL:
|
||||
array_type = CONF_COILS
|
||||
device_config[CALL_TYPE_COIL] = 1234
|
||||
device_config[CONF_SLAVE] = 1
|
||||
else:
|
||||
array_type = CONF_REGISTERS
|
||||
device_config[CONF_REGISTER] = 1234
|
||||
device_config[CONF_COMMAND_OFF] = 0x00
|
||||
device_config[CONF_COMMAND_ON] = 0x01
|
||||
else:
|
||||
device_config = {
|
||||
CONF_NAME: device_name,
|
||||
read_type: 1234,
|
||||
CONF_SLAVE: 10,
|
||||
}
|
||||
array_type = CONF_COILS
|
||||
array_type = None
|
||||
device_config[CONF_ADDRESS] = 1234
|
||||
if read_type == CALL_TYPE_COIL:
|
||||
device_config[CONF_INPUT_TYPE] = CALL_TYPE_COIL
|
||||
|
||||
if do_options:
|
||||
device_config.update({})
|
||||
device_config[CONF_SLAVE] = 1
|
||||
if read_type != CALL_TYPE_COIL:
|
||||
device_config.update(
|
||||
{
|
||||
CONF_STATE_OFF: 0,
|
||||
CONF_STATE_ON: 1,
|
||||
CONF_VERIFY_REGISTER: 1235,
|
||||
CONF_COMMAND_OFF: 0x00,
|
||||
CONF_COMMAND_ON: 0x01,
|
||||
}
|
||||
)
|
||||
if do_discovery:
|
||||
device_config.update(
|
||||
{
|
||||
CONF_DEVICE_CLASS: "switch",
|
||||
CONF_INPUT_TYPE: read_type,
|
||||
}
|
||||
)
|
||||
else:
|
||||
if read_type != CALL_TYPE_COIL:
|
||||
device_config[CONF_VERIFY_STATE] = True
|
||||
device_config[CONF_REGISTER_TYPE] = read_type
|
||||
|
||||
await base_config_test(
|
||||
hass,
|
||||
device_config,
|
||||
device_name,
|
||||
SWITCH_DOMAIN,
|
||||
None,
|
||||
CONF_SWITCHES,
|
||||
array_type,
|
||||
method_discovery=False,
|
||||
method_discovery=do_discovery,
|
||||
)
|
||||
|
||||
|
||||
|
@ -88,16 +126,16 @@ async def test_coil_switch(hass, regs, expected):
|
|||
hass,
|
||||
{
|
||||
CONF_NAME: switch_name,
|
||||
CALL_TYPE_COIL: 1234,
|
||||
CONF_SLAVE: 1,
|
||||
CONF_ADDRESS: 1234,
|
||||
CONF_INPUT_TYPE: CALL_TYPE_COIL,
|
||||
},
|
||||
switch_name,
|
||||
SWITCH_DOMAIN,
|
||||
None,
|
||||
CONF_SWITCHES,
|
||||
CONF_COILS,
|
||||
regs,
|
||||
expected,
|
||||
method_discovery=False,
|
||||
method_discovery=True,
|
||||
scan_interval=5,
|
||||
)
|
||||
assert state == expected
|
||||
|
@ -142,7 +180,7 @@ async def test_register_switch(hass, regs, expected):
|
|||
},
|
||||
switch_name,
|
||||
SWITCH_DOMAIN,
|
||||
None,
|
||||
CONF_SWITCHES,
|
||||
CONF_REGISTERS,
|
||||
regs,
|
||||
expected,
|
||||
|
@ -183,7 +221,7 @@ async def test_register_state_switch(hass, regs, expected):
|
|||
},
|
||||
switch_name,
|
||||
SWITCH_DOMAIN,
|
||||
None,
|
||||
CONF_SWITCHES,
|
||||
CONF_REGISTERS,
|
||||
regs,
|
||||
expected,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue