From e2d8165157b39986d0b095e0694ff912345582cd Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Sat, 27 Oct 2018 19:28:32 +0800 Subject: [PATCH 01/18] modbus: support multiple modbus hub --- homeassistant/components/modbus/__init__.py | 265 ++++++++++-------- .../components/modbus/binary_sensor.py | 31 +- homeassistant/components/modbus/climate.py | 79 ++++-- homeassistant/components/modbus/sensor.py | 193 ++++++++----- homeassistant/components/modbus/switch.py | 136 ++++----- 5 files changed, 411 insertions(+), 293 deletions(-) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 40ede019c1015e..8027eb887bd79a 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -6,151 +6,199 @@ """ import logging import threading +from typing import TYPE_CHECKING, Any, Dict, List import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.const import ( - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, - CONF_HOST, CONF_METHOD, CONF_PORT, CONF_TYPE, CONF_TIMEOUT, ATTR_STATE) + ATTR_STATE, CONF_HOST, CONF_METHOD, CONF_PORT, CONF_TIMEOUT, CONF_TYPE, + EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) + +if TYPE_CHECKING: + from pymodbus.client.sync import BaseModbusClient DOMAIN = 'modbus' REQUIREMENTS = ['pymodbus==1.5.2'] # Type of network -CONF_BAUDRATE = 'baudrate' -CONF_BYTESIZE = 'bytesize' -CONF_STOPBITS = 'stopbits' -CONF_PARITY = 'parity' +CONF_BAUDRATE = "baudrate" +CONF_BYTESIZE = "bytesize" +CONF_STOPBITS = "stopbits" +CONF_PARITY = "parity" +CONF_HUB_NAME = "hub_name" + +BASE_SCHEMA = vol.Schema({ + vol.Optional(CONF_HUB_NAME, default="default"): cv.string +}) -SERIAL_SCHEMA = { +SERIAL_SCHEMA = BASE_SCHEMA.extend({ 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_METHOD): vol.Any("rtu", "ascii"), vol.Required(CONF_PORT): cv.string, - vol.Required(CONF_PARITY): vol.Any('E', 'O', 'N'), + vol.Required(CONF_PARITY): vol.Any("E", "O", "N"), vol.Required(CONF_STOPBITS): vol.Any(1, 2), - vol.Required(CONF_TYPE): 'serial', + vol.Required(CONF_TYPE): "serial", vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout, -} +}) -ETHERNET_SCHEMA = { +ETHERNET_SCHEMA = BASE_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_PORT): cv.port, - vol.Required(CONF_TYPE): vol.Any('tcp', 'udp', 'rtuovertcp'), + vol.Required(CONF_TYPE): vol.Any("tcp", "udp", "rtuovertcp"), vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout, -} +}) -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA) -}, extra=vol.ALLOW_EXTRA) +def check_base_on_type(value: Any) -> Any: + """Check modbus component schema base on "type".""" + if value[CONF_TYPE] == "serial": + return SERIAL_SCHEMA(value) + if value[CONF_TYPE] in ("tcp", "udp", "rtuovertcp"): + return ETHERNET_SCHEMA(value) + raise vol.Invalid("%s %s is not supported" % (CONF_TYPE, value[CONF_TYPE])) + +CONFIG_SCHEMA = vol.Schema( + { + DOMAIN: + vol.All(cv.ensure_list, + vol.Schema([vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA)])) + }, + extra=vol.ALLOW_EXTRA, +) _LOGGER = logging.getLogger(__name__) -SERVICE_WRITE_REGISTER = 'write_register' -SERVICE_WRITE_COIL = 'write_coil' +SERVICE_WRITE_REGISTER = "write_register" +SERVICE_WRITE_COIL = "write_coil" -ATTR_ADDRESS = 'address' -ATTR_UNIT = 'unit' -ATTR_VALUE = 'value' +ATTR_ADDRESS = "address" +ATTR_UNIT = "unit" +ATTR_VALUE = "value" SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema({ + vol.Optional(CONF_HUB_NAME, default="default"): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, - vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int]) + vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int]), }) SERVICE_WRITE_COIL_SCHEMA = vol.Schema({ + vol.Optional(CONF_HUB_NAME, default="default"): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, - vol.Required(ATTR_STATE): cv.boolean + vol.Required(ATTR_STATE): cv.boolean, }) -HUB = None +HUB = {} # type: Dict[str, BaseModbusClient] -def setup(hass, config): - """Set up Modbus component.""" - # Modbus connection type - client_type = config[DOMAIN][CONF_TYPE] +def setup_client(client_config: dict) -> "BaseModbusClient": + """Setup pymodbus client.""" + from pymodbus.client.sync import ( + ModbusTcpClient, + ModbusUdpClient, + ModbusSerialClient, + ) + from pymodbus.transaction import ModbusRtuFramer + + client_type = client_config[CONF_TYPE] # Connect to Modbus network # pylint: disable=import-error - if client_type == 'serial': - from pymodbus.client.sync import ModbusSerialClient as ModbusClient - client = ModbusClient(method=config[DOMAIN][CONF_METHOD], - port=config[DOMAIN][CONF_PORT], - baudrate=config[DOMAIN][CONF_BAUDRATE], - stopbits=config[DOMAIN][CONF_STOPBITS], - bytesize=config[DOMAIN][CONF_BYTESIZE], - parity=config[DOMAIN][CONF_PARITY], - timeout=config[DOMAIN][CONF_TIMEOUT]) - elif client_type == 'rtuovertcp': - from pymodbus.client.sync import ModbusTcpClient as ModbusClient - from pymodbus.transaction import ModbusRtuFramer as ModbusFramer - client = ModbusClient(host=config[DOMAIN][CONF_HOST], - port=config[DOMAIN][CONF_PORT], - framer=ModbusFramer, - timeout=config[DOMAIN][CONF_TIMEOUT]) - elif client_type == 'tcp': - from pymodbus.client.sync import ModbusTcpClient as ModbusClient - client = ModbusClient(host=config[DOMAIN][CONF_HOST], - port=config[DOMAIN][CONF_PORT], - timeout=config[DOMAIN][CONF_TIMEOUT]) - elif client_type == 'udp': - from pymodbus.client.sync import ModbusUdpClient as ModbusClient - client = ModbusClient(host=config[DOMAIN][CONF_HOST], - port=config[DOMAIN][CONF_PORT], - timeout=config[DOMAIN][CONF_TIMEOUT]) - else: - return False - + if client_type == "serial": + + return ModbusSerialClient( + method=client_config[CONF_METHOD], + port=client_config[CONF_PORT], + baudrate=client_config[CONF_BAUDRATE], + stopbits=client_config[CONF_STOPBITS], + bytesize=client_config[CONF_BYTESIZE], + parity=client_config[CONF_PARITY], + timeout=client_config[CONF_TIMEOUT], + ) + if client_type == "rtuovertcp": + + return ModbusTcpClient( + host=client_config[CONF_HOST], + port=client_config[CONF_PORT], + framer=ModbusRtuFramer, + timeout=client_config[CONF_TIMEOUT], + ) + if client_type == "tcp": + return ModbusTcpClient( + host=client_config[CONF_HOST], + port=client_config[CONF_PORT], + timeout=client_config[CONF_TIMEOUT], + ) + if client_type == "udp": + return ModbusUdpClient( + host=client_config[CONF_HOST], + port=client_config[CONF_PORT], + timeout=client_config[CONF_TIMEOUT], + ) + + assert False + + +def setup(hass: Any, config: dict) -> bool: + """Set up Modbus component.""" + # Modbus connection type global HUB - HUB = ModbusHub(client) - def stop_modbus(event): + for client_config in config[DOMAIN]: + client = setup_client(client_config) + client_name = client_config[CONF_HUB_NAME] + HUB[client_name] = ModbusHub(client) + + def stop_modbus(event: Any) -> None: """Stop Modbus service.""" - HUB.close() + for client in HUB.values(): + client.close() - def start_modbus(event): + def start_modbus(event: Any) -> None: """Start Modbus service.""" - HUB.connect() + for client in HUB.values(): + client.connect() + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_modbus) # Register services for modbus hass.services.register( - DOMAIN, SERVICE_WRITE_REGISTER, write_register, - schema=SERVICE_WRITE_REGISTER_SCHEMA) + DOMAIN, + SERVICE_WRITE_REGISTER, + write_register, + schema=SERVICE_WRITE_REGISTER_SCHEMA, + ) hass.services.register( - DOMAIN, SERVICE_WRITE_COIL, write_coil, + DOMAIN, + SERVICE_WRITE_COIL, + write_coil, schema=SERVICE_WRITE_COIL_SCHEMA) - def write_register(service): + def write_register(service: Any) -> None: """Write modbus registers.""" unit = int(float(service.data.get(ATTR_UNIT))) address = int(float(service.data.get(ATTR_ADDRESS))) value = service.data.get(ATTR_VALUE) + client_name = service.data.get(CONF_HUB_NAME) if isinstance(value, list): - HUB.write_registers( - unit, - address, - [int(float(i)) for i in value]) + HUB[client_name].write_registers(unit, address, + [int(float(i)) for i in value]) else: - HUB.write_register( - unit, - address, - int(float(value))) + HUB[client_name].write_register(unit, address, int(float(value))) - def write_coil(service): + def write_coil(service: Any) -> None: """Write modbus coil.""" unit = service.data.get(ATTR_UNIT) address = service.data.get(ATTR_ADDRESS) state = service.data.get(ATTR_STATE) - HUB.write_coil(unit, address, state) + client_name = service.data.get(CONF_HUB_NAME) + HUB[client_name].write_coil(unit, address, state) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_modbus) @@ -160,71 +208,56 @@ def write_coil(service): class ModbusHub: """Thread safe wrapper class for pymodbus.""" - def __init__(self, modbus_client): + def __init__(self, modbus_client: "BaseModbusClient") -> None: """Initialize the modbus hub.""" self._client = modbus_client self._lock = threading.Lock() - def close(self): + def close(self) -> None: """Disconnect client.""" with self._lock: self._client.close() - def connect(self): + def connect(self) -> None: """Connect client.""" with self._lock: self._client.connect() - def read_coils(self, unit, address, count): + def read_coils(self, unit: int, address: int, count: int) -> Any: """Read coils.""" with self._lock: - kwargs = {'unit': unit} if unit else {} - return self._client.read_coils( - address, - count, - **kwargs) + kwargs = {"unit": unit} if unit else {} + return self._client.read_coils(address, count, **kwargs) - def read_input_registers(self, unit, address, count): + def read_input_registers(self, unit: int, address: int, count: int) -> Any: """Read input registers.""" with self._lock: - kwargs = {'unit': unit} if unit else {} - return self._client.read_input_registers( - address, - count, - **kwargs) + kwargs = {"unit": unit} if unit else {} + return self._client.read_input_registers(address, count, **kwargs) - def read_holding_registers(self, unit, address, count): + def read_holding_registers(self, unit: int, address: int, + count: int) -> Any: """Read holding registers.""" with self._lock: - kwargs = {'unit': unit} if unit else {} - return self._client.read_holding_registers( - address, - count, - **kwargs) + kwargs = {"unit": unit} if unit else {} + return self._client.read_holding_registers(address, count, + **kwargs) - def write_coil(self, unit, address, value): + def write_coil(self, unit: int, address: int, value: int) -> Any: """Write coil.""" with self._lock: - kwargs = {'unit': unit} if unit else {} - self._client.write_coil( - address, - value, - **kwargs) + kwargs = {"unit": unit} if unit else {} + self._client.write_coil(address, value, **kwargs) - def write_register(self, unit, address, value): + def write_register(self, unit: int, address: int, value: int) -> Any: """Write register.""" with self._lock: - kwargs = {'unit': unit} if unit else {} - self._client.write_register( - address, - value, - **kwargs) + kwargs = {"unit": unit} if unit else {} + self._client.write_register(address, value, **kwargs) - def write_registers(self, unit, address, values): + def write_registers(self, unit: int, address: int, + values: List[int]) -> Any: """Write registers.""" with self._lock: - kwargs = {'unit': unit} if unit else {} - self._client.write_registers( - address, - values, - **kwargs) + kwargs = {"unit": unit} if unit else {} + self._client.write_registers(address, values, **kwargs) diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index f9f2597593e641..b25d707f21e575 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -5,13 +5,15 @@ https://home-assistant.io/components/binary_sensor.modbus/ """ import logging + import voluptuous as vol from homeassistant.components import modbus -from homeassistant.const import CONF_NAME, CONF_SLAVE from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.helpers import config_validation as cv +from homeassistant.components.modbus import CONF_HUB_NAME from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import CONF_NAME, CONF_SLAVE +from homeassistant.helpers import config_validation as cv _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] @@ -21,6 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_COILS): [{ + vol.Required(CONF_HUB_NAME, default="default"): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_SLAVE): cv.positive_int @@ -32,18 +35,19 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus binary sensors.""" sensors = [] for coil in config.get(CONF_COILS): - sensors.append(ModbusCoilSensor( - coil.get(CONF_NAME), - coil.get(CONF_SLAVE), - coil.get(CONF_COIL))) + sensors.append( + ModbusCoilSensor( + coil.get(CONF_HUB_NAME), coil.get(CONF_NAME), + coil.get(CONF_SLAVE), coil.get(CONF_COIL))) add_entities(sensors) class ModbusCoilSensor(BinarySensorDevice): """Modbus coil sensor.""" - def __init__(self, name, slave, coil): + def __init__(self, hub_name, name, slave, coil): """Initialize the modbus coil sensor.""" + self._hub_name = hub_name self._name = name self._slave = int(slave) if slave else None self._coil = int(coil) @@ -59,13 +63,16 @@ def is_on(self): """Return the state of the sensor.""" return self._value + @property + def client(self) -> "BaseModbusClient": + """Find and return the client from modbus HUB.""" + return modbus.HUB[self._hub_name] + def update(self): """Update the state of the sensor.""" - result = modbus.HUB.read_coils(self._slave, self._coil, 1) + result = self.client.read_coils(self._slave, self._coil, 1) try: self._value = result.bits[0] except AttributeError: - _LOGGER.error( - 'No response from modbus slave %s coil %s', - self._slave, - self._coil) + _LOGGER.error('No response from modbus slave %s coil %s', + self._slave, self._coil) diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 1c5c03e4502a18..ce4915184bc94b 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -13,13 +13,12 @@ import voluptuous as vol -from homeassistant.const import ( - CONF_NAME, CONF_SLAVE, ATTR_TEMPERATURE) -from homeassistant.components.climate import ( - ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE) - -from homeassistant.components import modbus import homeassistant.helpers.config_validation as cv +from homeassistant.components import modbus +from homeassistant.components.climate import (ClimateDevice, PLATFORM_SCHEMA, + SUPPORT_TARGET_TEMPERATURE) +from homeassistant.components.modbus import CONF_HUB_NAME +from homeassistant.const import ATTR_TEMPERATURE, CONF_NAME, CONF_SLAVE DEPENDENCIES = ['modbus'] @@ -35,14 +34,22 @@ DATA_TYPE_FLOAT = 'float' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_NAME): cv.string, - vol.Required(CONF_SLAVE): cv.positive_int, - vol.Required(CONF_TARGET_TEMP): cv.positive_int, - vol.Required(CONF_CURRENT_TEMP): cv.positive_int, + vol.Required(CONF_HUB_NAME, default="default"): + cv.string, + vol.Required(CONF_NAME): + cv.string, + vol.Required(CONF_SLAVE): + cv.positive_int, + vol.Required(CONF_TARGET_TEMP): + cv.positive_int, + vol.Required(CONF_CURRENT_TEMP): + cv.positive_int, vol.Optional(CONF_DATA_TYPE, default=DATA_TYPE_FLOAT): vol.In([DATA_TYPE_INT, DATA_TYPE_UINT, DATA_TYPE_FLOAT]), - vol.Optional(CONF_COUNT, default=2): cv.positive_int, - vol.Optional(CONF_PRECISION, default=1): cv.positive_int + vol.Optional(CONF_COUNT, default=2): + cv.positive_int, + vol.Optional(CONF_PRECISION, default=1): + cv.positive_int }) _LOGGER = logging.getLogger(__name__) @@ -59,18 +66,21 @@ def setup_platform(hass, config, add_entities, discovery_info=None): data_type = config.get(CONF_DATA_TYPE) count = config.get(CONF_COUNT) precision = config.get(CONF_PRECISION) + hub_name = config.get(CONF_HUB_NAME) - add_entities([ModbusThermostat(name, modbus_slave, - target_temp_register, current_temp_register, - data_type, count, precision)], True) + add_entities([ + ModbusThermostat(hub_name, name, modbus_slave, target_temp_register, + current_temp_register, data_type, count, precision) + ], True) class ModbusThermostat(ClimateDevice): """Representation of a Modbus Thermostat.""" - def __init__(self, name, modbus_slave, target_temp_register, + def __init__(self, hub_name, name, modbus_slave, target_temp_register, current_temp_register, data_type, count, precision): """Initialize the unit.""" + self._hub_name = hub_name self._name = name self._slave = modbus_slave self._target_temperature_register = target_temp_register @@ -82,12 +92,26 @@ def __init__(self, name, modbus_slave, target_temp_register, self._precision = precision self._structure = '>f' - data_types = {DATA_TYPE_INT: {1: 'h', 2: 'i', 4: 'q'}, - DATA_TYPE_UINT: {1: 'H', 2: 'I', 4: 'Q'}, - DATA_TYPE_FLOAT: {1: 'e', 2: 'f', 4: 'd'}} - - self._structure = '>{}'.format(data_types[self._data_type] - [self._count]) + data_types = { + DATA_TYPE_INT: { + 1: 'h', + 2: 'i', + 4: 'q' + }, + DATA_TYPE_UINT: { + 1: 'H', + 2: 'I', + 4: 'Q' + }, + DATA_TYPE_FLOAT: { + 1: 'e', + 2: 'f', + 4: 'd' + } + } + + self._structure = '>{}'.format( + data_types[self._data_type][self._count]) @property def supported_features(self): @@ -116,6 +140,11 @@ def target_temperature(self): """Return the temperature we try to reach.""" return self._target_temperature + @property + def client(self) -> "BaseModbusClient": + """Find and return the client from modbus HUB.""" + return modbus.HUB[self._hub_name] + def set_temperature(self, **kwargs): """Set new target temperature.""" target_temperature = kwargs.get(ATTR_TEMPERATURE) @@ -133,8 +162,8 @@ def set_temperature(self, **kwargs): def read_register(self, register): """Read holding register using the modbus hub slave.""" try: - result = modbus.HUB.read_holding_registers(self._slave, register, - self._count) + result = self.client.read_holding_registers( + self._slave, register, self._count) except AttributeError as ex: _LOGGER.error(ex) byte_string = b''.join( @@ -145,4 +174,4 @@ def read_register(self, register): def write_register(self, register, value): """Write register using the modbus hub slave.""" - modbus.HUB.write_registers(self._slave, register, [value, 0]) + self.client.write_registers(self._slave, register, [value, 0]) diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 833cb0c5a628e3..98c7bd53944352 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -6,75 +6,104 @@ """ import logging import struct +from typing import TYPE_CHECKING, Any import voluptuous as vol from homeassistant.components import modbus +from homeassistant.components.modbus import CONF_HUB_NAME +from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( - CONF_NAME, CONF_OFFSET, CONF_UNIT_OF_MEASUREMENT, CONF_SLAVE, - CONF_STRUCTURE) -from homeassistant.helpers.entity import Entity + CONF_NAME, + CONF_OFFSET, + CONF_SLAVE, + CONF_STRUCTURE, + CONF_UNIT_OF_MEASUREMENT, +) from homeassistant.helpers import config_validation as cv -from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.helpers.entity import Entity + +if TYPE_CHECKING: + from pymodbus.client.sync import BaseModbusClient _LOGGER = logging.getLogger(__name__) -DEPENDENCIES = ['modbus'] +DEPENDENCIES = ["modbus"] -CONF_COUNT = 'count' -CONF_REVERSE_ORDER = 'reverse_order' -CONF_PRECISION = 'precision' -CONF_REGISTER = 'register' -CONF_REGISTERS = 'registers' -CONF_SCALE = 'scale' -CONF_DATA_TYPE = 'data_type' -CONF_REGISTER_TYPE = 'register_type' +CONF_COUNT = "count" +CONF_REVERSE_ORDER = "reverse_order" +CONF_PRECISION = "precision" +CONF_REGISTER = "register" +CONF_REGISTERS = "registers" +CONF_SCALE = "scale" +CONF_DATA_TYPE = "data_type" +CONF_REGISTER_TYPE = "register_type" -REGISTER_TYPE_HOLDING = 'holding' -REGISTER_TYPE_INPUT = 'input' +REGISTER_TYPE_HOLDING = "holding" +REGISTER_TYPE_INPUT = "input" -DATA_TYPE_INT = 'int' -DATA_TYPE_UINT = 'uint' -DATA_TYPE_FLOAT = 'float' -DATA_TYPE_CUSTOM = 'custom' +DATA_TYPE_INT = "int" +DATA_TYPE_UINT = "uint" +DATA_TYPE_FLOAT = "float" +DATA_TYPE_CUSTOM = "custom" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_REGISTERS): [{ - vol.Required(CONF_NAME): cv.string, - vol.Required(CONF_REGISTER): cv.positive_int, + vol.Required(CONF_HUB_NAME, default="default"): + cv.string, + vol.Required(CONF_NAME): + cv.string, + vol.Required(CONF_REGISTER): + cv.positive_int, vol.Optional(CONF_REGISTER_TYPE, default=REGISTER_TYPE_HOLDING): vol.In([REGISTER_TYPE_HOLDING, REGISTER_TYPE_INPUT]), - vol.Optional(CONF_COUNT, default=1): cv.positive_int, - vol.Optional(CONF_REVERSE_ORDER, default=False): cv.boolean, - vol.Optional(CONF_OFFSET, default=0): vol.Coerce(float), - vol.Optional(CONF_PRECISION, default=0): cv.positive_int, - vol.Optional(CONF_SCALE, default=1): vol.Coerce(float), - vol.Optional(CONF_SLAVE): cv.positive_int, + vol.Optional(CONF_COUNT, default=1): + cv.positive_int, + vol.Optional(CONF_REVERSE_ORDER, default=False): + cv.boolean, + vol.Optional(CONF_OFFSET, default=0): + vol.Coerce(float), + vol.Optional(CONF_PRECISION, default=0): + cv.positive_int, + vol.Optional(CONF_SCALE, default=1): + vol.Coerce(float), + vol.Optional(CONF_SLAVE): + 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_CUSTOM]), - vol.Optional(CONF_STRUCTURE): cv.string, - vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string + vol.In([ + DATA_TYPE_INT, DATA_TYPE_UINT, DATA_TYPE_FLOAT, + DATA_TYPE_CUSTOM + ]), + vol.Optional(CONF_STRUCTURE): + cv.string, + vol.Optional(CONF_UNIT_OF_MEASUREMENT): + cv.string, }] }) -def setup_platform(hass, config, add_entities, discovery_info=None): +def setup_platform(hass: Any, + config: dict, + add_entities: Any, + discovery_info: Any = None) -> bool: """Set up the Modbus sensors.""" sensors = [] - data_types = {DATA_TYPE_INT: {1: 'h', 2: 'i', 4: 'q'}} - data_types[DATA_TYPE_UINT] = {1: 'H', 2: 'I', 4: 'Q'} - data_types[DATA_TYPE_FLOAT] = {1: 'e', 2: 'f', 4: 'd'} + data_types = {DATA_TYPE_INT: {1: "h", 2: "i", 4: "q"}} + data_types[DATA_TYPE_UINT] = {1: "H", 2: "I", 4: "Q"} + data_types[DATA_TYPE_FLOAT] = {1: "e", 2: "f", 4: "d"} for register in config.get(CONF_REGISTERS): - structure = '>i' + structure = ">i" if register.get(CONF_DATA_TYPE) != DATA_TYPE_CUSTOM: try: - structure = '>{}'.format(data_types[ - register.get(CONF_DATA_TYPE)][register.get(CONF_COUNT)]) + structure = ">{}".format(data_types[register.get( + CONF_DATA_TYPE)][register.get(CONF_COUNT)]) except KeyError: - _LOGGER.error("Unable to detect data type for %s sensor, " - "try a custom type.", register.get(CONF_NAME)) + _LOGGER.error( + "Unable to detect data type for %s sensor, " + "try a custom type.", + register.get(CONF_NAME), + ) continue else: structure = register.get(CONF_STRUCTURE) @@ -82,42 +111,49 @@ def setup_platform(hass, config, add_entities, discovery_info=None): try: size = struct.calcsize(structure) except struct.error as err: - _LOGGER.error( - "Error in sensor %s structure: %s", - register.get(CONF_NAME), err) + _LOGGER.error("Error in sensor %s structure: %s", + register.get(CONF_NAME), err) continue if register.get(CONF_COUNT) * 2 != size: _LOGGER.error( "Structure size (%d bytes) mismatch registers count " - "(%d words)", size, register.get(CONF_COUNT)) + "(%d words)", + size, + register.get(CONF_COUNT), + ) continue - sensors.append(ModbusRegisterSensor( - register.get(CONF_NAME), - register.get(CONF_SLAVE), - register.get(CONF_REGISTER), - register.get(CONF_REGISTER_TYPE), - register.get(CONF_UNIT_OF_MEASUREMENT), - register.get(CONF_COUNT), - register.get(CONF_REVERSE_ORDER), - register.get(CONF_SCALE), - register.get(CONF_OFFSET), - structure, - register.get(CONF_PRECISION))) + sensors.append( + ModbusRegisterSensor( + register.get(CONF_HUB_NAME), + register.get(CONF_NAME), + register.get(CONF_SLAVE), + register.get(CONF_REGISTER), + register.get(CONF_REGISTER_TYPE), + register.get(CONF_UNIT_OF_MEASUREMENT), + register.get(CONF_COUNT), + register.get(CONF_REVERSE_ORDER), + register.get(CONF_SCALE), + register.get(CONF_OFFSET), + structure, + register.get(CONF_PRECISION), + )) if not sensors: return False add_entities(sensors) + return True class ModbusRegisterSensor(Entity): """Modbus register sensor.""" - def __init__(self, name, slave, register, register_type, + def __init__(self, hub_name, name, slave, register, register_type, unit_of_measurement, count, reverse_order, scale, offset, structure, precision): """Initialize the modbus register sensor.""" + self._hub_name = hub_name self._name = name self._slave = int(slave) if slave else None self._register = int(register) @@ -129,35 +165,36 @@ def __init__(self, name, slave, register, register_type, self._offset = offset self._precision = precision self._structure = structure - self._value = None + self._value: str = None @property - def state(self): + def state(self) -> str: """Return the state of the sensor.""" return self._value @property - def name(self): + def name(self) -> str: """Return the name of the sensor.""" return self._name @property - def unit_of_measurement(self): + def unit_of_measurement(self) -> str: """Return the unit of measurement.""" return self._unit_of_measurement - def update(self): + @property + def client(self) -> "BaseModbusClient": + """Find and return the client from modbus HUB.""" + return modbus.HUB[self._hub_name] + + def update(self) -> None: """Update the state of the sensor.""" if self._register_type == REGISTER_TYPE_INPUT: - result = modbus.HUB.read_input_registers( - self._slave, - self._register, - self._count) + result = self.client.read_input_registers( + self._slave, self._register, self._count) else: - result = modbus.HUB.read_holding_registers( - self._slave, - self._register, - self._count) + result = self.client.read_holding_registers( + self._slave, self._register, self._count) val = 0 try: @@ -165,12 +202,14 @@ def update(self): if self._reverse_order: registers.reverse() except AttributeError: - _LOGGER.error("No response from modbus slave %s, register %s", - self._slave, self._register) + _LOGGER.error( + "No response from modbus slave %s, register %s", + self._slave, + self._register, + ) return - byte_string = b''.join( - [x.to_bytes(2, byteorder='big') for x in registers] - ) + byte_string = b"".join( + [x.to_bytes(2, byteorder="big") for x in registers]) val = struct.unpack(self._structure, byte_string)[0] - self._value = format( - self._scale * val + self._offset, '.{}f'.format(self._precision)) + self._value = format(self._scale * val + self._offset, + ".{}f".format(self._precision)) diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index a8c8358f0cf19e..28ed7f39f525c2 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -5,14 +5,16 @@ https://home-assistant.io/components/switch.modbus/ """ import logging + import voluptuous as vol from homeassistant.components import modbus -from homeassistant.const import ( - CONF_NAME, CONF_SLAVE, CONF_COMMAND_ON, CONF_COMMAND_OFF) -from homeassistant.helpers.entity import ToggleEntity -from homeassistant.helpers import config_validation as cv +from homeassistant.components.modbus import CONF_HUB_NAME from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import (CONF_COMMAND_OFF, CONF_COMMAND_ON, CONF_NAME, + CONF_SLAVE) +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.entity import ToggleEntity _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] @@ -31,21 +33,32 @@ REGISTER_TYPE_INPUT = 'input' REGISTERS_SCHEMA = vol.Schema({ - vol.Required(CONF_NAME): cv.string, - vol.Optional(CONF_SLAVE): cv.positive_int, - vol.Required(CONF_REGISTER): cv.positive_int, - vol.Required(CONF_COMMAND_ON): cv.positive_int, - vol.Required(CONF_COMMAND_OFF): cv.positive_int, - vol.Optional(CONF_VERIFY_STATE, default=True): cv.boolean, + vol.Required(CONF_HUB_NAME, default="default"): + cv.string, + vol.Required(CONF_NAME): + cv.string, + vol.Optional(CONF_SLAVE): + cv.positive_int, + vol.Required(CONF_REGISTER): + cv.positive_int, + vol.Required(CONF_COMMAND_ON): + cv.positive_int, + vol.Required(CONF_COMMAND_OFF): + cv.positive_int, + vol.Optional(CONF_VERIFY_STATE, default=True): + cv.boolean, vol.Optional(CONF_VERIFY_REGISTER): cv.positive_int, vol.Optional(CONF_REGISTER_TYPE, default=REGISTER_TYPE_HOLDING): vol.In([REGISTER_TYPE_HOLDING, REGISTER_TYPE_INPUT]), - vol.Optional(CONF_STATE_ON): cv.positive_int, - vol.Optional(CONF_STATE_OFF): cv.positive_int, + vol.Optional(CONF_STATE_ON): + cv.positive_int, + vol.Optional(CONF_STATE_OFF): + cv.positive_int, }) COILS_SCHEMA = vol.Schema({ + vol.Required(CONF_HUB_NAME, default="default"): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_SLAVE): cv.positive_int, @@ -64,31 +77,31 @@ def setup_platform(hass, config, add_entities, discovery_info=None): switches = [] if CONF_COILS in config: for coil in config.get(CONF_COILS): - switches.append(ModbusCoilSwitch( - coil.get(CONF_NAME), - coil.get(CONF_SLAVE), - coil.get(CONF_COIL))) + switches.append( + ModbusCoilSwitch( + coil.get(CONF_HUB_NAME), coil.get(CONF_NAME), + coil.get(CONF_SLAVE), coil.get(CONF_COIL))) if CONF_REGISTERS in config: for register in config.get(CONF_REGISTERS): - switches.append(ModbusRegisterSwitch( - register.get(CONF_NAME), - register.get(CONF_SLAVE), - register.get(CONF_REGISTER), - register.get(CONF_COMMAND_ON), - register.get(CONF_COMMAND_OFF), - register.get(CONF_VERIFY_STATE), - register.get(CONF_VERIFY_REGISTER), - register.get(CONF_REGISTER_TYPE), - register.get(CONF_STATE_ON), - register.get(CONF_STATE_OFF))) + switches.append( + ModbusRegisterSwitch( + register.get(CONF_HUB_NAME), register.get(CONF_NAME), + register.get(CONF_SLAVE), register.get(CONF_REGISTER), + register.get(CONF_COMMAND_ON), + register.get(CONF_COMMAND_OFF), + register.get(CONF_VERIFY_STATE), + register.get(CONF_VERIFY_REGISTER), + register.get(CONF_REGISTER_TYPE), + register.get(CONF_STATE_ON), register.get(CONF_STATE_OFF))) add_entities(switches) class ModbusCoilSwitch(ToggleEntity): """Representation of a Modbus coil switch.""" - def __init__(self, name, slave, coil): + def __init__(self, hub_name, name, slave, coil): """Initialize the coil switch.""" + self._hub_name = hub_name self._name = name self._slave = int(slave) if slave else None self._coil = int(coil) @@ -104,42 +117,46 @@ def name(self): """Return the name of the switch.""" return self._name + @property + def client(self) -> "BaseModbusClient": + """Find and return the client from modbus HUB.""" + return modbus.HUB[self._hub_name] + def turn_on(self, **kwargs): """Set switch on.""" - modbus.HUB.write_coil(self._slave, self._coil, True) + self.client.write_coil(self._slave, self._coil, True) def turn_off(self, **kwargs): """Set switch off.""" - modbus.HUB.write_coil(self._slave, self._coil, False) + self.client.write_coil(self._slave, self._coil, False) def update(self): """Update the state of the switch.""" - result = modbus.HUB.read_coils(self._slave, self._coil, 1) + result = self.client.read_coils(self._slave, self._coil, 1) try: self._is_on = bool(result.bits[0]) except AttributeError: - _LOGGER.error( - 'No response from modbus slave %s coil %s', - self._slave, - self._coil) + _LOGGER.error('No response from modbus slave %s coil %s', + self._slave, self._coil) class ModbusRegisterSwitch(ModbusCoilSwitch): """Representation of a Modbus register switch.""" # pylint: disable=super-init-not-called - def __init__(self, name, slave, register, command_on, - command_off, verify_state, verify_register, - register_type, state_on, state_off): + def __init__(self, hub_name, name, slave, register, command_on, + command_off, verify_state, verify_register, register_type, + state_on, state_off): """Initialize the register switch.""" + self._hub_name = hub_name self._name = name self._slave = slave self._register = register self._command_on = command_on self._command_off = command_off self._verify_state = verify_state - self._verify_register = ( - verify_register if verify_register else self._register) + self._verify_register = (verify_register + if verify_register else self._register) self._register_type = register_type if state_on is not None: @@ -154,21 +171,22 @@ def __init__(self, name, slave, register, command_on, self._is_on = None + @property + def client(self) -> "BaseModbusClient": + """Find and return the client from modbus HUB.""" + return modbus.HUB[self._hub_name] + def turn_on(self, **kwargs): """Set switch on.""" - modbus.HUB.write_register( - self._slave, - self._register, - self._command_on) + self.client.write_register(self._slave, self._register, + self._command_on) if not self._verify_state: self._is_on = True def turn_off(self, **kwargs): """Set switch off.""" - modbus.HUB.write_register( - self._slave, - self._register, - self._command_off) + self.client.write_register(self._slave, self._register, + self._command_off) if not self._verify_state: self._is_on = False @@ -179,23 +197,17 @@ def update(self): value = 0 if self._register_type == REGISTER_TYPE_INPUT: - result = modbus.HUB.read_input_registers( - self._slave, - self._register, - 1) + result = self.client.read_input_registers(self._slave, + self._register, 1) else: - result = modbus.HUB.read_holding_registers( - self._slave, - self._register, - 1) + result = self.client.read_holding_registers( + self._slave, self._register, 1) try: value = int(result.registers[0]) except AttributeError: - _LOGGER.error( - 'No response from modbus slave %s register %s', - self._slave, - self._verify_register) + _LOGGER.error('No response from modbus slave %s register %s', + self._slave, self._verify_register) if value == self._state_on: self._is_on = True @@ -204,7 +216,5 @@ def update(self): else: _LOGGER.error( 'Unexpected response from modbus slave %s ' - 'register %s, got 0x%2x', - self._slave, - self._verify_register, + 'register %s, got 0x%2x', self._slave, self._verify_register, value) From ac81d9e8c5514f8ae811054fbd629c806708e35e Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Sat, 27 Oct 2018 21:00:23 +0800 Subject: [PATCH 02/18] update data after entities added --- homeassistant/components/modbus/binary_sensor.py | 2 +- homeassistant/components/modbus/sensor.py | 2 +- homeassistant/components/modbus/switch.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index b25d707f21e575..5633551bae432a 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -39,7 +39,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): ModbusCoilSensor( coil.get(CONF_HUB_NAME), coil.get(CONF_NAME), coil.get(CONF_SLAVE), coil.get(CONF_COIL))) - add_entities(sensors) + add_entities(sensors, True) class ModbusCoilSensor(BinarySensorDevice): diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 98c7bd53944352..20edb4fd690609 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -142,7 +142,7 @@ def setup_platform(hass: Any, if not sensors: return False - add_entities(sensors) + add_entities(sensors, True) return True diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index 28ed7f39f525c2..259edcc17d9e71 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -93,7 +93,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): register.get(CONF_VERIFY_REGISTER), register.get(CONF_REGISTER_TYPE), register.get(CONF_STATE_ON), register.get(CONF_STATE_OFF))) - add_entities(switches) + add_entities(switches, True) class ModbusCoilSwitch(ToggleEntity): From e9016d5ba850715445db6e4f2853ca8b0f765841 Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Sun, 28 Oct 2018 09:22:36 +0800 Subject: [PATCH 03/18] pass hub object to each entity. and save hub to hass.data but not in module level --- homeassistant/components/modbus/__init__.py | 23 ++--- .../components/modbus/binary_sensor.py | 30 +++---- homeassistant/components/modbus/climate.py | 34 ++++---- homeassistant/components/modbus/sensor.py | 36 ++++---- homeassistant/components/modbus/switch.py | 84 +++++++++---------- 5 files changed, 99 insertions(+), 108 deletions(-) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 8027eb887bd79a..09026eb150ef9f 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -6,7 +6,7 @@ """ import logging import threading -from typing import TYPE_CHECKING, Any, Dict, List +from typing import TYPE_CHECKING, Any, List import voluptuous as vol @@ -16,6 +16,7 @@ EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) if TYPE_CHECKING: + # pylint: disable=unused-import from pymodbus.client.sync import BaseModbusClient DOMAIN = 'modbus' @@ -61,6 +62,7 @@ def check_base_on_type(value: Any) -> Any: raise vol.Invalid("%s %s is not supported" % (CONF_TYPE, value[CONF_TYPE])) + CONFIG_SCHEMA = vol.Schema( { DOMAIN: @@ -93,8 +95,6 @@ def check_base_on_type(value: Any) -> Any: vol.Required(ATTR_STATE): cv.boolean, }) -HUB = {} # type: Dict[str, BaseModbusClient] - def setup_client(client_config: dict) -> "BaseModbusClient": """Setup pymodbus client.""" @@ -148,21 +148,21 @@ def setup_client(client_config: dict) -> "BaseModbusClient": def setup(hass: Any, config: dict) -> bool: """Set up Modbus component.""" # Modbus connection type - global HUB + hass.data[DOMAIN] = hub_collect = {} for client_config in config[DOMAIN]: client = setup_client(client_config) client_name = client_config[CONF_HUB_NAME] - HUB[client_name] = ModbusHub(client) + hub_collect[client_name] = ModbusHub(client) def stop_modbus(event: Any) -> None: """Stop Modbus service.""" - for client in HUB.values(): + for client in hub_collect.values(): client.close() def start_modbus(event: Any) -> None: """Start Modbus service.""" - for client in HUB.values(): + for client in hub_collect.values(): client.connect() hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_modbus) @@ -187,10 +187,11 @@ def write_register(service: Any) -> None: value = service.data.get(ATTR_VALUE) client_name = service.data.get(CONF_HUB_NAME) if isinstance(value, list): - HUB[client_name].write_registers(unit, address, - [int(float(i)) for i in value]) + hub_collect[client_name].write_registers( + unit, address, [int(float(i)) for i in value]) else: - HUB[client_name].write_register(unit, address, int(float(value))) + hub_collect[client_name].write_register(unit, address, + int(float(value))) def write_coil(service: Any) -> None: """Write modbus coil.""" @@ -198,7 +199,7 @@ def write_coil(service: Any) -> None: address = service.data.get(ATTR_ADDRESS) state = service.data.get(ATTR_STATE) client_name = service.data.get(CONF_HUB_NAME) - HUB[client_name].write_coil(unit, address, state) + hub_collect[client_name].write_coil(unit, address, state) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_modbus) diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index 5633551bae432a..494f2941e9ad56 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -5,16 +5,20 @@ https://home-assistant.io/components/binary_sensor.modbus/ """ import logging +from typing import TYPE_CHECKING import voluptuous as vol -from homeassistant.components import modbus from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.components.modbus import CONF_HUB_NAME +from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import CONF_NAME, CONF_SLAVE from homeassistant.helpers import config_validation as cv +if TYPE_CHECKING: + # pylint: disable=unused-import + from pymodbus.client.sync import BaseModbusClient + _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] @@ -31,23 +35,24 @@ }) -def setup_platform(hass, config, add_entities, discovery_info=None): +def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Modbus binary sensors.""" sensors = [] for coil in config.get(CONF_COILS): + hub_name = coil.get(CONF_HUB_NAME) + hub = hass.data[DOMAIN][hub_name] sensors.append( - ModbusCoilSensor( - coil.get(CONF_HUB_NAME), coil.get(CONF_NAME), - coil.get(CONF_SLAVE), coil.get(CONF_COIL))) - add_entities(sensors, True) + ModbusCoilSensor(hub, coil.get(CONF_NAME), coil.get(CONF_SLAVE), + coil.get(CONF_COIL))) + add_devices(sensors) class ModbusCoilSensor(BinarySensorDevice): """Modbus coil sensor.""" - def __init__(self, hub_name, name, slave, coil): + def __init__(self, hub, name, slave, coil): """Initialize the modbus coil sensor.""" - self._hub_name = hub_name + self._hub: "BaseModbusClient" = hub self._name = name self._slave = int(slave) if slave else None self._coil = int(coil) @@ -63,14 +68,9 @@ def is_on(self): """Return the state of the sensor.""" return self._value - @property - def client(self) -> "BaseModbusClient": - """Find and return the client from modbus HUB.""" - return modbus.HUB[self._hub_name] - def update(self): """Update the state of the sensor.""" - result = self.client.read_coils(self._slave, self._coil, 1) + result = self._hub.read_coils(self._slave, self._coil, 1) try: self._value = result.bits[0] except AttributeError: diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index ce4915184bc94b..a6584dbc50f0f1 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -10,16 +10,20 @@ """ import logging import struct +from typing import TYPE_CHECKING import voluptuous as vol import homeassistant.helpers.config_validation as cv -from homeassistant.components import modbus -from homeassistant.components.climate import (ClimateDevice, PLATFORM_SCHEMA, - SUPPORT_TARGET_TEMPERATURE) -from homeassistant.components.modbus import CONF_HUB_NAME +from homeassistant.components.climate import ( + PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE, ClimateDevice) +from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN from homeassistant.const import ATTR_TEMPERATURE, CONF_NAME, CONF_SLAVE +if TYPE_CHECKING: + # pylint: disable=unused-import + from pymodbus.client.sync import BaseModbusClient + DEPENDENCIES = ['modbus'] # Parameters not defined by homeassistant.const @@ -57,7 +61,7 @@ SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE -def setup_platform(hass, config, add_entities, discovery_info=None): +def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Modbus Thermostat Platform.""" name = config.get(CONF_NAME) modbus_slave = config.get(CONF_SLAVE) @@ -67,9 +71,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None): count = config.get(CONF_COUNT) precision = config.get(CONF_PRECISION) hub_name = config.get(CONF_HUB_NAME) + hub = hass.data[DOMAIN][hub_name] - add_entities([ - ModbusThermostat(hub_name, name, modbus_slave, target_temp_register, + add_devices([ + ModbusThermostat(hub, name, modbus_slave, target_temp_register, current_temp_register, data_type, count, precision) ], True) @@ -77,10 +82,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None): class ModbusThermostat(ClimateDevice): """Representation of a Modbus Thermostat.""" - def __init__(self, hub_name, name, modbus_slave, target_temp_register, + def __init__(self, hub, name, modbus_slave, target_temp_register, current_temp_register, data_type, count, precision): """Initialize the unit.""" - self._hub_name = hub_name + self._hub: "BaseModbusClient" = hub self._name = name self._slave = modbus_slave self._target_temperature_register = target_temp_register @@ -140,11 +145,6 @@ def target_temperature(self): """Return the temperature we try to reach.""" return self._target_temperature - @property - def client(self) -> "BaseModbusClient": - """Find and return the client from modbus HUB.""" - return modbus.HUB[self._hub_name] - def set_temperature(self, **kwargs): """Set new target temperature.""" target_temperature = kwargs.get(ATTR_TEMPERATURE) @@ -162,8 +162,8 @@ def set_temperature(self, **kwargs): def read_register(self, register): """Read holding register using the modbus hub slave.""" try: - result = self.client.read_holding_registers( - self._slave, register, self._count) + result = self._hub.read_holding_registers(self._slave, register, + self._count) except AttributeError as ex: _LOGGER.error(ex) byte_string = b''.join( @@ -174,4 +174,4 @@ def read_register(self, register): def write_register(self, register, value): """Write register using the modbus hub slave.""" - self.client.write_registers(self._slave, register, [value, 0]) + self._hub.write_registers(self._slave, register, [value, 0]) diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 20edb4fd690609..d870f4343b70be 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -10,20 +10,15 @@ import voluptuous as vol -from homeassistant.components import modbus -from homeassistant.components.modbus import CONF_HUB_NAME +from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import ( - CONF_NAME, - CONF_OFFSET, - CONF_SLAVE, - CONF_STRUCTURE, - CONF_UNIT_OF_MEASUREMENT, -) +from homeassistant.const import (CONF_NAME, CONF_OFFSET, CONF_SLAVE, + CONF_STRUCTURE, CONF_UNIT_OF_MEASUREMENT) from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import Entity if TYPE_CHECKING: + # pylint: disable=unused-import from pymodbus.client.sync import BaseModbusClient _LOGGER = logging.getLogger(__name__) @@ -84,7 +79,7 @@ def setup_platform(hass: Any, config: dict, - add_entities: Any, + add_devices: Any, discovery_info: Any = None) -> bool: """Set up the Modbus sensors.""" sensors = [] @@ -92,7 +87,7 @@ def setup_platform(hass: Any, data_types[DATA_TYPE_UINT] = {1: "H", 2: "I", 4: "Q"} data_types[DATA_TYPE_FLOAT] = {1: "e", 2: "f", 4: "d"} - for register in config.get(CONF_REGISTERS): + for register in config.get(CONF_REGISTERS, []): structure = ">i" if register.get(CONF_DATA_TYPE) != DATA_TYPE_CUSTOM: try: @@ -124,9 +119,11 @@ def setup_platform(hass: Any, ) continue + hub_name = register.get(CONF_HUB_NAME) + hub = hass.data[DOMAIN][hub_name] sensors.append( ModbusRegisterSensor( - register.get(CONF_HUB_NAME), + hub, register.get(CONF_NAME), register.get(CONF_SLAVE), register.get(CONF_REGISTER), @@ -142,18 +139,18 @@ def setup_platform(hass: Any, if not sensors: return False - add_entities(sensors, True) + add_devices(sensors) return True class ModbusRegisterSensor(Entity): """Modbus register sensor.""" - def __init__(self, hub_name, name, slave, register, register_type, + def __init__(self, hub, name, slave, register, register_type, unit_of_measurement, count, reverse_order, scale, offset, structure, precision): """Initialize the modbus register sensor.""" - self._hub_name = hub_name + self._hub: "BaseModbusClient" = hub self._name = name self._slave = int(slave) if slave else None self._register = int(register) @@ -182,18 +179,13 @@ def unit_of_measurement(self) -> str: """Return the unit of measurement.""" return self._unit_of_measurement - @property - def client(self) -> "BaseModbusClient": - """Find and return the client from modbus HUB.""" - return modbus.HUB[self._hub_name] - def update(self) -> None: """Update the state of the sensor.""" if self._register_type == REGISTER_TYPE_INPUT: - result = self.client.read_input_registers( + result = self._hub.read_input_registers( self._slave, self._register, self._count) else: - result = self.client.read_holding_registers( + result = self._hub.read_holding_registers( self._slave, self._register, self._count) val = 0 diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index 259edcc17d9e71..bd8e2abfb2bd3b 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -5,17 +5,21 @@ https://home-assistant.io/components/switch.modbus/ """ import logging +from typing import TYPE_CHECKING import voluptuous as vol -from homeassistant.components import modbus -from homeassistant.components.modbus import CONF_HUB_NAME +from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import (CONF_COMMAND_OFF, CONF_COMMAND_ON, CONF_NAME, CONF_SLAVE) from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import ToggleEntity +if TYPE_CHECKING: + # pylint: disable=unused-import + from pymodbus.client.sync import BaseModbusClient + _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] @@ -72,36 +76,41 @@ })) -def setup_platform(hass, config, add_entities, discovery_info=None): +def setup_platform(hass, config, add_devices, discovery_info=None): """Read configuration and create Modbus devices.""" switches = [] if CONF_COILS in config: for coil in config.get(CONF_COILS): + hub_name = coil.get(CONF_HUB_NAME) + hub = hass.data[DOMAIN][hub_name] switches.append( - ModbusCoilSwitch( - coil.get(CONF_HUB_NAME), coil.get(CONF_NAME), - coil.get(CONF_SLAVE), coil.get(CONF_COIL))) + ModbusCoilSwitch(hub, coil.get(CONF_NAME), + coil.get(CONF_SLAVE), coil.get(CONF_COIL))) if CONF_REGISTERS in config: for register in config.get(CONF_REGISTERS): + hub_name = register.get(CONF_HUB_NAME) + hub = hass.data[DOMAIN][hub_name] + switches.append( - ModbusRegisterSwitch( - register.get(CONF_HUB_NAME), register.get(CONF_NAME), - register.get(CONF_SLAVE), register.get(CONF_REGISTER), - register.get(CONF_COMMAND_ON), - register.get(CONF_COMMAND_OFF), - register.get(CONF_VERIFY_STATE), - register.get(CONF_VERIFY_REGISTER), - register.get(CONF_REGISTER_TYPE), - register.get(CONF_STATE_ON), register.get(CONF_STATE_OFF))) - add_entities(switches, True) + ModbusRegisterSwitch(hub, register.get(CONF_NAME), + register.get(CONF_SLAVE), + register.get(CONF_REGISTER), + register.get(CONF_COMMAND_ON), + register.get(CONF_COMMAND_OFF), + register.get(CONF_VERIFY_STATE), + register.get(CONF_VERIFY_REGISTER), + register.get(CONF_REGISTER_TYPE), + register.get(CONF_STATE_ON), + register.get(CONF_STATE_OFF))) + add_devices(switches) class ModbusCoilSwitch(ToggleEntity): """Representation of a Modbus coil switch.""" - def __init__(self, hub_name, name, slave, coil): + def __init__(self, hub, name, slave, coil): """Initialize the coil switch.""" - self._hub_name = hub_name + self._hub: "BaseModbusClient" = hub self._name = name self._slave = int(slave) if slave else None self._coil = int(coil) @@ -117,22 +126,17 @@ def name(self): """Return the name of the switch.""" return self._name - @property - def client(self) -> "BaseModbusClient": - """Find and return the client from modbus HUB.""" - return modbus.HUB[self._hub_name] - def turn_on(self, **kwargs): """Set switch on.""" - self.client.write_coil(self._slave, self._coil, True) + self._hub.write_coil(self._slave, self._coil, True) def turn_off(self, **kwargs): """Set switch off.""" - self.client.write_coil(self._slave, self._coil, False) + self._hub.write_coil(self._slave, self._coil, False) def update(self): """Update the state of the switch.""" - result = self.client.read_coils(self._slave, self._coil, 1) + result = self._hub.read_coils(self._slave, self._coil, 1) try: self._is_on = bool(result.bits[0]) except AttributeError: @@ -144,11 +148,11 @@ class ModbusRegisterSwitch(ModbusCoilSwitch): """Representation of a Modbus register switch.""" # pylint: disable=super-init-not-called - def __init__(self, hub_name, name, slave, register, command_on, - command_off, verify_state, verify_register, register_type, - state_on, state_off): + def __init__(self, hub, name, slave, register, command_on, command_off, + verify_state, verify_register, register_type, state_on, + state_off): """Initialize the register switch.""" - self._hub_name = hub_name + self._hub: "BaseModbusClient" = hub self._name = name self._slave = slave self._register = register @@ -171,22 +175,16 @@ def __init__(self, hub_name, name, slave, register, command_on, self._is_on = None - @property - def client(self) -> "BaseModbusClient": - """Find and return the client from modbus HUB.""" - return modbus.HUB[self._hub_name] - def turn_on(self, **kwargs): """Set switch on.""" - self.client.write_register(self._slave, self._register, - self._command_on) + self._hub.write_register(self._slave, self._register, self._command_on) if not self._verify_state: self._is_on = True def turn_off(self, **kwargs): """Set switch off.""" - self.client.write_register(self._slave, self._register, - self._command_off) + self._hub.write_register(self._slave, self._register, + self._command_off) if not self._verify_state: self._is_on = False @@ -197,11 +195,11 @@ def update(self): value = 0 if self._register_type == REGISTER_TYPE_INPUT: - result = self.client.read_input_registers(self._slave, - self._register, 1) + result = self._hub.read_input_registers(self._slave, + self._register, 1) else: - result = self.client.read_holding_registers( - self._slave, self._register, 1) + result = self._hub.read_holding_registers(self._slave, + self._register, 1) try: value = int(result.registers[0]) From 7b78534ed80fd0674b1d9a538433aae9e02e660e Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Sun, 28 Oct 2018 09:40:04 +0800 Subject: [PATCH 04/18] add hub_client setup log --- homeassistant/components/modbus/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 09026eb150ef9f..0bbad13b51388a 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -154,6 +154,7 @@ def setup(hass: Any, config: dict) -> bool: client = setup_client(client_config) client_name = client_config[CONF_HUB_NAME] hub_collect[client_name] = ModbusHub(client) + _LOGGER.debug("Setting up hub_client: %s", client_config) def stop_modbus(event: Any) -> None: """Stop Modbus service.""" From 3a606430108a0511574224c77f6800e663030c73 Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Sun, 28 Oct 2018 09:40:30 +0800 Subject: [PATCH 05/18] don't update when adding device, because hub_client is not ready right now --- homeassistant/components/modbus/climate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index a6584dbc50f0f1..9e2a308940b451 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -76,7 +76,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): add_devices([ ModbusThermostat(hub, name, modbus_slave, target_temp_register, current_temp_register, data_type, count, precision) - ], True) + ]) class ModbusThermostat(ClimateDevice): From 88e559a54ee7f19f4a5e6ae8e43637d933970206 Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Sun, 28 Oct 2018 10:36:01 +0800 Subject: [PATCH 06/18] support restore last state --- homeassistant/components/modbus/sensor.py | 8 ++++++++ homeassistant/components/modbus/switch.py | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index d870f4343b70be..9c8d5fd76ad370 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -16,6 +16,7 @@ CONF_STRUCTURE, CONF_UNIT_OF_MEASUREMENT) from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import Entity +from homeassistant.helpers.restore_state import async_get_last_state if TYPE_CHECKING: # pylint: disable=unused-import @@ -164,6 +165,13 @@ def __init__(self, hub, name, slave, register, register_type, self._structure = structure self._value: str = None + async def async_added_to_hass(self): + """Handle entity which will be added.""" + state = await async_get_last_state(self.hass, self.entity_id) + if not state: + return + self._value = state.state + @property def state(self) -> str: """Return the state of the sensor.""" diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index bd8e2abfb2bd3b..ccbe84e0af97a1 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -12,9 +12,10 @@ from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import (CONF_COMMAND_OFF, CONF_COMMAND_ON, CONF_NAME, - CONF_SLAVE) + CONF_SLAVE, STATE_ON) from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import ToggleEntity +from homeassistant.helpers.restore_state import async_get_last_state if TYPE_CHECKING: # pylint: disable=unused-import @@ -116,6 +117,13 @@ def __init__(self, hub, name, slave, coil): self._coil = int(coil) self._is_on = None + async def async_added_to_hass(self): + """Handle entity which will be added.""" + state = await async_get_last_state(self.hass, self.entity_id) + if not state: + return + self._is_on = state.state == STATE_ON + @property def is_on(self): """Return true if switch is on.""" From 154ea7a511a5cd184bf2dcedf2bb84dd3366a55e Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Sun, 28 Oct 2018 10:42:41 +0800 Subject: [PATCH 07/18] remove useless func --- homeassistant/components/modbus/__init__.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 0bbad13b51388a..447aacef168d4a 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -52,17 +52,6 @@ vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout, }) - -def check_base_on_type(value: Any) -> Any: - """Check modbus component schema base on "type".""" - if value[CONF_TYPE] == "serial": - return SERIAL_SCHEMA(value) - if value[CONF_TYPE] in ("tcp", "udp", "rtuovertcp"): - return ETHERNET_SCHEMA(value) - - raise vol.Invalid("%s %s is not supported" % (CONF_TYPE, value[CONF_TYPE])) - - CONFIG_SCHEMA = vol.Schema( { DOMAIN: From e210578197fbb9d486317fc8689fd79b9c007ab7 Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Mon, 29 Oct 2018 14:21:24 +0800 Subject: [PATCH 08/18] compatible with python35 --- homeassistant/components/modbus/binary_sensor.py | 2 +- homeassistant/components/modbus/climate.py | 2 +- homeassistant/components/modbus/sensor.py | 2 +- homeassistant/components/modbus/switch.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index 494f2941e9ad56..5c00e6e70f965a 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -52,7 +52,7 @@ class ModbusCoilSensor(BinarySensorDevice): def __init__(self, hub, name, slave, coil): """Initialize the modbus coil sensor.""" - self._hub: "BaseModbusClient" = hub + self._hub = hub # type: BaseModbusClient self._name = name self._slave = int(slave) if slave else None self._coil = int(coil) diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 9e2a308940b451..059c6bf4a7cfce 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -85,7 +85,7 @@ class ModbusThermostat(ClimateDevice): def __init__(self, hub, name, modbus_slave, target_temp_register, current_temp_register, data_type, count, precision): """Initialize the unit.""" - self._hub: "BaseModbusClient" = hub + self._hub = hub # type: BaseModbusClient self._name = name self._slave = modbus_slave self._target_temperature_register = target_temp_register diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 9c8d5fd76ad370..b5801e51376711 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -151,7 +151,7 @@ def __init__(self, hub, name, slave, register, register_type, unit_of_measurement, count, reverse_order, scale, offset, structure, precision): """Initialize the modbus register sensor.""" - self._hub: "BaseModbusClient" = hub + self._hub = hub # type: BaseModbusClient self._name = name self._slave = int(slave) if slave else None self._register = int(register) diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index ccbe84e0af97a1..cdf038ad558fa7 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -111,7 +111,7 @@ class ModbusCoilSwitch(ToggleEntity): def __init__(self, hub, name, slave, coil): """Initialize the coil switch.""" - self._hub: "BaseModbusClient" = hub + self._hub = hub # type: BaseModbusClient self._name = name self._slave = int(slave) if slave else None self._coil = int(coil) @@ -160,7 +160,7 @@ def __init__(self, hub, name, slave, register, command_on, command_off, verify_state, verify_register, register_type, state_on, state_off): """Initialize the register switch.""" - self._hub: "BaseModbusClient" = hub + self._hub = hub # type: BaseModbusClient self._name = name self._slave = slave self._register = register From e6ab38c2a4f9de9c8ab935e99df246ef3139cddf Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Wed, 19 Dec 2018 23:35:56 +0100 Subject: [PATCH 09/18] removed unrelated style changes --- homeassistant/components/modbus/__init__.py | 220 +++++++++--------- .../components/modbus/binary_sensor.py | 26 +-- homeassistant/components/modbus/climate.py | 71 ++---- homeassistant/components/modbus/sensor.py | 189 +++++++-------- homeassistant/components/modbus/switch.py | 141 +++++------ 5 files changed, 294 insertions(+), 353 deletions(-) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 447aacef168d4a..abb83ed75cc194 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -6,135 +6,111 @@ """ import logging import threading -from typing import TYPE_CHECKING, Any, List import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.const import ( - ATTR_STATE, CONF_HOST, CONF_METHOD, CONF_PORT, CONF_TIMEOUT, CONF_TYPE, - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) - -if TYPE_CHECKING: - # pylint: disable=unused-import - from pymodbus.client.sync import BaseModbusClient + EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, + CONF_HOST, CONF_METHOD, CONF_PORT, CONF_TYPE, CONF_TIMEOUT, ATTR_STATE) DOMAIN = 'modbus' REQUIREMENTS = ['pymodbus==1.5.2'] # Type of network -CONF_BAUDRATE = "baudrate" -CONF_BYTESIZE = "bytesize" -CONF_STOPBITS = "stopbits" -CONF_PARITY = "parity" -CONF_HUB_NAME = "hub_name" +CONF_BAUDRATE = 'baudrate' +CONF_BYTESIZE = 'bytesize' +CONF_STOPBITS = 'stopbits' +CONF_PARITY = 'parity' +CONF_HUB_NAME = 'hub_name' BASE_SCHEMA = vol.Schema({ - vol.Optional(CONF_HUB_NAME, default="default"): cv.string + vol.Optional(CONF_HUB_NAME, default='default'): cv.string }) SERIAL_SCHEMA = BASE_SCHEMA.extend({ 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_METHOD): vol.Any('rtu', 'ascii'), vol.Required(CONF_PORT): cv.string, - vol.Required(CONF_PARITY): vol.Any("E", "O", "N"), + vol.Required(CONF_PARITY): vol.Any('E', 'O', 'N'), vol.Required(CONF_STOPBITS): vol.Any(1, 2), - vol.Required(CONF_TYPE): "serial", + vol.Required(CONF_TYPE): 'serial', vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout, }) ETHERNET_SCHEMA = BASE_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_PORT): cv.port, - vol.Required(CONF_TYPE): vol.Any("tcp", "udp", "rtuovertcp"), + vol.Required(CONF_TYPE): vol.Any('tcp', 'udp', 'rtuovertcp'), vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout, }) -CONFIG_SCHEMA = vol.Schema( - { - DOMAIN: - vol.All(cv.ensure_list, - vol.Schema([vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA)])) - }, - extra=vol.ALLOW_EXTRA, -) +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: + vol.All(cv.ensure_list, + vol.Schema([vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA)])) +}, extra=vol.ALLOW_EXTRA,) _LOGGER = logging.getLogger(__name__) -SERVICE_WRITE_REGISTER = "write_register" -SERVICE_WRITE_COIL = "write_coil" +SERVICE_WRITE_REGISTER = 'write_register' +SERVICE_WRITE_COIL = 'write_coil' -ATTR_ADDRESS = "address" -ATTR_UNIT = "unit" -ATTR_VALUE = "value" +ATTR_ADDRESS = 'address' +ATTR_UNIT = 'unit' +ATTR_VALUE = 'value' SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema({ - vol.Optional(CONF_HUB_NAME, default="default"): cv.string, + vol.Optional(CONF_HUB_NAME, default='default'): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, - vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int]), + vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int]) }) SERVICE_WRITE_COIL_SCHEMA = vol.Schema({ - vol.Optional(CONF_HUB_NAME, default="default"): cv.string, + vol.Optional(CONF_HUB_NAME, default='default'): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, - vol.Required(ATTR_STATE): cv.boolean, + vol.Required(ATTR_STATE): cv.boolean }) -def setup_client(client_config: dict) -> "BaseModbusClient": - """Setup pymodbus client.""" - from pymodbus.client.sync import ( - ModbusTcpClient, - ModbusUdpClient, - ModbusSerialClient, - ) - from pymodbus.transaction import ModbusRtuFramer - +def setup_client(client_config): + """Set up pymodbus client.""" client_type = client_config[CONF_TYPE] - # Connect to Modbus network - # pylint: disable=import-error - - if client_type == "serial": - - return ModbusSerialClient( - method=client_config[CONF_METHOD], - port=client_config[CONF_PORT], - baudrate=client_config[CONF_BAUDRATE], - stopbits=client_config[CONF_STOPBITS], - bytesize=client_config[CONF_BYTESIZE], - parity=client_config[CONF_PARITY], - timeout=client_config[CONF_TIMEOUT], - ) - if client_type == "rtuovertcp": - - return ModbusTcpClient( - host=client_config[CONF_HOST], - port=client_config[CONF_PORT], - framer=ModbusRtuFramer, - timeout=client_config[CONF_TIMEOUT], - ) - if client_type == "tcp": - return ModbusTcpClient( - host=client_config[CONF_HOST], - port=client_config[CONF_PORT], - timeout=client_config[CONF_TIMEOUT], - ) - if client_type == "udp": - return ModbusUdpClient( - host=client_config[CONF_HOST], - port=client_config[CONF_PORT], - timeout=client_config[CONF_TIMEOUT], - ) - + if client_type == 'serial': + from pymodbus.client.sync import ModbusSerialClient as ModbusClient + return ModbusClient(method=client_config[CONF_METHOD], + port=client_config[CONF_PORT], + baudrate=client_config[CONF_BAUDRATE], + stopbits=client_config[CONF_STOPBITS], + bytesize=client_config[CONF_BYTESIZE], + parity=client_config[CONF_PARITY], + timeout=client_config[CONF_TIMEOUT]) + if client_type == 'rtuovertcp': + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + from pymodbus.transaction import ModbusRtuFramer + return ModbusClient(host=client_config[CONF_HOST], + port=client_config[CONF_PORT], + framer=ModbusRtuFramer, + timeout=client_config[CONF_TIMEOUT]) + if client_type == 'tcp': + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + return ModbusClient(host=client_config[CONF_HOST], + port=client_config[CONF_PORT], + timeout=client_config[CONF_TIMEOUT]) + if client_type == 'udp': + from pymodbus.client.sync import ModbusUdpClient as ModbusClient + return ModbusClient(host=client_config[CONF_HOST], + port=client_config[CONF_PORT], + timeout=client_config[CONF_TIMEOUT]) assert False -def setup(hass: Any, config: dict) -> bool: +def setup(hass, config): """Set up Modbus component.""" # Modbus connection type hass.data[DOMAIN] = hub_collect = {} @@ -143,14 +119,14 @@ def setup(hass: Any, config: dict) -> bool: client = setup_client(client_config) client_name = client_config[CONF_HUB_NAME] hub_collect[client_name] = ModbusHub(client) - _LOGGER.debug("Setting up hub_client: %s", client_config) + _LOGGER.debug('Setting up hub_client: %s', client_config) - def stop_modbus(event: Any) -> None: + def stop_modbus(event): """Stop Modbus service.""" for client in hub_collect.values(): client.close() - def start_modbus(event: Any) -> None: + def start_modbus(event): """Start Modbus service.""" for client in hub_collect.values(): client.connect() @@ -162,15 +138,14 @@ def start_modbus(event: Any) -> None: DOMAIN, SERVICE_WRITE_REGISTER, write_register, - schema=SERVICE_WRITE_REGISTER_SCHEMA, - ) + schema=SERVICE_WRITE_REGISTER_SCHEMA) hass.services.register( DOMAIN, SERVICE_WRITE_COIL, write_coil, schema=SERVICE_WRITE_COIL_SCHEMA) - def write_register(service: Any) -> None: + def write_register(service): """Write modbus registers.""" unit = int(float(service.data.get(ATTR_UNIT))) address = int(float(service.data.get(ATTR_ADDRESS))) @@ -178,12 +153,16 @@ def write_register(service: Any) -> None: client_name = service.data.get(CONF_HUB_NAME) if isinstance(value, list): hub_collect[client_name].write_registers( - unit, address, [int(float(i)) for i in value]) + unit, + address, + [int(float(i)) for i in value]) else: - hub_collect[client_name].write_register(unit, address, - int(float(value))) + hub_collect[client_name].write_register( + unit, + address, + int(float(value))) - def write_coil(service: Any) -> None: + def write_coil(service): """Write modbus coil.""" unit = service.data.get(ATTR_UNIT) address = service.data.get(ATTR_ADDRESS) @@ -199,56 +178,71 @@ def write_coil(service: Any) -> None: class ModbusHub: """Thread safe wrapper class for pymodbus.""" - def __init__(self, modbus_client: "BaseModbusClient") -> None: + def __init__(self, modbus_client): """Initialize the modbus hub.""" self._client = modbus_client self._lock = threading.Lock() - def close(self) -> None: + def close(self): """Disconnect client.""" with self._lock: self._client.close() - def connect(self) -> None: + def connect(self): """Connect client.""" with self._lock: self._client.connect() - def read_coils(self, unit: int, address: int, count: int) -> Any: + def read_coils(self, unit, address, count): """Read coils.""" with self._lock: - kwargs = {"unit": unit} if unit else {} - return self._client.read_coils(address, count, **kwargs) + kwargs = {'unit': unit} if unit else {} + return self._client.read_coils( + address, + count, + **kwargs) - def read_input_registers(self, unit: int, address: int, count: int) -> Any: + def read_input_registers(self, unit, address, count): """Read input registers.""" with self._lock: - kwargs = {"unit": unit} if unit else {} - return self._client.read_input_registers(address, count, **kwargs) + kwargs = {'unit': unit} if unit else {} + return self._client.read_input_registers( + address, + count, + **kwargs) - def read_holding_registers(self, unit: int, address: int, - count: int) -> Any: + def read_holding_registers(self, unit, address, count): """Read holding registers.""" with self._lock: - kwargs = {"unit": unit} if unit else {} - return self._client.read_holding_registers(address, count, - **kwargs) + kwargs = {'unit': unit} if unit else {} + return self._client.read_holding_registers( + address, + count, + **kwargs) - def write_coil(self, unit: int, address: int, value: int) -> Any: + def write_coil(self, unit, address, value): """Write coil.""" with self._lock: - kwargs = {"unit": unit} if unit else {} - self._client.write_coil(address, value, **kwargs) + kwargs = {'unit': unit} if unit else {} + self._client.write_coil( + address, + value, + **kwargs) - def write_register(self, unit: int, address: int, value: int) -> Any: + def write_register(self, unit, address, value): """Write register.""" with self._lock: - kwargs = {"unit": unit} if unit else {} - self._client.write_register(address, value, **kwargs) + kwargs = {'unit': unit} if unit else {} + self._client.write_register( + address, + value, + **kwargs) - def write_registers(self, unit: int, address: int, - values: List[int]) -> Any: + def write_registers(self, unit, address, values): """Write registers.""" with self._lock: - kwargs = {"unit": unit} if unit else {} - self._client.write_registers(address, values, **kwargs) + kwargs = {'unit': unit} if unit else {} + self._client.write_registers( + address, + values, + **kwargs) diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index 5c00e6e70f965a..673c6e2c54dcf5 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -5,19 +5,13 @@ https://home-assistant.io/components/binary_sensor.modbus/ """ import logging -from typing import TYPE_CHECKING - import voluptuous as vol -from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN -from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import CONF_NAME, CONF_SLAVE +from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.helpers import config_validation as cv - -if TYPE_CHECKING: - # pylint: disable=unused-import - from pymodbus.client.sync import BaseModbusClient +from homeassistant.components.sensor import PLATFORM_SCHEMA _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] @@ -27,7 +21,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_COILS): [{ - vol.Required(CONF_HUB_NAME, default="default"): cv.string, + vol.Required(CONF_HUB_NAME, default='default'): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_SLAVE): cv.positive_int @@ -35,16 +29,18 @@ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus binary sensors.""" sensors = [] for coil in config.get(CONF_COILS): hub_name = coil.get(CONF_HUB_NAME) hub = hass.data[DOMAIN][hub_name] - sensors.append( - ModbusCoilSensor(hub, coil.get(CONF_NAME), coil.get(CONF_SLAVE), - coil.get(CONF_COIL))) - add_devices(sensors) + sensors.append(ModbusCoilSensor( + hub, + coil.get(CONF_NAME), + coil.get(CONF_SLAVE), + coil.get(CONF_COIL))) + add_entities(sensors) class ModbusCoilSensor(BinarySensorDevice): @@ -52,7 +48,7 @@ class ModbusCoilSensor(BinarySensorDevice): def __init__(self, hub, name, slave, coil): """Initialize the modbus coil sensor.""" - self._hub = hub # type: BaseModbusClient + self._hub = hub self._name = name self._slave = int(slave) if slave else None self._coil = int(coil) diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 059c6bf4a7cfce..76344caa50a763 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -10,19 +10,16 @@ """ import logging import struct -from typing import TYPE_CHECKING import voluptuous as vol -import homeassistant.helpers.config_validation as cv +from homeassistant.const import ( + CONF_NAME, CONF_SLAVE, ATTR_TEMPERATURE) from homeassistant.components.climate import ( - PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE, ClimateDevice) -from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN -from homeassistant.const import ATTR_TEMPERATURE, CONF_NAME, CONF_SLAVE + ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE) -if TYPE_CHECKING: - # pylint: disable=unused-import - from pymodbus.client.sync import BaseModbusClient +from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN +import homeassistant.helpers.config_validation as cv DEPENDENCIES = ['modbus'] @@ -38,22 +35,15 @@ DATA_TYPE_FLOAT = 'float' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HUB_NAME, default="default"): - cv.string, - vol.Required(CONF_NAME): - cv.string, - vol.Required(CONF_SLAVE): - cv.positive_int, - vol.Required(CONF_TARGET_TEMP): - cv.positive_int, - vol.Required(CONF_CURRENT_TEMP): - cv.positive_int, + vol.Required(CONF_HUB_NAME, default="default"): cv.string, + vol.Required(CONF_NAME): cv.string, + vol.Required(CONF_SLAVE): cv.positive_int, + vol.Required(CONF_TARGET_TEMP): cv.positive_int, + vol.Required(CONF_CURRENT_TEMP): cv.positive_int, vol.Optional(CONF_DATA_TYPE, default=DATA_TYPE_FLOAT): vol.In([DATA_TYPE_INT, DATA_TYPE_UINT, DATA_TYPE_FLOAT]), - vol.Optional(CONF_COUNT, default=2): - cv.positive_int, - vol.Optional(CONF_PRECISION, default=1): - cv.positive_int + vol.Optional(CONF_COUNT, default=2): cv.positive_int, + vol.Optional(CONF_PRECISION, default=1): cv.positive_int }) _LOGGER = logging.getLogger(__name__) @@ -61,7 +51,7 @@ SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus Thermostat Platform.""" name = config.get(CONF_NAME) modbus_slave = config.get(CONF_SLAVE) @@ -73,10 +63,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hub_name = config.get(CONF_HUB_NAME) hub = hass.data[DOMAIN][hub_name] - add_devices([ - ModbusThermostat(hub, name, modbus_slave, target_temp_register, - current_temp_register, data_type, count, precision) - ]) + add_entities([ModbusThermostat(hub, name, modbus_slave, + target_temp_register, current_temp_register, + data_type, count, precision)], True) class ModbusThermostat(ClimateDevice): @@ -85,7 +74,7 @@ class ModbusThermostat(ClimateDevice): def __init__(self, hub, name, modbus_slave, target_temp_register, current_temp_register, data_type, count, precision): """Initialize the unit.""" - self._hub = hub # type: BaseModbusClient + self._hub = hub self._name = name self._slave = modbus_slave self._target_temperature_register = target_temp_register @@ -97,26 +86,12 @@ def __init__(self, hub, name, modbus_slave, target_temp_register, self._precision = precision self._structure = '>f' - data_types = { - DATA_TYPE_INT: { - 1: 'h', - 2: 'i', - 4: 'q' - }, - DATA_TYPE_UINT: { - 1: 'H', - 2: 'I', - 4: 'Q' - }, - DATA_TYPE_FLOAT: { - 1: 'e', - 2: 'f', - 4: 'd' - } - } - - self._structure = '>{}'.format( - data_types[self._data_type][self._count]) + data_types = {DATA_TYPE_INT: {1: 'h', 2: 'i', 4: 'q'}, + DATA_TYPE_UINT: {1: 'H', 2: 'I', 4: 'Q'}, + DATA_TYPE_FLOAT: {1: 'e', 2: 'f', 4: 'd'}} + + self._structure = '>{}'.format(data_types[self._data_type] + [self._count]) @property def supported_features(self): diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index b5801e51376711..2fea95531206ab 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -6,100 +6,76 @@ """ import logging import struct -from typing import TYPE_CHECKING, Any import voluptuous as vol from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import (CONF_NAME, CONF_OFFSET, CONF_SLAVE, - CONF_STRUCTURE, CONF_UNIT_OF_MEASUREMENT) +from homeassistant.const import ( + CONF_NAME, CONF_OFFSET, CONF_UNIT_OF_MEASUREMENT, CONF_SLAVE, + CONF_STRUCTURE) +from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers import config_validation as cv -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.restore_state import async_get_last_state - -if TYPE_CHECKING: - # pylint: disable=unused-import - from pymodbus.client.sync import BaseModbusClient +from homeassistant.components.sensor import PLATFORM_SCHEMA _LOGGER = logging.getLogger(__name__) -DEPENDENCIES = ["modbus"] +DEPENDENCIES = ['modbus'] -CONF_COUNT = "count" -CONF_REVERSE_ORDER = "reverse_order" -CONF_PRECISION = "precision" -CONF_REGISTER = "register" -CONF_REGISTERS = "registers" -CONF_SCALE = "scale" -CONF_DATA_TYPE = "data_type" -CONF_REGISTER_TYPE = "register_type" +CONF_COUNT = 'count' +CONF_REVERSE_ORDER = 'reverse_order' +CONF_PRECISION = 'precision' +CONF_REGISTER = 'register' +CONF_REGISTERS = 'registers' +CONF_SCALE = 'scale' +CONF_DATA_TYPE = 'data_type' +CONF_REGISTER_TYPE = 'register_type' -REGISTER_TYPE_HOLDING = "holding" -REGISTER_TYPE_INPUT = "input" +REGISTER_TYPE_HOLDING = 'holding' +REGISTER_TYPE_INPUT = 'input' -DATA_TYPE_INT = "int" -DATA_TYPE_UINT = "uint" -DATA_TYPE_FLOAT = "float" -DATA_TYPE_CUSTOM = "custom" +DATA_TYPE_INT = 'int' +DATA_TYPE_UINT = 'uint' +DATA_TYPE_FLOAT = 'float' +DATA_TYPE_CUSTOM = 'custom' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_REGISTERS): [{ - vol.Required(CONF_HUB_NAME, default="default"): - cv.string, - vol.Required(CONF_NAME): - cv.string, - vol.Required(CONF_REGISTER): - cv.positive_int, + vol.Required(CONF_HUB_NAME, default='default'): cv.string, + vol.Required(CONF_NAME): cv.string, + vol.Required(CONF_REGISTER): cv.positive_int, vol.Optional(CONF_REGISTER_TYPE, default=REGISTER_TYPE_HOLDING): vol.In([REGISTER_TYPE_HOLDING, REGISTER_TYPE_INPUT]), - vol.Optional(CONF_COUNT, default=1): - cv.positive_int, - vol.Optional(CONF_REVERSE_ORDER, default=False): - cv.boolean, - vol.Optional(CONF_OFFSET, default=0): - vol.Coerce(float), - vol.Optional(CONF_PRECISION, default=0): - cv.positive_int, - vol.Optional(CONF_SCALE, default=1): - vol.Coerce(float), - vol.Optional(CONF_SLAVE): - cv.positive_int, + vol.Optional(CONF_COUNT, default=1): cv.positive_int, + vol.Optional(CONF_REVERSE_ORDER, default=False): cv.boolean, + vol.Optional(CONF_OFFSET, default=0): vol.Coerce(float), + vol.Optional(CONF_PRECISION, default=0): cv.positive_int, + vol.Optional(CONF_SCALE, default=1): vol.Coerce(float), + vol.Optional(CONF_SLAVE): 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_CUSTOM - ]), - vol.Optional(CONF_STRUCTURE): - cv.string, - vol.Optional(CONF_UNIT_OF_MEASUREMENT): - cv.string, + vol.In([DATA_TYPE_INT, DATA_TYPE_UINT, DATA_TYPE_FLOAT, + DATA_TYPE_CUSTOM]), + vol.Optional(CONF_STRUCTURE): cv.string, + vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string }] }) -def setup_platform(hass: Any, - config: dict, - add_devices: Any, - discovery_info: Any = None) -> bool: +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus sensors.""" sensors = [] - data_types = {DATA_TYPE_INT: {1: "h", 2: "i", 4: "q"}} - data_types[DATA_TYPE_UINT] = {1: "H", 2: "I", 4: "Q"} - data_types[DATA_TYPE_FLOAT] = {1: "e", 2: "f", 4: "d"} + data_types = {DATA_TYPE_INT: {1: 'h', 2: 'i', 4: 'q'}} + data_types[DATA_TYPE_UINT] = {1: 'H', 2: 'I', 4: 'Q'} + data_types[DATA_TYPE_FLOAT] = {1: 'e', 2: 'f', 4: 'd'} - for register in config.get(CONF_REGISTERS, []): - structure = ">i" + for register in config.get(CONF_REGISTERS): + structure = '>i' if register.get(CONF_DATA_TYPE) != DATA_TYPE_CUSTOM: try: - structure = ">{}".format(data_types[register.get( + structure = '>{}'.format(data_types[register.get( CONF_DATA_TYPE)][register.get(CONF_COUNT)]) except KeyError: - _LOGGER.error( - "Unable to detect data type for %s sensor, " - "try a custom type.", - register.get(CONF_NAME), - ) + _LOGGER.error("Unable to detect data type for %s sensor, " + "try a custom type.", register.get(CONF_NAME)) continue else: structure = register.get(CONF_STRUCTURE) @@ -107,51 +83,46 @@ def setup_platform(hass: Any, try: size = struct.calcsize(structure) except struct.error as err: - _LOGGER.error("Error in sensor %s structure: %s", - register.get(CONF_NAME), err) + _LOGGER.error( + "Error in sensor %s structure: %s", + register.get(CONF_NAME), err) continue if register.get(CONF_COUNT) * 2 != size: _LOGGER.error( "Structure size (%d bytes) mismatch registers count " - "(%d words)", - size, - register.get(CONF_COUNT), - ) + "(%d words)", size, register.get(CONF_COUNT)) continue hub_name = register.get(CONF_HUB_NAME) hub = hass.data[DOMAIN][hub_name] - sensors.append( - ModbusRegisterSensor( - hub, - register.get(CONF_NAME), - register.get(CONF_SLAVE), - register.get(CONF_REGISTER), - register.get(CONF_REGISTER_TYPE), - register.get(CONF_UNIT_OF_MEASUREMENT), - register.get(CONF_COUNT), - register.get(CONF_REVERSE_ORDER), - register.get(CONF_SCALE), - register.get(CONF_OFFSET), - structure, - register.get(CONF_PRECISION), - )) + sensors.append(ModbusRegisterSensor( + hub, + register.get(CONF_NAME), + register.get(CONF_SLAVE), + register.get(CONF_REGISTER), + register.get(CONF_REGISTER_TYPE), + register.get(CONF_UNIT_OF_MEASUREMENT), + register.get(CONF_COUNT), + register.get(CONF_REVERSE_ORDER), + register.get(CONF_SCALE), + register.get(CONF_OFFSET), + structure, + register.get(CONF_PRECISION))) if not sensors: return False - add_devices(sensors) - return True + add_entities(sensors) -class ModbusRegisterSensor(Entity): +class ModbusRegisterSensor(RestoreEntity): """Modbus register sensor.""" def __init__(self, hub, name, slave, register, register_type, unit_of_measurement, count, reverse_order, scale, offset, structure, precision): """Initialize the modbus register sensor.""" - self._hub = hub # type: BaseModbusClient + self._hub = hub self._name = name self._slave = int(slave) if slave else None self._register = int(register) @@ -163,38 +134,42 @@ def __init__(self, hub, name, slave, register, register_type, self._offset = offset self._precision = precision self._structure = structure - self._value: str = None + self._value = None async def async_added_to_hass(self): """Handle entity which will be added.""" - state = await async_get_last_state(self.hass, self.entity_id) + state = await self.async_get_last_state() if not state: return self._value = state.state @property - def state(self) -> str: + def state(self): """Return the state of the sensor.""" return self._value @property - def name(self) -> str: + def name(self): """Return the name of the sensor.""" return self._name @property - def unit_of_measurement(self) -> str: + def unit_of_measurement(self): """Return the unit of measurement.""" return self._unit_of_measurement - def update(self) -> None: + def update(self): """Update the state of the sensor.""" if self._register_type == REGISTER_TYPE_INPUT: result = self._hub.read_input_registers( - self._slave, self._register, self._count) + self._slave, + self._register, + self._count) else: result = self._hub.read_holding_registers( - self._slave, self._register, self._count) + self._slave, + self._register, + self._count) val = 0 try: @@ -202,14 +177,12 @@ def update(self) -> None: if self._reverse_order: registers.reverse() except AttributeError: - _LOGGER.error( - "No response from modbus slave %s, register %s", - self._slave, - self._register, - ) + _LOGGER.error("No response from modbus slave %s, register %s", + self._slave, self._register) return - byte_string = b"".join( - [x.to_bytes(2, byteorder="big") for x in registers]) + byte_string = b''.join( + [x.to_bytes(2, byteorder='big') for x in registers] + ) val = struct.unpack(self._structure, byte_string)[0] - self._value = format(self._scale * val + self._offset, - ".{}f".format(self._precision)) + self._value = format( + self._scale * val + self._offset, '.{}f'.format(self._precision)) diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index cdf038ad558fa7..32e4b851786f7c 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -5,21 +5,15 @@ https://home-assistant.io/components/switch.modbus/ """ import logging -from typing import TYPE_CHECKING - import voluptuous as vol from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import (CONF_COMMAND_OFF, CONF_COMMAND_ON, CONF_NAME, - CONF_SLAVE, STATE_ON) -from homeassistant.helpers import config_validation as cv +from homeassistant.const import ( + CONF_NAME, CONF_SLAVE, CONF_COMMAND_ON, CONF_COMMAND_OFF, STATE_ON) from homeassistant.helpers.entity import ToggleEntity -from homeassistant.helpers.restore_state import async_get_last_state - -if TYPE_CHECKING: - # pylint: disable=unused-import - from pymodbus.client.sync import BaseModbusClient +from homeassistant.helpers.restore_state import RestoreEntity +from homeassistant.helpers import config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] @@ -38,32 +32,23 @@ REGISTER_TYPE_INPUT = 'input' REGISTERS_SCHEMA = vol.Schema({ - vol.Required(CONF_HUB_NAME, default="default"): - cv.string, - vol.Required(CONF_NAME): - cv.string, - vol.Optional(CONF_SLAVE): - cv.positive_int, - vol.Required(CONF_REGISTER): - cv.positive_int, - vol.Required(CONF_COMMAND_ON): - cv.positive_int, - vol.Required(CONF_COMMAND_OFF): - cv.positive_int, - vol.Optional(CONF_VERIFY_STATE, default=True): - cv.boolean, + vol.Required(CONF_HUB_NAME, default='default'): cv.string, + vol.Required(CONF_NAME): cv.string, + vol.Optional(CONF_SLAVE): cv.positive_int, + vol.Required(CONF_REGISTER): cv.positive_int, + vol.Required(CONF_COMMAND_ON): cv.positive_int, + vol.Required(CONF_COMMAND_OFF): cv.positive_int, + vol.Optional(CONF_VERIFY_STATE, default=True): cv.boolean, vol.Optional(CONF_VERIFY_REGISTER): cv.positive_int, vol.Optional(CONF_REGISTER_TYPE, default=REGISTER_TYPE_HOLDING): vol.In([REGISTER_TYPE_HOLDING, REGISTER_TYPE_INPUT]), - vol.Optional(CONF_STATE_ON): - cv.positive_int, - vol.Optional(CONF_STATE_OFF): - cv.positive_int, + vol.Optional(CONF_STATE_ON): cv.positive_int, + vol.Optional(CONF_STATE_OFF): cv.positive_int, }) COILS_SCHEMA = vol.Schema({ - vol.Required(CONF_HUB_NAME, default="default"): cv.string, + vol.Required(CONF_HUB_NAME, default='default'): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_SLAVE): cv.positive_int, @@ -77,41 +62,44 @@ })) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Read configuration and create Modbus devices.""" switches = [] if CONF_COILS in config: for coil in config.get(CONF_COILS): hub_name = coil.get(CONF_HUB_NAME) hub = hass.data[DOMAIN][hub_name] - switches.append( - ModbusCoilSwitch(hub, coil.get(CONF_NAME), - coil.get(CONF_SLAVE), coil.get(CONF_COIL))) + switches.append(ModbusCoilSwitch( + hub, + coil.get(CONF_NAME), + coil.get(CONF_SLAVE), + coil.get(CONF_COIL))) if CONF_REGISTERS in config: for register in config.get(CONF_REGISTERS): hub_name = register.get(CONF_HUB_NAME) hub = hass.data[DOMAIN][hub_name] - switches.append( - ModbusRegisterSwitch(hub, register.get(CONF_NAME), - register.get(CONF_SLAVE), - register.get(CONF_REGISTER), - register.get(CONF_COMMAND_ON), - register.get(CONF_COMMAND_OFF), - register.get(CONF_VERIFY_STATE), - register.get(CONF_VERIFY_REGISTER), - register.get(CONF_REGISTER_TYPE), - register.get(CONF_STATE_ON), - register.get(CONF_STATE_OFF))) - add_devices(switches) - - -class ModbusCoilSwitch(ToggleEntity): + switches.append(ModbusRegisterSwitch( + hub, + register.get(CONF_NAME), + register.get(CONF_SLAVE), + register.get(CONF_REGISTER), + register.get(CONF_COMMAND_ON), + register.get(CONF_COMMAND_OFF), + register.get(CONF_VERIFY_STATE), + register.get(CONF_VERIFY_REGISTER), + register.get(CONF_REGISTER_TYPE), + register.get(CONF_STATE_ON), + register.get(CONF_STATE_OFF))) + add_entities(switches) + + +class ModbusCoilSwitch(ToggleEntity, RestoreEntity): """Representation of a Modbus coil switch.""" def __init__(self, hub, name, slave, coil): """Initialize the coil switch.""" - self._hub = hub # type: BaseModbusClient + self._hub = hub self._name = name self._slave = int(slave) if slave else None self._coil = int(coil) @@ -119,7 +107,7 @@ def __init__(self, hub, name, slave, coil): async def async_added_to_hass(self): """Handle entity which will be added.""" - state = await async_get_last_state(self.hass, self.entity_id) + state = await self.async_get_last_state() if not state: return self._is_on = state.state == STATE_ON @@ -148,27 +136,29 @@ def update(self): try: self._is_on = bool(result.bits[0]) except AttributeError: - _LOGGER.error('No response from modbus slave %s coil %s', - self._slave, self._coil) + _LOGGER.error( + 'No response from modbus slave %s coil %s', + self._slave, + self._coil) class ModbusRegisterSwitch(ModbusCoilSwitch): """Representation of a Modbus register switch.""" # pylint: disable=super-init-not-called - def __init__(self, hub, name, slave, register, command_on, command_off, - verify_state, verify_register, register_type, state_on, - state_off): + def __init__(self, hub, name, slave, register, command_on, + command_off, verify_state, verify_register, + register_type, state_on, state_off): """Initialize the register switch.""" - self._hub = hub # type: BaseModbusClient + self._hub = hub self._name = name self._slave = slave self._register = register self._command_on = command_on self._command_off = command_off self._verify_state = verify_state - self._verify_register = (verify_register - if verify_register else self._register) + self._verify_register = ( + verify_register if verify_register else self._register) self._register_type = register_type if state_on is not None: @@ -185,14 +175,19 @@ def __init__(self, hub, name, slave, register, command_on, command_off, def turn_on(self, **kwargs): """Set switch on.""" - self._hub.write_register(self._slave, self._register, self._command_on) + self._hub.write_register( + self._slave, + self._register, + self._command_on) if not self._verify_state: self._is_on = True def turn_off(self, **kwargs): """Set switch off.""" - self._hub.write_register(self._slave, self._register, - self._command_off) + self._hub.write_register( + self._slave, + self._register, + self._command_off) if not self._verify_state: self._is_on = False @@ -203,17 +198,23 @@ def update(self): value = 0 if self._register_type == REGISTER_TYPE_INPUT: - result = self._hub.read_input_registers(self._slave, - self._register, 1) + result = self._hub.read_input_registers( + self._slave, + self._register, + 1) else: - result = self._hub.read_holding_registers(self._slave, - self._register, 1) + result = self._hub.read_holding_registers( + self._slave, + self._register, + 1) try: value = int(result.registers[0]) except AttributeError: - _LOGGER.error('No response from modbus slave %s register %s', - self._slave, self._verify_register) + _LOGGER.error( + 'No response from modbus slave %s register %s', + self._slave, + self._verify_register) if value == self._state_on: self._is_on = True @@ -222,5 +223,7 @@ def update(self): else: _LOGGER.error( 'Unexpected response from modbus slave %s ' - 'register %s, got 0x%2x', self._slave, self._verify_register, + 'register %s, got 0x%2x', + self._slave, + self._verify_register, value) From 9557c5b0401dee834f6d98cc4adf4bc67aa91549 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Thu, 20 Dec 2018 01:51:57 +0100 Subject: [PATCH 10/18] Update flexit for multi-device modbus --- homeassistant/components/climate/flexit.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/climate/flexit.py b/homeassistant/components/climate/flexit.py index de74d2facb57b9..54c097aa66d7e1 100644 --- a/homeassistant/components/climate/flexit.py +++ b/homeassistant/components/climate/flexit.py @@ -20,13 +20,14 @@ from homeassistant.components.climate import ( ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE, SUPPORT_FAN_MODE) -from homeassistant.components import modbus +from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['pyflexit==0.3'] DEPENDENCIES = ['modbus'] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HUB_NAME, default="default"): cv.string, vol.Required(CONF_SLAVE): vol.All(int, vol.Range(min=0, max=32)), vol.Optional(CONF_NAME, default=DEVICE_DEFAULT_NAME): cv.string }) @@ -40,15 +41,18 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Flexit Platform.""" modbus_slave = config.get(CONF_SLAVE, None) name = config.get(CONF_NAME, None) - add_entities([Flexit(modbus_slave, name)], True) + hub_name = config.get(CONF_HUB_NAME) + hub = hass.data[DOMAIN][hub_name] + add_entities([Flexit(hub, modbus_slave, name)], True) class Flexit(ClimateDevice): """Representation of a Flexit AC unit.""" - def __init__(self, modbus_slave, name): + def __init__(self, hub, modbus_slave, name): """Initialize the unit.""" from pyflexit import pyflexit + self._hub = hub self._name = name self._slave = modbus_slave self._target_temperature = None @@ -64,7 +68,7 @@ def __init__(self, modbus_slave, name): self._heating = None self._cooling = None self._alarm = False - self.unit = pyflexit.pyflexit(modbus.HUB, modbus_slave) + self.unit = pyflexit.pyflexit(hub, modbus_slave) @property def supported_features(self): From 6daf92074071ae2bd9b172ec58b86edcc3f2a098 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Wed, 2 Jan 2019 20:29:53 +0100 Subject: [PATCH 11/18] change how hubs are referenced in the configuration --- homeassistant/components/climate/flexit.py | 9 +++++---- homeassistant/components/modbus/__init__.py | 19 ++++++++++--------- .../components/modbus/binary_sensor.py | 8 ++++---- homeassistant/components/modbus/sensor.py | 7 ++++--- homeassistant/components/modbus/switch.py | 11 ++++++----- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/climate/flexit.py b/homeassistant/components/climate/flexit.py index 54c097aa66d7e1..d47c42d419f357 100644 --- a/homeassistant/components/climate/flexit.py +++ b/homeassistant/components/climate/flexit.py @@ -20,14 +20,16 @@ from homeassistant.components.climate import ( ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE, SUPPORT_FAN_MODE) -from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN +from homeassistant.components.modbus import DOMAIN import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['pyflexit==0.3'] DEPENDENCIES = ['modbus'] +CONF_HUB = 'hub' + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HUB_NAME, default="default"): cv.string, + vol.Required(CONF_HUB, default="default"): cv.string, vol.Required(CONF_SLAVE): vol.All(int, vol.Range(min=0, max=32)), vol.Optional(CONF_NAME, default=DEVICE_DEFAULT_NAME): cv.string }) @@ -41,8 +43,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Flexit Platform.""" modbus_slave = config.get(CONF_SLAVE, None) name = config.get(CONF_NAME, None) - hub_name = config.get(CONF_HUB_NAME) - hub = hass.data[DOMAIN][hub_name] + hub = hass.data[DOMAIN][config.get(CONF_HUB)] add_entities([Flexit(hub, modbus_slave, name)], True) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index abb83ed75cc194..ed25028c9c0864 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -12,7 +12,8 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import ( EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, - CONF_HOST, CONF_METHOD, CONF_PORT, CONF_TYPE, CONF_TIMEOUT, ATTR_STATE) + CONF_HOST, CONF_METHOD, CONF_NAME, CONF_PORT, CONF_TYPE, CONF_TIMEOUT, + ATTR_STATE) DOMAIN = 'modbus' @@ -23,10 +24,9 @@ CONF_BYTESIZE = 'bytesize' CONF_STOPBITS = 'stopbits' CONF_PARITY = 'parity' -CONF_HUB_NAME = 'hub_name' BASE_SCHEMA = vol.Schema({ - vol.Optional(CONF_HUB_NAME, default='default'): cv.string + vol.Optional(CONF_NAME, default='default'): cv.string }) SERIAL_SCHEMA = BASE_SCHEMA.extend({ @@ -61,16 +61,17 @@ ATTR_ADDRESS = 'address' ATTR_UNIT = 'unit' ATTR_VALUE = 'value' +ATTR_HUB = 'hub' SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema({ - vol.Optional(CONF_HUB_NAME, default='default'): cv.string, + vol.Optional(ATTR_HUB, default='default'): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int]) }) SERVICE_WRITE_COIL_SCHEMA = vol.Schema({ - vol.Optional(CONF_HUB_NAME, default='default'): cv.string, + vol.Optional(ATTR_HUB, default='default'): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, vol.Required(ATTR_STATE): cv.boolean @@ -117,9 +118,9 @@ def setup(hass, config): for client_config in config[DOMAIN]: client = setup_client(client_config) - client_name = client_config[CONF_HUB_NAME] + client_name = client_config[CONF_NAME] hub_collect[client_name] = ModbusHub(client) - _LOGGER.debug('Setting up hub_client: %s', client_config) + _LOGGER.debug('Setting up hub: %s', client_config) def stop_modbus(event): """Stop Modbus service.""" @@ -150,7 +151,7 @@ def write_register(service): unit = int(float(service.data.get(ATTR_UNIT))) address = int(float(service.data.get(ATTR_ADDRESS))) value = service.data.get(ATTR_VALUE) - client_name = service.data.get(CONF_HUB_NAME) + client_name = service.data.get(ATTR_HUB) if isinstance(value, list): hub_collect[client_name].write_registers( unit, @@ -167,7 +168,7 @@ def write_coil(service): unit = service.data.get(ATTR_UNIT) address = service.data.get(ATTR_ADDRESS) state = service.data.get(ATTR_STATE) - client_name = service.data.get(CONF_HUB_NAME) + client_name = service.data.get(ATTR_HUB) hub_collect[client_name].write_coil(unit, address, state) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_modbus) diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index 673c6e2c54dcf5..720d52b87dd7e1 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -7,7 +7,7 @@ import logging import voluptuous as vol -from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN +from homeassistant.components.modbus import DOMAIN from homeassistant.const import CONF_NAME, CONF_SLAVE from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.helpers import config_validation as cv @@ -16,12 +16,13 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] +CONF_HUB = 'hub' CONF_COIL = 'coil' CONF_COILS = 'coils' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_COILS): [{ - vol.Required(CONF_HUB_NAME, default='default'): cv.string, + vol.Required(CONF_HUB, default='default'): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_SLAVE): cv.positive_int @@ -33,8 +34,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus binary sensors.""" sensors = [] for coil in config.get(CONF_COILS): - hub_name = coil.get(CONF_HUB_NAME) - hub = hass.data[DOMAIN][hub_name] + hub = hass.data[DOMAIN][coil.get(CONF_HUB)] sensors.append(ModbusCoilSensor( hub, coil.get(CONF_NAME), diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 2fea95531206ab..89297c98b750dc 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -9,7 +9,7 @@ import voluptuous as vol -from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN +from homeassistant.components.modbus import DOMAIN from homeassistant.const import ( CONF_NAME, CONF_OFFSET, CONF_UNIT_OF_MEASUREMENT, CONF_SLAVE, CONF_STRUCTURE) @@ -21,6 +21,7 @@ DEPENDENCIES = ['modbus'] +CONF_HUB = 'hub' CONF_COUNT = 'count' CONF_REVERSE_ORDER = 'reverse_order' CONF_PRECISION = 'precision' @@ -40,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_REGISTERS): [{ - vol.Required(CONF_HUB_NAME, default='default'): cv.string, + vol.Required(CONF_HUB, default='default'): cv.string, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_REGISTER): cv.positive_int, vol.Optional(CONF_REGISTER_TYPE, default=REGISTER_TYPE_HOLDING): @@ -94,7 +95,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): "(%d words)", size, register.get(CONF_COUNT)) continue - hub_name = register.get(CONF_HUB_NAME) + hub_name = register.get(CONF_HUB) hub = hass.data[DOMAIN][hub_name] sensors.append(ModbusRegisterSensor( hub, diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index 32e4b851786f7c..ec76f7538d2231 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -7,7 +7,7 @@ import logging import voluptuous as vol -from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN +from homeassistant.components.modbus import DOMAIN from homeassistant.const import ( CONF_NAME, CONF_SLAVE, CONF_COMMAND_ON, CONF_COMMAND_OFF, STATE_ON) from homeassistant.helpers.entity import ToggleEntity @@ -18,6 +18,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] +CONF_HUB = "hub" CONF_COIL = "coil" CONF_COILS = "coils" CONF_REGISTER = "register" @@ -32,7 +33,7 @@ REGISTER_TYPE_INPUT = 'input' REGISTERS_SCHEMA = vol.Schema({ - vol.Required(CONF_HUB_NAME, default='default'): cv.string, + vol.Required(CONF_HUB, default='default'): cv.string, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_SLAVE): cv.positive_int, vol.Required(CONF_REGISTER): cv.positive_int, @@ -48,7 +49,7 @@ }) COILS_SCHEMA = vol.Schema({ - vol.Required(CONF_HUB_NAME, default='default'): cv.string, + vol.Required(CONF_HUB, default='default'): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_SLAVE): cv.positive_int, @@ -67,7 +68,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): switches = [] if CONF_COILS in config: for coil in config.get(CONF_COILS): - hub_name = coil.get(CONF_HUB_NAME) + hub_name = coil.get(CONF_HUB) hub = hass.data[DOMAIN][hub_name] switches.append(ModbusCoilSwitch( hub, @@ -76,7 +77,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): coil.get(CONF_COIL))) if CONF_REGISTERS in config: for register in config.get(CONF_REGISTERS): - hub_name = register.get(CONF_HUB_NAME) + hub_name = register.get(CONF_HUB) hub = hass.data[DOMAIN][hub_name] switches.append(ModbusRegisterSwitch( From 1ab40a4b0349f07659e81a66f8a2df0363a42a11 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Wed, 2 Jan 2019 20:39:19 +0100 Subject: [PATCH 12/18] Also update climate/modbus.py --- homeassistant/components/modbus/climate.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 76344caa50a763..df6742395d99da 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -18,7 +18,7 @@ from homeassistant.components.climate import ( ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE) -from homeassistant.components.modbus import CONF_HUB_NAME, DOMAIN +from homeassistant.components.modbus import DOMAIN import homeassistant.helpers.config_validation as cv DEPENDENCIES = ['modbus'] @@ -29,13 +29,14 @@ CONF_DATA_TYPE = 'data_type' CONF_COUNT = 'data_count' CONF_PRECISION = 'precision' +CONF_HUB = 'hub' DATA_TYPE_INT = 'int' DATA_TYPE_UINT = 'uint' DATA_TYPE_FLOAT = 'float' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HUB_NAME, default="default"): cv.string, + vol.Required(CONF_HUB, default="default"): cv.string, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_SLAVE): cv.positive_int, vol.Required(CONF_TARGET_TEMP): cv.positive_int, @@ -60,7 +61,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): data_type = config.get(CONF_DATA_TYPE) count = config.get(CONF_COUNT) precision = config.get(CONF_PRECISION) - hub_name = config.get(CONF_HUB_NAME) + hub_name = config.get(CONF_HUB) hub = hass.data[DOMAIN][hub_name] add_entities([ModbusThermostat(hub, name, modbus_slave, From c97eaa0dc8d18dca33bf7b67c3ccf284094dc8d1 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Wed, 2 Jan 2019 20:40:20 +0100 Subject: [PATCH 13/18] Remove unwanted whitescapce --- homeassistant/components/modbus/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index ed25028c9c0864..4430ff5c4acda8 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -12,7 +12,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import ( EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, - CONF_HOST, CONF_METHOD, CONF_NAME, CONF_PORT, CONF_TYPE, CONF_TIMEOUT, + CONF_HOST, CONF_METHOD, CONF_NAME, CONF_PORT, CONF_TYPE, CONF_TIMEOUT, ATTR_STATE) DOMAIN = 'modbus' From 1f1f80befe0535244670d3b2096fc7cb113eb4f0 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Thu, 31 Jan 2019 23:01:36 +0100 Subject: [PATCH 14/18] Defined common constants centrally --- homeassistant/components/climate/flexit.py | 9 ++++----- homeassistant/components/modbus/__init__.py | 19 +++++++++---------- .../components/modbus/binary_sensor.py | 8 ++++---- homeassistant/components/modbus/climate.py | 7 +++---- homeassistant/components/modbus/sensor.py | 8 ++++---- homeassistant/components/modbus/switch.py | 8 ++++---- 6 files changed, 28 insertions(+), 31 deletions(-) diff --git a/homeassistant/components/climate/flexit.py b/homeassistant/components/climate/flexit.py index d47c42d419f357..f43588e3c9c40f 100644 --- a/homeassistant/components/climate/flexit.py +++ b/homeassistant/components/climate/flexit.py @@ -20,16 +20,15 @@ from homeassistant.components.climate import ( ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE, SUPPORT_FAN_MODE) -from homeassistant.components.modbus import DOMAIN +from homeassistant.components.modbus import ( + CONF_HUB, DEFAULT_HUB, DOMAIN as MODBUS_DOMAIN) import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['pyflexit==0.3'] DEPENDENCIES = ['modbus'] -CONF_HUB = 'hub' - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HUB, default="default"): cv.string, + vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_SLAVE): vol.All(int, vol.Range(min=0, max=32)), vol.Optional(CONF_NAME, default=DEVICE_DEFAULT_NAME): cv.string }) @@ -43,7 +42,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Flexit Platform.""" modbus_slave = config.get(CONF_SLAVE, None) name = config.get(CONF_NAME, None) - hub = hass.data[DOMAIN][config.get(CONF_HUB)] + hub = hass.data[MODBUS_DOMAIN][config.get(CONF_HUB)] add_entities([Flexit(hub, modbus_slave, name)], True) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 4430ff5c4acda8..d95f166e559fd0 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -19,14 +19,17 @@ REQUIREMENTS = ['pymodbus==1.5.2'] +CONF_HUB = 'hub' # Type of network CONF_BAUDRATE = 'baudrate' CONF_BYTESIZE = 'bytesize' CONF_STOPBITS = 'stopbits' CONF_PARITY = 'parity' +DEFAULT_HUB = 'default' + BASE_SCHEMA = vol.Schema({ - vol.Optional(CONF_NAME, default='default'): cv.string + vol.Optional(CONF_NAME, default=DEFAULT_HUB): cv.string }) SERIAL_SCHEMA = BASE_SCHEMA.extend({ @@ -59,19 +62,19 @@ SERVICE_WRITE_COIL = 'write_coil' ATTR_ADDRESS = 'address' +ATTR_HUB = 'hub' ATTR_UNIT = 'unit' ATTR_VALUE = 'value' -ATTR_HUB = 'hub' SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema({ - vol.Optional(ATTR_HUB, default='default'): cv.string, + vol.Optional(ATTR_HUB, DEFAULT_HUB): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int]) }) SERVICE_WRITE_COIL_SCHEMA = vol.Schema({ - vol.Optional(ATTR_HUB, default='default'): cv.string, + vol.Optional(ATTR_HUB, DEFAULT_HUB): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, vol.Required(ATTR_STATE): cv.boolean @@ -136,14 +139,10 @@ def start_modbus(event): # Register services for modbus hass.services.register( - DOMAIN, - SERVICE_WRITE_REGISTER, - write_register, + DOMAIN, SERVICE_WRITE_REGISTER, write_register, schema=SERVICE_WRITE_REGISTER_SCHEMA) hass.services.register( - DOMAIN, - SERVICE_WRITE_COIL, - write_coil, + DOMAIN, SERVICE_WRITE_COIL, write_coil, schema=SERVICE_WRITE_COIL_SCHEMA) def write_register(service): diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index 720d52b87dd7e1..12c10e71b30fc0 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -7,7 +7,8 @@ import logging import voluptuous as vol -from homeassistant.components.modbus import DOMAIN +from homeassistant.components.modbus import ( + CONF_HUB, DEFAULT_HUB, DOMAIN as MODBUS_DOMAIN) from homeassistant.const import CONF_NAME, CONF_SLAVE from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.helpers import config_validation as cv @@ -16,13 +17,12 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] -CONF_HUB = 'hub' CONF_COIL = 'coil' CONF_COILS = 'coils' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_COILS): [{ - vol.Required(CONF_HUB, default='default'): cv.string, + vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_SLAVE): cv.positive_int @@ -34,7 +34,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus binary sensors.""" sensors = [] for coil in config.get(CONF_COILS): - hub = hass.data[DOMAIN][coil.get(CONF_HUB)] + hub = hass.data[MODBUS_DOMAIN][coil.get(CONF_HUB)] sensors.append(ModbusCoilSensor( hub, coil.get(CONF_NAME), diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index df6742395d99da..787a6c605b7d57 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -17,8 +17,8 @@ CONF_NAME, CONF_SLAVE, ATTR_TEMPERATURE) from homeassistant.components.climate import ( ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE) - -from homeassistant.components.modbus import DOMAIN +from homeassistant.components.modbus import ( + CONF_HUB, DEFAULT_HUB, DOMAIN as MODBUS_DOMAIN) import homeassistant.helpers.config_validation as cv DEPENDENCIES = ['modbus'] @@ -29,14 +29,13 @@ CONF_DATA_TYPE = 'data_type' CONF_COUNT = 'data_count' CONF_PRECISION = 'precision' -CONF_HUB = 'hub' DATA_TYPE_INT = 'int' DATA_TYPE_UINT = 'uint' DATA_TYPE_FLOAT = 'float' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HUB, default="default"): cv.string, + vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_SLAVE): cv.positive_int, vol.Required(CONF_TARGET_TEMP): cv.positive_int, diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 89297c98b750dc..93d25138923995 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -9,7 +9,8 @@ import voluptuous as vol -from homeassistant.components.modbus import DOMAIN +from homeassistant.components.modbus import ( + CONF_HUB, DEFAULT_HUB, DOMAIN as MODBUS_DOMAIN) from homeassistant.const import ( CONF_NAME, CONF_OFFSET, CONF_UNIT_OF_MEASUREMENT, CONF_SLAVE, CONF_STRUCTURE) @@ -21,7 +22,6 @@ DEPENDENCIES = ['modbus'] -CONF_HUB = 'hub' CONF_COUNT = 'count' CONF_REVERSE_ORDER = 'reverse_order' CONF_PRECISION = 'precision' @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_REGISTERS): [{ - vol.Required(CONF_HUB, default='default'): cv.string, + vol.Required(CONF_HUB, DEFAULT_HUB): cv.string, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_REGISTER): cv.positive_int, vol.Optional(CONF_REGISTER_TYPE, default=REGISTER_TYPE_HOLDING): @@ -96,7 +96,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): continue hub_name = register.get(CONF_HUB) - hub = hass.data[DOMAIN][hub_name] + hub = hass.data[MODBUS_DOMAIN][hub_name] sensors.append(ModbusRegisterSensor( hub, register.get(CONF_NAME), diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index ec76f7538d2231..5bb9d72fd78d48 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -7,7 +7,8 @@ import logging import voluptuous as vol -from homeassistant.components.modbus import DOMAIN +from homeassistant.components.modbus import ( + CONF_HUB, DEFAULT_HUB, DOMAIN as MODBUS_DOMAIN) from homeassistant.const import ( CONF_NAME, CONF_SLAVE, CONF_COMMAND_ON, CONF_COMMAND_OFF, STATE_ON) from homeassistant.helpers.entity import ToggleEntity @@ -18,7 +19,6 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] -CONF_HUB = "hub" CONF_COIL = "coil" CONF_COILS = "coils" CONF_REGISTER = "register" @@ -33,7 +33,7 @@ REGISTER_TYPE_INPUT = 'input' REGISTERS_SCHEMA = vol.Schema({ - vol.Required(CONF_HUB, default='default'): cv.string, + vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_SLAVE): cv.positive_int, vol.Required(CONF_REGISTER): cv.positive_int, @@ -49,7 +49,7 @@ }) COILS_SCHEMA = vol.Schema({ - vol.Required(CONF_HUB, default='default'): cv.string, + vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_SLAVE): cv.positive_int, From 906433dc722a9d74db796994e5b40412cef8ee92 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Thu, 31 Jan 2019 23:37:09 +0100 Subject: [PATCH 15/18] Update DOMAIN in climate and switch components --- homeassistant/components/modbus/climate.py | 2 +- homeassistant/components/modbus/switch.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 787a6c605b7d57..7965e565eb41d5 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -61,7 +61,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): count = config.get(CONF_COUNT) precision = config.get(CONF_PRECISION) hub_name = config.get(CONF_HUB) - hub = hass.data[DOMAIN][hub_name] + hub = hass.data[MODBUS_DOMAIN][hub_name] add_entities([ModbusThermostat(hub, name, modbus_slave, target_temp_register, current_temp_register, diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index 5bb9d72fd78d48..3e29209057202d 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -69,7 +69,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): if CONF_COILS in config: for coil in config.get(CONF_COILS): hub_name = coil.get(CONF_HUB) - hub = hass.data[DOMAIN][hub_name] + hub = hass.data[MODBUS_DOMAIN][hub_name] switches.append(ModbusCoilSwitch( hub, coil.get(CONF_NAME), @@ -78,7 +78,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): if CONF_REGISTERS in config: for register in config.get(CONF_REGISTERS): hub_name = register.get(CONF_HUB) - hub = hass.data[DOMAIN][hub_name] + hub = hass.data[MODBUS_DOMAIN][hub_name] switches.append(ModbusRegisterSwitch( hub, From 73170d042f668c967afc30b95085d9d198aa0731 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Thu, 31 Jan 2019 23:48:48 +0100 Subject: [PATCH 16/18] Removed unnecessary vol.schema --- homeassistant/components/modbus/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index d95f166e559fd0..6c8d9a98878d23 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -51,9 +51,7 @@ }) CONFIG_SCHEMA = vol.Schema({ - DOMAIN: - vol.All(cv.ensure_list, - vol.Schema([vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA)])) + DOMAIN: vol.All(cv.ensure_list, [vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA)]) }, extra=vol.ALLOW_EXTRA,) _LOGGER = logging.getLogger(__name__) From 9bec1d1f4c1667928d51ccd009f599737e18b976 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Fri, 1 Feb 2019 20:34:08 +0100 Subject: [PATCH 17/18] Make hub name optional --- homeassistant/components/climate/flexit.py | 2 +- homeassistant/components/modbus/__init__.py | 4 ++-- homeassistant/components/modbus/binary_sensor.py | 2 +- homeassistant/components/modbus/climate.py | 2 +- homeassistant/components/modbus/sensor.py | 2 +- homeassistant/components/modbus/switch.py | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/climate/flexit.py b/homeassistant/components/climate/flexit.py index f43588e3c9c40f..e0453b8bf90fa4 100644 --- a/homeassistant/components/climate/flexit.py +++ b/homeassistant/components/climate/flexit.py @@ -28,7 +28,7 @@ DEPENDENCIES = ['modbus'] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, + vol.Optional(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_SLAVE): vol.All(int, vol.Range(min=0, max=32)), vol.Optional(CONF_NAME, default=DEVICE_DEFAULT_NAME): cv.string }) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 6c8d9a98878d23..9fa82dc007583c 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -65,14 +65,14 @@ ATTR_VALUE = 'value' SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema({ - vol.Optional(ATTR_HUB, DEFAULT_HUB): cv.string, + vol.Optional(ATTR_HUB, default=DEFAULT_HUB): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int]) }) SERVICE_WRITE_COIL_SCHEMA = vol.Schema({ - vol.Optional(ATTR_HUB, DEFAULT_HUB): cv.string, + vol.Optional(ATTR_HUB, default=DEFAULT_HUB): cv.string, vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, vol.Required(ATTR_STATE): cv.boolean diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index 12c10e71b30fc0..832ef8e84c395e 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -22,7 +22,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_COILS): [{ - vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, + vol.Optional(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_SLAVE): cv.positive_int diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 7965e565eb41d5..23051898679202 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -35,7 +35,7 @@ DATA_TYPE_FLOAT = 'float' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, + vol.Optional(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_SLAVE): cv.positive_int, vol.Required(CONF_TARGET_TEMP): cv.positive_int, diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 93d25138923995..e7187001c3a117 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_REGISTERS): [{ - vol.Required(CONF_HUB, DEFAULT_HUB): cv.string, + vol.Optional(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_REGISTER): cv.positive_int, vol.Optional(CONF_REGISTER_TYPE, default=REGISTER_TYPE_HOLDING): diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index 3e29209057202d..1084bdba0ab1f3 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -33,7 +33,7 @@ REGISTER_TYPE_INPUT = 'input' REGISTERS_SCHEMA = vol.Schema({ - vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, + vol.Optional(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_SLAVE): cv.positive_int, vol.Required(CONF_REGISTER): cv.positive_int, @@ -49,7 +49,7 @@ }) COILS_SCHEMA = vol.Schema({ - vol.Required(CONF_HUB, default=DEFAULT_HUB): cv.string, + vol.Optional(CONF_HUB, default=DEFAULT_HUB): cv.string, vol.Required(CONF_COIL): cv.positive_int, vol.Required(CONF_NAME): cv.string, vol.Required(CONF_SLAVE): cv.positive_int, From 60175a9dc37487267a68fdc54ad53b3d2a09ffb5 Mon Sep 17 00:00:00 2001 From: Ben Van Mechelen Date: Wed, 6 Feb 2019 16:54:48 +0100 Subject: [PATCH 18/18] Add name property to ModbusHub --- homeassistant/components/modbus/__init__.py | 12 +++++++++--- homeassistant/components/modbus/binary_sensor.py | 4 ++-- homeassistant/components/modbus/sensor.py | 4 ++-- homeassistant/components/modbus/switch.py | 9 ++++++--- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 9fa82dc007583c..77a62103f80b10 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -119,8 +119,8 @@ def setup(hass, config): for client_config in config[DOMAIN]: client = setup_client(client_config) - client_name = client_config[CONF_NAME] - hub_collect[client_name] = ModbusHub(client) + name = client_config[CONF_NAME] + hub_collect[name] = ModbusHub(client, name) _LOGGER.debug('Setting up hub: %s', client_config) def stop_modbus(event): @@ -176,10 +176,16 @@ def write_coil(service): class ModbusHub: """Thread safe wrapper class for pymodbus.""" - def __init__(self, modbus_client): + def __init__(self, modbus_client, name): """Initialize the modbus hub.""" self._client = modbus_client self._lock = threading.Lock() + self._name = name + + @property + def name(self): + """Return the name of this hub.""" + return self._name def close(self): """Disconnect client.""" diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index 832ef8e84c395e..7089439a7e18ce 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -70,5 +70,5 @@ def update(self): try: self._value = result.bits[0] except AttributeError: - _LOGGER.error('No response from modbus slave %s coil %s', - self._slave, self._coil) + _LOGGER.error('No response from hub %s, slave %s, coil %s', + self._hub.name, self._slave, self._coil) diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index e7187001c3a117..b263bad5318b21 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -178,8 +178,8 @@ def update(self): if self._reverse_order: registers.reverse() except AttributeError: - _LOGGER.error("No response from modbus slave %s, register %s", - self._slave, self._register) + _LOGGER.error("No response from hub %s, slave %s, register %s", + self._hub.name, self._slave, self._register) return byte_string = b''.join( [x.to_bytes(2, byteorder='big') for x in registers] diff --git a/homeassistant/components/modbus/switch.py b/homeassistant/components/modbus/switch.py index 1084bdba0ab1f3..04c73d7d3721d3 100644 --- a/homeassistant/components/modbus/switch.py +++ b/homeassistant/components/modbus/switch.py @@ -138,7 +138,8 @@ def update(self): self._is_on = bool(result.bits[0]) except AttributeError: _LOGGER.error( - 'No response from modbus slave %s coil %s', + 'No response from hub %s, slave %s, coil %s', + self._hub.name, self._slave, self._coil) @@ -213,7 +214,8 @@ def update(self): value = int(result.registers[0]) except AttributeError: _LOGGER.error( - 'No response from modbus slave %s register %s', + 'No response from hub %s, slave %s, register %s', + self._hub.name, self._slave, self._verify_register) @@ -223,8 +225,9 @@ def update(self): self._is_on = False else: _LOGGER.error( - 'Unexpected response from modbus slave %s ' + 'Unexpected response from hub %s, slave %s ' 'register %s, got 0x%2x', + self._hub.name, self._slave, self._verify_register, value)