Add opentherm_gw binary sensor support (#17625)

* Add OpenTherm Gateway binary sensor support.

* opentherm_gw binary_sensor platform does not need polling.
This commit is contained in:
mvn23 2018-10-20 18:51:01 +02:00 committed by Martin Hjelmare
parent 2e973c7572
commit 237ac08076
2 changed files with 191 additions and 3 deletions

View File

@ -0,0 +1,145 @@
"""
Support for OpenTherm Gateway binary sensors.
For more details about this platform, please refer to the documentation at
http://home-assistant.io/components/binary_sensor.opentherm_gw/
"""
import logging
from homeassistant.components.binary_sensor import (
BinarySensorDevice, ENTITY_ID_FORMAT)
from homeassistant.components.opentherm_gw import (
DATA_GW_VARS, DATA_OPENTHERM_GW, SIGNAL_OPENTHERM_GW_UPDATE)
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import async_generate_entity_id
DEVICE_CLASS_COLD = 'cold'
DEVICE_CLASS_HEAT = 'heat'
DEVICE_CLASS_PROBLEM = 'problem'
DEPENDENCIES = ['opentherm_gw']
_LOGGER = logging.getLogger(__name__)
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the OpenTherm Gateway binary sensors."""
if discovery_info is None:
return
gw_vars = hass.data[DATA_OPENTHERM_GW][DATA_GW_VARS]
sensor_info = {
# [device_class, friendly_name]
gw_vars.DATA_MASTER_CH_ENABLED: [
None, "Thermostat Central Heating Enabled"],
gw_vars.DATA_MASTER_DHW_ENABLED: [
None, "Thermostat Hot Water Enabled"],
gw_vars.DATA_MASTER_COOLING_ENABLED: [
None, "Thermostat Cooling Enabled"],
gw_vars.DATA_MASTER_OTC_ENABLED: [
None, "Thermostat Outside Temperature Correction Enabled"],
gw_vars.DATA_MASTER_CH2_ENABLED: [
None, "Thermostat Central Heating 2 Enabled"],
gw_vars.DATA_SLAVE_FAULT_IND: [
DEVICE_CLASS_PROBLEM, "Boiler Fault Indication"],
gw_vars.DATA_SLAVE_CH_ACTIVE: [
DEVICE_CLASS_HEAT, "Boiler Central Heating Status"],
gw_vars.DATA_SLAVE_DHW_ACTIVE: [
DEVICE_CLASS_HEAT, "Boiler Hot Water Status"],
gw_vars.DATA_SLAVE_FLAME_ON: [
DEVICE_CLASS_HEAT, "Boiler Flame Status"],
gw_vars.DATA_SLAVE_COOLING_ACTIVE: [
DEVICE_CLASS_COLD, "Boiler Cooling Status"],
gw_vars.DATA_SLAVE_CH2_ACTIVE: [
DEVICE_CLASS_HEAT, "Boiler Central Heating 2 Status"],
gw_vars.DATA_SLAVE_DIAG_IND: [
DEVICE_CLASS_PROBLEM, "Boiler Diagnostics Indication"],
gw_vars.DATA_SLAVE_DHW_PRESENT: [None, "Boiler Hot Water Present"],
gw_vars.DATA_SLAVE_CONTROL_TYPE: [None, "Boiler Control Type"],
gw_vars.DATA_SLAVE_COOLING_SUPPORTED: [None, "Boiler Cooling Support"],
gw_vars.DATA_SLAVE_DHW_CONFIG: [
None, "Boiler Hot Water Configuration"],
gw_vars.DATA_SLAVE_MASTER_LOW_OFF_PUMP: [
None, "Boiler Pump Commands Support"],
gw_vars.DATA_SLAVE_CH2_PRESENT: [
None, "Boiler Central Heating 2 Present"],
gw_vars.DATA_SLAVE_SERVICE_REQ: [
DEVICE_CLASS_PROBLEM, "Boiler Service Required"],
gw_vars.DATA_SLAVE_REMOTE_RESET: [None, "Boiler Remote Reset Support"],
gw_vars.DATA_SLAVE_LOW_WATER_PRESS: [
DEVICE_CLASS_PROBLEM, "Boiler Low Water Pressure"],
gw_vars.DATA_SLAVE_GAS_FAULT: [
DEVICE_CLASS_PROBLEM, "Boiler Gas Fault"],
gw_vars.DATA_SLAVE_AIR_PRESS_FAULT: [
DEVICE_CLASS_PROBLEM, "Boiler Air Pressure Fault"],
gw_vars.DATA_SLAVE_WATER_OVERTEMP: [
DEVICE_CLASS_PROBLEM, "Boiler Water Overtemperature"],
gw_vars.DATA_REMOTE_TRANSFER_DHW: [
None, "Remote Hot Water Setpoint Transfer Support"],
gw_vars.DATA_REMOTE_TRANSFER_MAX_CH: [
None, "Remote Maximum Central Heating Setpoint Write Support"],
gw_vars.DATA_REMOTE_RW_DHW: [
None, "Remote Hot Water Setpoint Write Support"],
gw_vars.DATA_REMOTE_RW_MAX_CH: [
None, "Remote Central Heating Setpoint Write Support"],
gw_vars.DATA_ROVRD_MAN_PRIO: [
None, "Remote Override Manual Change Priority"],
gw_vars.DATA_ROVRD_AUTO_PRIO: [
None, "Remote Override Program Change Priority"],
gw_vars.OTGW_GPIO_A_STATE: [None, "Gateway GPIO A State"],
gw_vars.OTGW_GPIO_B_STATE: [None, "Gateway GPIO B State"],
gw_vars.OTGW_IGNORE_TRANSITIONS: [None, "Gateway Ignore Transitions"],
gw_vars.OTGW_OVRD_HB: [None, "Gateway Override High Byte"],
}
sensors = []
for var in discovery_info:
device_class = sensor_info[var][0]
friendly_name = sensor_info[var][1]
entity_id = async_generate_entity_id(ENTITY_ID_FORMAT, var, hass=hass)
sensors.append(OpenThermBinarySensor(entity_id, var, device_class,
friendly_name))
async_add_entities(sensors)
class OpenThermBinarySensor(BinarySensorDevice):
"""Represent an OpenTherm Gateway binary sensor."""
def __init__(self, entity_id, var, device_class, friendly_name):
"""Initialize the binary sensor."""
self.entity_id = entity_id
self._var = var
self._state = None
self._device_class = device_class
self._friendly_name = friendly_name
async def async_added_to_hass(self):
"""Subscribe to updates from the component."""
_LOGGER.debug(
"Added OpenTherm Gateway binary sensor %s", self._friendly_name)
async_dispatcher_connect(self.hass, SIGNAL_OPENTHERM_GW_UPDATE,
self.receive_report)
async def receive_report(self, status):
"""Handle status updates from the component."""
self._state = bool(status.get(self._var))
self.async_schedule_update_ha_state()
@property
def name(self):
"""Return the friendly name."""
return self._friendly_name
@property
def is_on(self):
"""Return true if the binary sensor is on."""
return self._state
@property
def device_class(self):
"""Return the class of this device."""
return self._device_class
@property
def should_poll(self):
"""Return False because entity pushes its state."""
return False

View File

@ -8,6 +8,7 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.binary_sensor import DOMAIN as COMP_BINARY_SENSOR
from homeassistant.components.sensor import DOMAIN as COMP_SENSOR from homeassistant.components.sensor import DOMAIN as COMP_SENSOR
from homeassistant.const import (CONF_DEVICE, CONF_MONITORED_VARIABLES, from homeassistant.const import (CONF_DEVICE, CONF_MONITORED_VARIABLES,
CONF_NAME, PRECISION_HALVES, PRECISION_TENTHS, CONF_NAME, PRECISION_HALVES, PRECISION_TENTHS,
@ -55,6 +56,7 @@ async def async_setup(hass, config):
import pyotgw import pyotgw
conf = config[DOMAIN] conf = config[DOMAIN]
gateway = pyotgw.pyotgw() gateway = pyotgw.pyotgw()
monitored_vars = conf.get(CONF_MONITORED_VARIABLES)
hass.data[DATA_OPENTHERM_GW] = { hass.data[DATA_OPENTHERM_GW] = {
DATA_DEVICE: gateway, DATA_DEVICE: gateway,
DATA_GW_VARS: pyotgw.vars, DATA_GW_VARS: pyotgw.vars,
@ -63,8 +65,8 @@ async def async_setup(hass, config):
hass, conf[CONF_DEVICE], gateway)) hass, conf[CONF_DEVICE], gateway))
hass.async_create_task(async_load_platform( hass.async_create_task(async_load_platform(
hass, 'climate', DOMAIN, conf.get(CONF_CLIMATE))) hass, 'climate', DOMAIN, conf.get(CONF_CLIMATE)))
hass.async_create_task(setup_monitored_vars( if monitored_vars:
hass, conf.get(CONF_MONITORED_VARIABLES))) hass.async_create_task(setup_monitored_vars(hass, monitored_vars))
return True return True
@ -83,8 +85,43 @@ async def connect_and_subscribe(hass, device_path, gateway):
async def setup_monitored_vars(hass, monitored_vars): async def setup_monitored_vars(hass, monitored_vars):
"""Set up requested sensors.""" """Set up requested sensors."""
gw_vars = hass.data[DATA_OPENTHERM_GW][DATA_GW_VARS] gw_vars = hass.data[DATA_OPENTHERM_GW][DATA_GW_VARS]
# Use dict to prepare for binary sensor support.
sensor_type_map = { sensor_type_map = {
COMP_BINARY_SENSOR: [
gw_vars.DATA_MASTER_CH_ENABLED,
gw_vars.DATA_MASTER_DHW_ENABLED,
gw_vars.DATA_MASTER_COOLING_ENABLED,
gw_vars.DATA_MASTER_OTC_ENABLED,
gw_vars.DATA_MASTER_CH2_ENABLED,
gw_vars.DATA_SLAVE_FAULT_IND,
gw_vars.DATA_SLAVE_CH_ACTIVE,
gw_vars.DATA_SLAVE_DHW_ACTIVE,
gw_vars.DATA_SLAVE_FLAME_ON,
gw_vars.DATA_SLAVE_COOLING_ACTIVE,
gw_vars.DATA_SLAVE_CH2_ACTIVE,
gw_vars.DATA_SLAVE_DIAG_IND,
gw_vars.DATA_SLAVE_DHW_PRESENT,
gw_vars.DATA_SLAVE_CONTROL_TYPE,
gw_vars.DATA_SLAVE_COOLING_SUPPORTED,
gw_vars.DATA_SLAVE_DHW_CONFIG,
gw_vars.DATA_SLAVE_MASTER_LOW_OFF_PUMP,
gw_vars.DATA_SLAVE_CH2_PRESENT,
gw_vars.DATA_SLAVE_SERVICE_REQ,
gw_vars.DATA_SLAVE_REMOTE_RESET,
gw_vars.DATA_SLAVE_LOW_WATER_PRESS,
gw_vars.DATA_SLAVE_GAS_FAULT,
gw_vars.DATA_SLAVE_AIR_PRESS_FAULT,
gw_vars.DATA_SLAVE_WATER_OVERTEMP,
gw_vars.DATA_REMOTE_TRANSFER_DHW,
gw_vars.DATA_REMOTE_TRANSFER_MAX_CH,
gw_vars.DATA_REMOTE_RW_DHW,
gw_vars.DATA_REMOTE_RW_MAX_CH,
gw_vars.DATA_ROVRD_MAN_PRIO,
gw_vars.DATA_ROVRD_AUTO_PRIO,
gw_vars.OTGW_GPIO_A_STATE,
gw_vars.OTGW_GPIO_B_STATE,
gw_vars.OTGW_IGNORE_TRANSITIONS,
gw_vars.OTGW_OVRD_HB,
],
COMP_SENSOR: [ COMP_SENSOR: [
gw_vars.DATA_CONTROL_SETPOINT, gw_vars.DATA_CONTROL_SETPOINT,
gw_vars.DATA_MASTER_MEMBERID, gw_vars.DATA_MASTER_MEMBERID,
@ -152,11 +189,17 @@ async def setup_monitored_vars(hass, monitored_vars):
gw_vars.OTGW_VREF, gw_vars.OTGW_VREF,
] ]
} }
binary_sensors = []
sensors = [] sensors = []
for var in monitored_vars: for var in monitored_vars:
if var in sensor_type_map[COMP_SENSOR]: if var in sensor_type_map[COMP_SENSOR]:
sensors.append(var) sensors.append(var)
elif var in sensor_type_map[COMP_BINARY_SENSOR]:
binary_sensors.append(var)
else: else:
_LOGGER.error("Monitored variable not supported: %s", var) _LOGGER.error("Monitored variable not supported: %s", var)
if binary_sensors:
hass.async_create_task(async_load_platform(
hass, COMP_BINARY_SENSOR, DOMAIN, binary_sensors))
if sensors: if sensors:
await async_load_platform(hass, COMP_SENSOR, DOMAIN, sensors) await async_load_platform(hass, COMP_SENSOR, DOMAIN, sensors)