mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 22:27:07 +00:00
Modbus component refactoring - sensors and switches (#3297)
This commit is contained in:
parent
e4f4e91096
commit
ca646c08c2
61
homeassistant/components/binary_sensor/modbus.py
Normal file
61
homeassistant/components/binary_sensor/modbus.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"""
|
||||||
|
Support for Modbus Coil sensors.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/binary_sensor.modbus/
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
import homeassistant.components.modbus as modbus
|
||||||
|
from homeassistant.const import CONF_NAME
|
||||||
|
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
DEPENDENCIES = ['modbus']
|
||||||
|
|
||||||
|
CONF_COIL = "coil"
|
||||||
|
CONF_COILS = "coils"
|
||||||
|
CONF_SLAVE = "slave"
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
|
vol.Required(CONF_COILS): [{
|
||||||
|
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_devices, discovery_info=None):
|
||||||
|
"""Setup 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_devices(sensors)
|
||||||
|
|
||||||
|
|
||||||
|
class ModbusCoilSensor(BinarySensorDevice):
|
||||||
|
"""Modbus coil sensor."""
|
||||||
|
|
||||||
|
def __init__(self, name, slave, coil):
|
||||||
|
"""Initialize the modbus coil sensor."""
|
||||||
|
self._name = name
|
||||||
|
self._slave = int(slave) if slave else None
|
||||||
|
self._coil = int(coil)
|
||||||
|
self._value = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Return the state of the sensor."""
|
||||||
|
return self._value
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Update the state of the sensor."""
|
||||||
|
result = modbus.HUB.read_coils(self._slave, self._coil, 1)
|
||||||
|
self._value = result.bits[0]
|
@ -7,8 +7,12 @@ https://home-assistant.io/components/modbus/
|
|||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
|
||||||
|
CONF_HOST, CONF_METHOD, CONF_PORT)
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
DOMAIN = "modbus"
|
DOMAIN = "modbus"
|
||||||
|
|
||||||
@ -16,19 +20,33 @@ REQUIREMENTS = ['https://github.com/bashwork/pymodbus/archive/'
|
|||||||
'd7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0']
|
'd7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0']
|
||||||
|
|
||||||
# Type of network
|
# Type of network
|
||||||
MEDIUM = "type"
|
CONF_BAUDRATE = "baudrate"
|
||||||
|
CONF_BYTESIZE = "bytesize"
|
||||||
|
CONF_STOPBITS = "stopbits"
|
||||||
|
CONF_TYPE = "type"
|
||||||
|
CONF_PARITY = "parity"
|
||||||
|
|
||||||
# if MEDIUM == "serial"
|
SERIAL_SCHEMA = {
|
||||||
METHOD = "method"
|
vol.Required(CONF_BAUDRATE): cv.positive_int,
|
||||||
SERIAL_PORT = "port"
|
vol.Required(CONF_BYTESIZE): vol.Any(5, 6, 7, 8),
|
||||||
BAUDRATE = "baudrate"
|
vol.Required(CONF_METHOD): vol.Any('rtu', 'ascii'),
|
||||||
STOPBITS = "stopbits"
|
vol.Required(CONF_PORT): cv.string,
|
||||||
BYTESIZE = "bytesize"
|
vol.Required(CONF_PARITY): vol.Any('E', 'O', 'N'),
|
||||||
PARITY = "parity"
|
vol.Required(CONF_STOPBITS): vol.Any(1, 2),
|
||||||
|
vol.Required(CONF_TYPE): 'serial',
|
||||||
|
}
|
||||||
|
|
||||||
|
ETHERNET_SCHEMA = {
|
||||||
|
vol.Required(CONF_HOST): cv.string,
|
||||||
|
vol.Required(CONF_PORT): cv.positive_int,
|
||||||
|
vol.Required(CONF_TYPE): vol.Any('tcp', 'udp'),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
|
DOMAIN: vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA)
|
||||||
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
# if MEDIUM == "tcp" or "udp"
|
|
||||||
HOST = "host"
|
|
||||||
IP_PORT = "port"
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -38,36 +56,41 @@ ATTR_ADDRESS = "address"
|
|||||||
ATTR_UNIT = "unit"
|
ATTR_UNIT = "unit"
|
||||||
ATTR_VALUE = "value"
|
ATTR_VALUE = "value"
|
||||||
|
|
||||||
|
SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema({
|
||||||
|
vol.Required(ATTR_UNIT): cv.positive_int,
|
||||||
|
vol.Required(ATTR_ADDRESS): cv.positive_int,
|
||||||
|
vol.Required(ATTR_VALUE): cv.positive_int
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
HUB = None
|
HUB = None
|
||||||
TYPE = None
|
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Setup Modbus component."""
|
"""Setup Modbus component."""
|
||||||
# Modbus connection type
|
# Modbus connection type
|
||||||
# pylint: disable=global-statement, import-error
|
# pylint: disable=global-statement, import-error
|
||||||
global TYPE
|
client_type = config[DOMAIN][CONF_TYPE]
|
||||||
TYPE = config[DOMAIN][MEDIUM]
|
|
||||||
|
|
||||||
# Connect to Modbus network
|
# Connect to Modbus network
|
||||||
# pylint: disable=global-statement, import-error
|
# pylint: disable=global-statement, import-error
|
||||||
|
|
||||||
if TYPE == "serial":
|
if client_type == "serial":
|
||||||
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
|
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
|
||||||
client = ModbusClient(method=config[DOMAIN][METHOD],
|
client = ModbusClient(method=config[DOMAIN][CONF_METHOD],
|
||||||
port=config[DOMAIN][SERIAL_PORT],
|
port=config[DOMAIN][CONF_PORT],
|
||||||
baudrate=config[DOMAIN][BAUDRATE],
|
baudrate=config[DOMAIN][CONF_BAUDRATE],
|
||||||
stopbits=config[DOMAIN][STOPBITS],
|
stopbits=config[DOMAIN][CONF_STOPBITS],
|
||||||
bytesize=config[DOMAIN][BYTESIZE],
|
bytesize=config[DOMAIN][CONF_BYTESIZE],
|
||||||
parity=config[DOMAIN][PARITY])
|
parity=config[DOMAIN][CONF_PARITY])
|
||||||
elif TYPE == "tcp":
|
elif client_type == "tcp":
|
||||||
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
|
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
|
||||||
client = ModbusClient(host=config[DOMAIN][HOST],
|
client = ModbusClient(host=config[DOMAIN][CONF_HOST],
|
||||||
port=config[DOMAIN][IP_PORT])
|
port=config[DOMAIN][CONF_PORT])
|
||||||
elif TYPE == "udp":
|
elif client_type == "udp":
|
||||||
from pymodbus.client.sync import ModbusUdpClient as ModbusClient
|
from pymodbus.client.sync import ModbusUdpClient as ModbusClient
|
||||||
client = ModbusClient(host=config[DOMAIN][HOST],
|
client = ModbusClient(host=config[DOMAIN][CONF_HOST],
|
||||||
port=config[DOMAIN][IP_PORT])
|
port=config[DOMAIN][CONF_PORT])
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -84,7 +107,8 @@ def setup(hass, config):
|
|||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_modbus)
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_modbus)
|
||||||
|
|
||||||
# Register services for modbus
|
# Register services for modbus
|
||||||
hass.services.register(DOMAIN, SERVICE_WRITE_REGISTER, write_register)
|
hass.services.register(DOMAIN, SERVICE_WRITE_REGISTER, write_register,
|
||||||
|
schema=SERVICE_WRITE_REGISTER_SCHEMA)
|
||||||
|
|
||||||
def write_register(service):
|
def write_register(service):
|
||||||
"""Write modbus registers."""
|
"""Write modbus registers."""
|
||||||
@ -128,39 +152,44 @@ class ModbusHub(object):
|
|||||||
def read_coils(self, unit, address, count):
|
def read_coils(self, unit, address, count):
|
||||||
"""Read coils."""
|
"""Read coils."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
|
kwargs = {'unit': unit} if unit else {}
|
||||||
return self._client.read_coils(
|
return self._client.read_coils(
|
||||||
address,
|
address,
|
||||||
count,
|
count,
|
||||||
unit=unit)
|
**kwargs)
|
||||||
|
|
||||||
def read_holding_registers(self, unit, address, count):
|
def read_holding_registers(self, unit, address, count):
|
||||||
"""Read holding registers."""
|
"""Read holding registers."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
|
kwargs = {'unit': unit} if unit else {}
|
||||||
return self._client.read_holding_registers(
|
return self._client.read_holding_registers(
|
||||||
address,
|
address,
|
||||||
count,
|
count,
|
||||||
unit=unit)
|
**kwargs)
|
||||||
|
|
||||||
def write_coil(self, unit, address, value):
|
def write_coil(self, unit, address, value):
|
||||||
"""Write coil."""
|
"""Write coil."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
|
kwargs = {'unit': unit} if unit else {}
|
||||||
self._client.write_coil(
|
self._client.write_coil(
|
||||||
address,
|
address,
|
||||||
value,
|
value,
|
||||||
unit=unit)
|
**kwargs)
|
||||||
|
|
||||||
def write_register(self, unit, address, value):
|
def write_register(self, unit, address, value):
|
||||||
"""Write register."""
|
"""Write register."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
|
kwargs = {'unit': unit} if unit else {}
|
||||||
self._client.write_register(
|
self._client.write_register(
|
||||||
address,
|
address,
|
||||||
value,
|
value,
|
||||||
unit=unit)
|
**kwargs)
|
||||||
|
|
||||||
def write_registers(self, unit, address, values):
|
def write_registers(self, unit, address, values):
|
||||||
"""Write registers."""
|
"""Write registers."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
|
kwargs = {'unit': unit} if unit else {}
|
||||||
self._client.write_registers(
|
self._client.write_registers(
|
||||||
address,
|
address,
|
||||||
values,
|
values,
|
||||||
unit=unit)
|
**kwargs)
|
||||||
|
@ -1,100 +1,80 @@
|
|||||||
"""
|
"""
|
||||||
Support for Modbus sensors.
|
Support for Modbus Register sensors.
|
||||||
|
|
||||||
For more details about this platform, please refer to the documentation at
|
For more details about this platform, please refer to the documentation at
|
||||||
https://home-assistant.io/components/sensor.modbus/
|
https://home-assistant.io/components/sensor.modbus/
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
import homeassistant.components.modbus as modbus
|
import homeassistant.components.modbus as modbus
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_OFF, STATE_ON, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
CONF_NAME, CONF_OFFSET, CONF_UNIT_OF_MEASUREMENT)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
DEPENDENCIES = ['modbus']
|
DEPENDENCIES = ['modbus']
|
||||||
|
|
||||||
|
CONF_COUNT = "count"
|
||||||
|
CONF_PRECISION = "precision"
|
||||||
|
CONF_REGISTER = "register"
|
||||||
|
CONF_REGISTERS = "registers"
|
||||||
|
CONF_SCALE = "scale"
|
||||||
|
CONF_SLAVE = "slave"
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
|
vol.Required(CONF_REGISTERS): [{
|
||||||
|
vol.Required(CONF_NAME): cv.string,
|
||||||
|
vol.Required(CONF_REGISTER): cv.positive_int,
|
||||||
|
vol.Optional(CONF_COUNT, default=1): cv.positive_int,
|
||||||
|
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_UNIT_OF_MEASUREMENT): cv.string
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
"""Setup Modbus devices."""
|
"""Setup Modbus sensors."""
|
||||||
sensors = []
|
sensors = []
|
||||||
slave = config.get("slave", None)
|
for register in config.get(CONF_REGISTERS):
|
||||||
if modbus.TYPE == "serial" and not slave:
|
sensors.append(ModbusRegisterSensor(
|
||||||
_LOGGER.error("No slave number provided for serial Modbus")
|
register.get(CONF_NAME),
|
||||||
return False
|
register.get(CONF_SLAVE),
|
||||||
registers = config.get("registers")
|
register.get(CONF_REGISTER),
|
||||||
if registers:
|
register.get(CONF_UNIT_OF_MEASUREMENT),
|
||||||
for regnum, register in registers.items():
|
register.get(CONF_COUNT),
|
||||||
if register.get("name"):
|
register.get(CONF_SCALE),
|
||||||
sensors.append(
|
register.get(CONF_OFFSET),
|
||||||
ModbusSensor(register.get("name"),
|
register.get(CONF_PRECISION)))
|
||||||
slave,
|
|
||||||
regnum,
|
|
||||||
None,
|
|
||||||
register.get("unit"),
|
|
||||||
scale=register.get("scale", 1),
|
|
||||||
offset=register.get("offset", 0),
|
|
||||||
precision=register.get("precision", 0)))
|
|
||||||
if register.get("bits"):
|
|
||||||
bits = register.get("bits")
|
|
||||||
for bitnum, bit in bits.items():
|
|
||||||
if bit.get("name"):
|
|
||||||
sensors.append(ModbusSensor(bit.get("name"),
|
|
||||||
slave,
|
|
||||||
regnum,
|
|
||||||
bitnum))
|
|
||||||
coils = config.get("coils")
|
|
||||||
if coils:
|
|
||||||
for coilnum, coil in coils.items():
|
|
||||||
sensors.append(ModbusSensor(coil.get("name"),
|
|
||||||
slave,
|
|
||||||
coilnum,
|
|
||||||
coil=True))
|
|
||||||
|
|
||||||
add_devices(sensors)
|
add_devices(sensors)
|
||||||
|
|
||||||
|
|
||||||
class ModbusSensor(Entity):
|
class ModbusRegisterSensor(Entity):
|
||||||
"""Representation of a Modbus Sensor."""
|
"""Modbus resgister sensor."""
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments, too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes, too-many-arguments
|
||||||
def __init__(self, name, slave, register, bit=None, unit=None, coil=False,
|
def __init__(self, name, slave, register, unit_of_measurement, count,
|
||||||
scale=1, offset=0, precision=0):
|
scale, offset, precision):
|
||||||
"""Initialize the sensor."""
|
"""Initialize the modbus register sensor."""
|
||||||
self._name = name
|
self._name = name
|
||||||
self.slave = int(slave) if slave else 1
|
self._slave = int(slave) if slave else None
|
||||||
self.register = int(register)
|
self._register = int(register)
|
||||||
self.bit = int(bit) if bit else None
|
self._unit_of_measurement = unit_of_measurement
|
||||||
self._value = None
|
self._count = int(count)
|
||||||
self._unit = unit
|
|
||||||
self._coil = coil
|
|
||||||
self._scale = scale
|
self._scale = scale
|
||||||
self._offset = offset
|
self._offset = offset
|
||||||
self._precision = precision
|
self._precision = precision
|
||||||
|
self._value = None
|
||||||
def __str__(self):
|
|
||||||
"""Return the name and the state of the sensor."""
|
|
||||||
return "%s: %s" % (self.name, self.state)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""Polling needed."""
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self):
|
|
||||||
"""Return a unique id."""
|
|
||||||
return "MODBUS-SENSOR-{}-{}-{}".format(self.slave,
|
|
||||||
self.register,
|
|
||||||
self.bit)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state of the sensor."""
|
"""Return the state of the sensor."""
|
||||||
if self.bit:
|
return self._value
|
||||||
return STATE_ON if self._value else STATE_OFF
|
|
||||||
else:
|
|
||||||
return self._value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -103,28 +83,18 @@ class ModbusSensor(Entity):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
"""Return the unit of measurement of this entity, if any."""
|
"""Return the unit of measurement."""
|
||||||
if self._unit == "C":
|
return self._unit_of_measurement
|
||||||
return TEMP_CELSIUS
|
|
||||||
elif self._unit == "F":
|
|
||||||
return TEMP_FAHRENHEIT
|
|
||||||
else:
|
|
||||||
return self._unit
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update the state of the sensor."""
|
"""Update the state of the sensor."""
|
||||||
if self._coil:
|
result = modbus.HUB.read_holding_registers(
|
||||||
result = modbus.HUB.read_coils(self.slave, self.register, 1)
|
self._slave,
|
||||||
self._value = result.bits[0]
|
self._register,
|
||||||
else:
|
self._count)
|
||||||
result = modbus.HUB.read_holding_registers(
|
val = 0
|
||||||
self.slave, self.register, 1)
|
for i, res in enumerate(result.registers):
|
||||||
val = 0
|
val += res * (2**(i*16))
|
||||||
for i, res in enumerate(result.registers):
|
self._value = format(
|
||||||
val += res * (2**(i*16))
|
self._scale * val + self._offset,
|
||||||
if self.bit:
|
".{}f".format(self._precision))
|
||||||
self._value = val & (0x0001 << self.bit)
|
|
||||||
else:
|
|
||||||
self._value = format(
|
|
||||||
self._scale * val + self._offset,
|
|
||||||
".{}f".format(self._precision))
|
|
||||||
|
@ -5,74 +5,51 @@ For more details about this platform, please refer to the documentation at
|
|||||||
https://home-assistant.io/components/switch.modbus/
|
https://home-assistant.io/components/switch.modbus/
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
import homeassistant.components.modbus as modbus
|
import homeassistant.components.modbus as modbus
|
||||||
|
from homeassistant.const import CONF_NAME
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.helpers.entity import ToggleEntity
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
DEPENDENCIES = ['modbus']
|
DEPENDENCIES = ['modbus']
|
||||||
|
|
||||||
|
CONF_COIL = "coil"
|
||||||
|
CONF_COILS = "coils"
|
||||||
|
CONF_SLAVE = "slave"
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
|
vol.Required(CONF_COILS): [{
|
||||||
|
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_devices, discovery_info=None):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
"""Read configuration and create Modbus devices."""
|
"""Read configuration and create Modbus devices."""
|
||||||
switches = []
|
switches = []
|
||||||
slave = config.get("slave", None)
|
for coil in config.get("coils"):
|
||||||
if modbus.TYPE == "serial" and not slave:
|
switches.append(ModbusCoilSwitch(
|
||||||
_LOGGER.error("No slave number provided for serial Modbus")
|
coil.get(CONF_NAME),
|
||||||
return False
|
coil.get(CONF_SLAVE),
|
||||||
registers = config.get("registers")
|
coil.get(CONF_COIL)))
|
||||||
if registers:
|
|
||||||
for regnum, register in registers.items():
|
|
||||||
bits = register.get("bits")
|
|
||||||
for bitnum, bit in bits.items():
|
|
||||||
if bit.get("name"):
|
|
||||||
switches.append(ModbusSwitch(bit.get("name"),
|
|
||||||
slave,
|
|
||||||
regnum,
|
|
||||||
bitnum))
|
|
||||||
coils = config.get("coils")
|
|
||||||
if coils:
|
|
||||||
for coilnum, coil in coils.items():
|
|
||||||
switches.append(ModbusSwitch(coil.get("name"),
|
|
||||||
slave,
|
|
||||||
coilnum,
|
|
||||||
0,
|
|
||||||
coil=True))
|
|
||||||
add_devices(switches)
|
add_devices(switches)
|
||||||
|
|
||||||
|
|
||||||
class ModbusSwitch(ToggleEntity):
|
class ModbusCoilSwitch(ToggleEntity):
|
||||||
"""Representation of a Modbus switch."""
|
"""Representation of a Modbus switch."""
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
def __init__(self, name, slave, register, bit, coil=False):
|
def __init__(self, name, slave, coil):
|
||||||
"""Initialize the switch."""
|
"""Initialize the switch."""
|
||||||
self._name = name
|
self._name = name
|
||||||
self.slave = int(slave) if slave else 1
|
self._slave = int(slave) if slave else None
|
||||||
self.register = int(register)
|
self._coil = int(coil)
|
||||||
self.bit = int(bit)
|
|
||||||
self._coil = coil
|
|
||||||
self._is_on = None
|
self._is_on = None
|
||||||
self.register_value = None
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""String representation of Modbus switch."""
|
|
||||||
return "%s: %s" % (self.name, self.state)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""Poling needed.
|
|
||||||
|
|
||||||
Slaves are not allowed to initiate communication on Modbus networks.
|
|
||||||
"""
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self):
|
|
||||||
"""Return a unique ID."""
|
|
||||||
return "MODBUS-SWITCH-{}-{}-{}".format(self.slave,
|
|
||||||
self.register,
|
|
||||||
self.bit)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
@ -86,39 +63,13 @@ class ModbusSwitch(ToggleEntity):
|
|||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
"""Set switch on."""
|
"""Set switch on."""
|
||||||
if self.register_value is None:
|
modbus.HUB.write_coil(self._slave, self._coil, True)
|
||||||
self.update()
|
|
||||||
|
|
||||||
if self._coil:
|
|
||||||
modbus.HUB.write_coil(self.slave, self.register, True)
|
|
||||||
else:
|
|
||||||
val = self.register_value | (0x0001 << self.bit)
|
|
||||||
modbus.HUB.write_register(self.slave, self.register, val)
|
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs):
|
||||||
"""Set switch off."""
|
"""Set switch off."""
|
||||||
if self.register_value is None:
|
modbus.HUB.write_coil(self._slave, self._coil, False)
|
||||||
self.update()
|
|
||||||
|
|
||||||
if self._coil:
|
|
||||||
modbus.HUB.write_coil(self.slave, self.register, False)
|
|
||||||
else:
|
|
||||||
val = self.register_value & ~(0x0001 << self.bit)
|
|
||||||
modbus.HUB.write_register(self.slave, self.register, val)
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update the state of the switch."""
|
"""Update the state of the switch."""
|
||||||
if self._coil:
|
result = modbus.HUB.read_coils(self._slave, self._coil, 1)
|
||||||
result = modbus.HUB.read_coils(self.slave, self.register, 1)
|
self._is_on = bool(result.bits[0])
|
||||||
self.register_value = result.bits[0]
|
|
||||||
self._is_on = self.register_value
|
|
||||||
else:
|
|
||||||
result = modbus.HUB.read_holding_registers(
|
|
||||||
self.slave,
|
|
||||||
self.register,
|
|
||||||
1)
|
|
||||||
val = 0
|
|
||||||
for i, res in enumerate(result.registers):
|
|
||||||
val += res * (2**(i*16))
|
|
||||||
self.register_value = val
|
|
||||||
self._is_on = (val & (0x0001 << self.bit) > 0)
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user