Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow discovery configuration of modbus platforms #46591

Merged
merged 28 commits into from Mar 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
925119c
Change modbus configuration to new style.
janiversen Feb 13, 2021
37310bd
Update discovery_info configuration for binary_sensor.
janiversen Feb 15, 2021
29e6160
Update discovery_info configuration for sensor.
janiversen Feb 14, 2021
bbe9b97
Update discovery_info configuration for switch.
janiversen Feb 15, 2021
c0b554e
Review comments.
janiversen Feb 19, 2021
6fad3fa
update due to change in core
janiversen Mar 19, 2021
98adf5f
flake8 problem.
janiversen Mar 19, 2021
42d11db
Correct log message.
janiversen Mar 20, 2021
466ef8e
add should_poll property.
janiversen Mar 20, 2021
daaff98
Fix polling for Modbus binary sensor
vzahradnik Mar 20, 2021
6cd6b24
Fix polling for Modbus sensor
vzahradnik Mar 20, 2021
ebf1c91
Fix polling for Modbus switch
vzahradnik Mar 20, 2021
15ca903
Fix switch.
janiversen Mar 20, 2021
d9c67d6
Fix pytest errors.
janiversen Mar 20, 2021
c5ca838
Update homeassistant/components/modbus/binary_sensor.py
janiversen Mar 27, 2021
33e34d4
Update homeassistant/components/modbus/binary_sensor.py
janiversen Mar 27, 2021
d5de0d1
Update homeassistant/components/modbus/modbus.py
janiversen Mar 27, 2021
3fa3848
Update homeassistant/components/modbus/sensor.py
janiversen Mar 27, 2021
a753194
Update homeassistant/components/modbus/sensor.py
janiversen Mar 27, 2021
ead49cf
Update homeassistant/components/modbus/sensor.py
janiversen Mar 27, 2021
f4835d2
Update homeassistant/components/modbus/switch.py
janiversen Mar 27, 2021
ba84387
Update homeassistant/components/modbus/switch.py
janiversen Mar 27, 2021
f73dc6a
Update homeassistant/components/modbus/switch.py
janiversen Mar 27, 2021
416a3d1
ToogleEntity -> SwitchEntity and add abastract
janiversen Mar 27, 2021
909bf51
Update homeassistant/components/modbus/switch.py
janiversen Mar 27, 2021
a3f8bab
Update tests/components/modbus/test_init.py
janiversen Mar 27, 2021
58e4f7f
removed if/else in test.
janiversen Mar 27, 2021
1f7ace8
Remove other if.
janiversen Mar 27, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
174 changes: 139 additions & 35 deletions homeassistant/components/modbus/__init__.py
@@ -1,11 +1,25 @@
"""Support for Modbus."""
from typing import Any, Union

import voluptuous as vol

from homeassistant.components.binary_sensor import (
DEVICE_CLASSES_SCHEMA as BINARY_SENSOR_DEVICE_CLASSES_SCHEMA,
)
from homeassistant.components.cover import (
DEVICE_CLASSES_SCHEMA as COVER_DEVICE_CLASSES_SCHEMA,
)
from homeassistant.components.sensor import (
DEVICE_CLASSES_SCHEMA as SENSOR_DEVICE_CLASSES_SCHEMA,
)
from homeassistant.components.switch import (
DEVICE_CLASSES_SCHEMA as SWITCH_DEVICE_CLASSES_SCHEMA,
)
from homeassistant.const import (
ATTR_STATE,
CONF_ADDRESS,
CONF_COMMAND_OFF,
CONF_COMMAND_ON,
CONF_COVERS,
CONF_DELAY,
CONF_DEVICE_CLASS,
Expand All @@ -19,6 +33,7 @@
CONF_STRUCTURE,
CONF_TIMEOUT,
CONF_TYPE,
CONF_UNIT_OF_MEASUREMENT,
)
import homeassistant.helpers.config_validation as cv

