Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[WIP]Support for Multi modbus hub #17901

Closed
wants to merge 10 commits into from
37 changes: 22 additions & 15 deletions homeassistant/components/binary_sensor/modbus.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@
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.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, 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']
Expand All @@ -21,29 +27,32 @@

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
}]
})


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):
sensors.append(ModbusCoilSensor(
coil.get(CONF_NAME),
coil.get(CONF_SLAVE),
coil.get(CONF_COIL)))
add_entities(sensors)
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)


class ModbusCoilSensor(BinarySensorDevice):
"""Modbus coil sensor."""

def __init__(self, name, slave, coil):
def __init__(self, hub, name, slave, coil):
"""Initialize the modbus coil sensor."""
self._hub = hub # type: BaseModbusClient
self._name = name
self._slave = int(slave) if slave else None
self._coil = int(coil)
Expand All @@ -61,11 +70,9 @@ def is_on(self):

def update(self):
"""Update the state of the sensor."""
result = modbus.HUB.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:
_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)
79 changes: 54 additions & 25 deletions homeassistant/components/climate/modbus.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@
"""
import logging
import struct
from typing import TYPE_CHECKING

import voluptuous as vol

from homeassistant.const import (
CONF_NAME, CONF_SLAVE, ATTR_TEMPERATURE)
import homeassistant.helpers.config_validation as cv
from homeassistant.components.climate import (
ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE)
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

from homeassistant.components import modbus
import homeassistant.helpers.config_validation as cv
if TYPE_CHECKING:
# pylint: disable=unused-import
from pymodbus.client.sync import BaseModbusClient

DEPENDENCIES = ['modbus']

Expand All @@ -35,22 +38,30 @@
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__)

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)
Expand All @@ -59,18 +70,22 @@ 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 = hass.data[DOMAIN][hub_name]

add_entities([ModbusThermostat(name, modbus_slave,
target_temp_register, current_temp_register,
data_type, count, precision)], True)
add_devices([
ModbusThermostat(hub, name, modbus_slave, target_temp_register,
current_temp_register, data_type, count, precision)
])


class ModbusThermostat(ClimateDevice):
"""Representation of a Modbus Thermostat."""

def __init__(self, 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 = hub # type: BaseModbusClient
self._name = name
self._slave = modbus_slave
self._target_temperature_register = target_temp_register
Expand All @@ -82,12 +97,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):
Expand Down Expand Up @@ -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._hub.read_holding_registers(self._slave, register,
self._count)
except AttributeError as ex:
_LOGGER.error(ex)
byte_string = b''.join(
Expand All @@ -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._hub.write_registers(self._slave, register, [value, 0])
Loading