""" homeassistant.components.modbus ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Support for Modbus sensors. Configuration: To use the Modbus sensors you will need to add something like the following to your configuration.yaml file. sensor: platform: modbus slave: 1 registers: 16: name: My integer sensor unit: C 24: bits: 0: name: My boolean sensor 2: name: My other boolean sensor coils: 0: name: My coil switch Variables: slave *Required Slave number (ignored and can be omitted if not serial Modbus). unit *Required Unit to attach to value (optional, ignored for boolean sensors). registers *Required Contains a list of relevant registers to read from. It can contain a "bits" section, listing relevant bits. coils *Optional Contains a list of relevant coils to read from. Note: - Each named register will create an integer sensor. - Each named bit will create a boolean sensor. """ import logging import homeassistant.components.modbus as modbus from homeassistant.helpers.entity import Entity from homeassistant.const import ( TEMP_CELCIUS, TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['modbus'] def setup_platform(hass, config, add_devices, discovery_info=None): """ Read config and create Modbus devices. """ sensors = [] slave = config.get("slave", None) if modbus.TYPE == "serial" and not slave: _LOGGER.error("No slave number provided for serial Modbus") return False registers = config.get("registers") if registers: for regnum, register in registers.items(): if register.get("name"): sensors.append(ModbusSensor(register.get("name"), slave, regnum, None, register.get("unit"))) 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) class ModbusSensor(Entity): # pylint: disable=too-many-arguments """ Represents a Modbus Sensor. """ def __init__(self, name, slave, register, bit=None, unit=None, coil=False): self._name = name self.slave = int(slave) if slave else 1 self.register = int(register) self.bit = int(bit) if bit else None self._value = None self._unit = unit self._coil = coil def __str__(self): return "%s: %s" % (self.name, self.state) @property def should_poll(self): """ We should poll, because slaves are not allowed to initiate communication on Modbus networks. """ return True @property def unique_id(self): """ Returns a unique id. """ return "MODBUS-SENSOR-{}-{}-{}".format(self.slave, self.register, self.bit) @property def state(self): """ Returns the state of the sensor. """ if self.bit: return STATE_ON if self._value else STATE_OFF else: return self._value @property def name(self): """ Get the name of the sensor. """ return self._name @property def unit_of_measurement(self): """ Unit of measurement of this entity, if any. """ if self._unit == "C": return TEMP_CELCIUS elif self._unit == "F": return TEMP_FAHRENHEIT else: return self._unit def update(self): """ Update the state of the sensor. """ if self._coil: result = modbus.NETWORK.read_coils(self.register, 1) self._value = result.bits[0] else: result = modbus.NETWORK.read_holding_registers( unit=self.slave, address=self.register, count=1) val = 0 for i, res in enumerate(result.registers): val += res * (2**(i*16)) if self.bit: self._value = val & (0x0001 << self.bit) else: self._value = val