Expand All @@ -28,11 +43,14 @@
ATTR_UNIT,
ATTR_VALUE,
CALL_TYPE_COIL,
CALL_TYPE_DISCRETE,
CALL_TYPE_REGISTER_HOLDING,
CALL_TYPE_REGISTER_INPUT,
CONF_BAUDRATE,
CONF_BINARY_SENSORS,
CONF_BYTESIZE,
CONF_CLIMATES,
CONF_COUNT,
CONF_CURRENT_TEMP,
CONF_CURRENT_TEMP_REGISTER_TYPE,
CONF_DATA_COUNT,
Expand All @@ -43,24 +61,30 @@
CONF_PARITY,
CONF_PRECISION,
CONF_REGISTER,
CONF_REVERSE_ORDER,
CONF_SCALE,
CONF_SENSORS,
CONF_STATE_CLOSED,
CONF_STATE_CLOSING,
CONF_STATE_OFF,
CONF_STATE_ON,
CONF_STATE_OPEN,
CONF_STATE_OPENING,
CONF_STATUS_REGISTER,
CONF_STATUS_REGISTER_TYPE,
CONF_STEP,
CONF_STOPBITS,
CONF_SWITCHES,
CONF_TARGET_TEMP,
CONF_UNIT,
CONF_VERIFY_REGISTER,
DATA_TYPE_CUSTOM,
DATA_TYPE_FLOAT,
DATA_TYPE_INT,
DATA_TYPE_STRING,
DATA_TYPE_UINT,
DEFAULT_HUB,
DEFAULT_SCAN_INTERVAL,
DEFAULT_SLAVE,
DEFAULT_STRUCTURE_PREFIX,
DEFAULT_TEMP_UNIT,
MODBUS_DOMAIN as DOMAIN,
Expand All @@ -69,11 +93,40 @@

BASE_SCHEMA = vol.Schema({vol.Optional(CONF_NAME, default=DEFAULT_HUB): cv.string})

CLIMATE_SCHEMA = vol.Schema(

def number(value: Any) -> Union[int, float]:
"""Coerce a value to number without losing precision."""
if isinstance(value, int):
return value
if isinstance(value, float):
return value

try:
value = int(value)
return value
except (TypeError, ValueError):
pass
try:
value = float(value)
return value
except (TypeError, ValueError) as err:
raise vol.Invalid(f"invalid number {value}") from err


BASE_COMPONENT_SCHEMA = vol.Schema(
{
vol.Required(CONF_CURRENT_TEMP): cv.positive_int,
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_SLAVE): cv.positive_int,
vol.Optional(CONF_SLAVE): cv.positive_int,
janiversen marked this conversation as resolved.
Show resolved Hide resolved
vol.Optional(
CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL
): cv.positive_int,
}
)


CLIMATE_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
{
vol.Required(CONF_CURRENT_TEMP): cv.positive_int,
vol.Required(CONF_TARGET_TEMP): cv.positive_int,
vol.Optional(CONF_DATA_COUNT, default=2): cv.positive_int,
vol.Optional(
Expand All @@ -84,9 +137,6 @@
),
vol.Optional(CONF_PRECISION, default=1): cv.positive_int,
vol.Optional(CONF_SCALE, default=1): vol.Coerce(float),
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): vol.All(
cv.time_period, lambda value: value.total_seconds()
),
vol.Optional(CONF_OFFSET, default=0): vol.Coerce(float),
vol.Optional(CONF_MAX_TEMP, default=35): cv.positive_int,
vol.Optional(CONF_MIN_TEMP, default=5): cv.positive_int,
Expand All @@ -98,14 +148,9 @@

COVERS_SCHEMA = vol.All(
cv.has_at_least_one_key(CALL_TYPE_COIL, CONF_REGISTER),
vol.Schema(
BASE_COMPONENT_SCHEMA.extend(
{
vol.Required(CONF_NAME): cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): vol.All(
cv.time_period, lambda value: value.total_seconds()
),
vol.Optional(CONF_DEVICE_CLASS): COVER_DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_SLAVE, default=DEFAULT_SLAVE): cv.positive_int,
vol.Optional(CONF_STATE_CLOSED, default=0): cv.positive_int,
vol.Optional(CONF_STATE_CLOSING, default=3): cv.positive_int,
vol.Optional(CONF_STATE_OPEN, default=1): cv.positive_int,
Expand All @@ -121,33 +166,104 @@
),
)

SERIAL_SCHEMA = BASE_SCHEMA.extend(
SWITCH_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
{
vol.Required(CONF_ADDRESS): cv.positive_int,
vol.Optional(CONF_DEVICE_CLASS): SWITCH_DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_INPUT_TYPE, default=CALL_TYPE_REGISTER_HOLDING): vol.In(
[CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT, CALL_TYPE_COIL]
),
vol.Optional(CONF_COMMAND_OFF, default=0x00): cv.positive_int,
vol.Optional(CONF_COMMAND_ON, default=0x01): cv.positive_int,
vol.Optional(CONF_STATE_OFF): cv.positive_int,
vol.Optional(CONF_STATE_ON): cv.positive_int,
vol.Optional(CONF_VERIFY_REGISTER): cv.positive_int,
}
)

