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:
jan iversen 2021-03-27 22:48:06 +01:00 committed by GitHub
parent 23d7330a2f
commit ffdfc521b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 605 additions and 139 deletions

View file

@ -146,4 +146,5 @@ async def base_config_test(
None,
method_discovery=method_discovery,
check_config_only=True,
config_modbus=config_modbus,
)

View 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")

View 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,
)

View file

@ -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

View file

@ -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

View file

@ -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,