Skip to content

Commit

Permalink
Add opentherm_gw binary sensor support (#17625)
Browse files Browse the repository at this point in the history
* Add OpenTherm Gateway binary sensor support.

* opentherm_gw binary_sensor platform does not need polling.
  • Loading branch information
mvn23 authored and MartinHjelmare committed Oct 20, 2018
1 parent 2e973c7 commit 237ac08
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 3 deletions.
145 changes: 145 additions & 0 deletions homeassistant/components/binary_sensor/opentherm_gw.py
@@ -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
49 changes: 46 additions & 3 deletions homeassistant/components/opentherm_gw.py
Expand Up @@ -8,6 +8,7 @@

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.const import (CONF_DEVICE, CONF_MONITORED_VARIABLES,
CONF_NAME, PRECISION_HALVES, PRECISION_TENTHS,
Expand Down Expand Up @@ -55,6 +56,7 @@ async def async_setup(hass, config):
import pyotgw
conf = config[DOMAIN]
gateway = pyotgw.pyotgw()
monitored_vars = conf.get(CONF_MONITORED_VARIABLES)
hass.data[DATA_OPENTHERM_GW] = {
DATA_DEVICE: gateway,
DATA_GW_VARS: pyotgw.vars,
Expand All @@ -63,8 +65,8 @@ async def async_setup(hass, config):
hass, conf[CONF_DEVICE], gateway))
hass.async_create_task(async_load_platform(
hass, 'climate', DOMAIN, conf.get(CONF_CLIMATE)))
hass.async_create_task(setup_monitored_vars(
hass, conf.get(CONF_MONITORED_VARIABLES)))
if monitored_vars:
hass.async_create_task(setup_monitored_vars(hass, monitored_vars))
return True


Expand All @@ -83,8 +85,43 @@ async def handle_report(status):
async def setup_monitored_vars(hass, monitored_vars):
"""Set up requested sensors."""
gw_vars = hass.data[DATA_OPENTHERM_GW][DATA_GW_VARS]
# Use dict to prepare for binary sensor support.
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: [
gw_vars.DATA_CONTROL_SETPOINT,
gw_vars.DATA_MASTER_MEMBERID,
Expand Down Expand Up @@ -152,11 +189,17 @@ async def setup_monitored_vars(hass, monitored_vars):
gw_vars.OTGW_VREF,
]
}
binary_sensors = []
sensors = []
for var in monitored_vars:
if var in sensor_type_map[COMP_SENSOR]:
sensors.append(var)
elif var in sensor_type_map[COMP_BINARY_SENSOR]:
binary_sensors.append(var)
else:
_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:
await async_load_platform(hass, COMP_SENSOR, DOMAIN, sensors)

0 comments on commit 237ac08

Please sign in to comment.