SENSOR_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
{
vol.Required(CONF_ADDRESS): cv.positive_int,
vol.Optional(CONF_COUNT, default=1): cv.positive_int,
vol.Optional(CONF_DATA_TYPE, default=DATA_TYPE_INT): vol.In(
[
DATA_TYPE_INT,
DATA_TYPE_UINT,
DATA_TYPE_FLOAT,
DATA_TYPE_STRING,
DATA_TYPE_CUSTOM,
]
),
vol.Optional(CONF_DEVICE_CLASS): SENSOR_DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_OFFSET, default=0): number,
vol.Optional(CONF_PRECISION, default=0): cv.positive_int,
vol.Optional(CONF_INPUT_TYPE, default=CALL_TYPE_REGISTER_HOLDING): vol.In(
[CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT]
),
vol.Optional(CONF_REVERSE_ORDER, default=False): cv.boolean,
vol.Optional(CONF_SCALE, default=1): number,
vol.Optional(CONF_STRUCTURE): cv.string,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
}
)

BINARY_SENSOR_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
{
vol.Required(CONF_ADDRESS): cv.positive_int,
vol.Optional(CONF_DEVICE_CLASS): BINARY_SENSOR_DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_INPUT_TYPE, default=CALL_TYPE_COIL): vol.In(
[CALL_TYPE_COIL, CALL_TYPE_DISCRETE]
),
}
)

MODBUS_SCHEMA = vol.Schema(
{
vol.Optional(CONF_NAME, default=DEFAULT_HUB): cv.string,
vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout,
vol.Optional(CONF_DELAY, default=0): cv.positive_int,
vol.Optional(CONF_BINARY_SENSORS): vol.All(
cv.ensure_list, [BINARY_SENSOR_SCHEMA]
),
vol.Optional(CONF_CLIMATES): vol.All(cv.ensure_list, [CLIMATE_SCHEMA]),
vol.Optional(CONF_COVERS): vol.All(cv.ensure_list, [COVERS_SCHEMA]),
vol.Optional(CONF_SENSORS): vol.All(cv.ensure_list, [SENSOR_SCHEMA]),
vol.Optional(CONF_SWITCHES): vol.All(cv.ensure_list, [SWITCH_SCHEMA]),
}
)

SERIAL_SCHEMA = MODBUS_SCHEMA.extend(
{
vol.Required(CONF_TYPE): "serial",
vol.Required(CONF_BAUDRATE): cv.positive_int,
vol.Required(CONF_BYTESIZE): vol.Any(5, 6, 7, 8),
vol.Required(CONF_METHOD): vol.Any("rtu", "ascii"),
vol.Required(CONF_PORT): cv.string,
vol.Required(CONF_PARITY): vol.Any("E", "O", "N"),
vol.Required(CONF_STOPBITS): vol.Any(1, 2),
vol.Required(CONF_TYPE): "serial",
vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout,
vol.Optional(CONF_CLIMATES): vol.All(cv.ensure_list, [CLIMATE_SCHEMA]),
vol.Optional(CONF_COVERS): vol.All(cv.ensure_list, [COVERS_SCHEMA]),
}
)

ETHERNET_SCHEMA = BASE_SCHEMA.extend(
ETHERNET_SCHEMA = MODBUS_SCHEMA.extend(
{
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_PORT): cv.port,
vol.Required(CONF_TYPE): vol.Any("tcp", "udp", "rtuovertcp"),
vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout,
vol.Optional(CONF_DELAY, default=0): cv.positive_int,
vol.Optional(CONF_CLIMATES): vol.All(cv.ensure_list, [CLIMATE_SCHEMA]),
vol.Optional(CONF_COVERS): vol.All(cv.ensure_list, [COVERS_SCHEMA]),
}
)

CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.All(
cv.ensure_list,
[
vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA),
],
),
},
extra=vol.ALLOW_EXTRA,
)

SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema(
{
vol.Optional(ATTR_HUB, default=DEFAULT_HUB): cv.string,
Expand All @@ -168,18 +284,6 @@
}
)

CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.All(
cv.ensure_list,
[
vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA),
],
),
},
extra=vol.ALLOW_EXTRA,
)


def setup(hass, config):
"""Set up Modbus component."""
Expand Down