Add OpenTherm Gateway sensor platform.

* Remove library imports from platforms (use hass.data instead)
* Update .coveragerc
* Update docstrings to use new component documentation url
This commit is contained in:
mvn23
2018-10-06 14:41:19 +02:00
parent 442bc0f75b
commit b3505ed561
4 changed files with 338 additions and 57 deletions

View File

@ -242,6 +242,9 @@ omit =
homeassistant/components/opencv.py homeassistant/components/opencv.py
homeassistant/components/*/opencv.py homeassistant/components/*/opencv.py
homeassistant/components/opentherm_gw.py
homeassistant/components/*/opentherm_gw.py
homeassistant/components/openuv/__init__.py homeassistant/components/openuv/__init__.py
homeassistant/components/*/openuv.py homeassistant/components/*/openuv.py
@ -429,7 +432,6 @@ omit =
homeassistant/components/climate/honeywell.py homeassistant/components/climate/honeywell.py
homeassistant/components/climate/knx.py homeassistant/components/climate/knx.py
homeassistant/components/climate/oem.py homeassistant/components/climate/oem.py
homeassistant/components/climate/opentherm_gw.py
homeassistant/components/climate/proliphix.py homeassistant/components/climate/proliphix.py
homeassistant/components/climate/radiotherm.py homeassistant/components/climate/radiotherm.py
homeassistant/components/climate/sensibo.py homeassistant/components/climate/sensibo.py

View File

@ -1,23 +1,20 @@
""" """
Support for OpenTherm Gateway devices. Support for OpenTherm Gateway climate devices.
For more details about this component, please refer to the documentation at For more details about this platform, please refer to the documentation at
http://home-assistant.io/components/climate.opentherm_gw/ http://home-assistant.io/components/opentherm_gw/
""" """
import logging import logging
import voluptuous as vol from homeassistant.components.climate import (ClimateDevice, STATE_IDLE,
STATE_HEAT, STATE_COOL,
from homeassistant.components.climate import (ClimateDevice, PLATFORM_SCHEMA,
STATE_IDLE, STATE_HEAT,
STATE_COOL,
SUPPORT_TARGET_TEMPERATURE) SUPPORT_TARGET_TEMPERATURE)
from homeassistant.components.opentherm_gw import SIGNAL_OPENTHERM_GW_UPDATE from homeassistant.components.opentherm_gw import (
from homeassistant.const import (ATTR_TEMPERATURE, CONF_DEVICE, CONF_NAME, DATA_DEVICE, DATA_GW_VARS, DATA_OPENTHERM_GW, SIGNAL_OPENTHERM_GW_UPDATE)
PRECISION_HALVES, PRECISION_TENTHS, from homeassistant.const import (ATTR_TEMPERATURE, CONF_NAME, PRECISION_HALVES,
TEMP_CELSIUS, PRECISION_WHOLE) PRECISION_TENTHS, TEMP_CELSIUS,
PRECISION_WHOLE)
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['opentherm_gw'] DEPENDENCIES = ['opentherm_gw']
@ -31,20 +28,20 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_platform(hass, config, async_add_entities, async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None): discovery_info=None):
"""Set up the opentherm_gw device.""" """Set up the opentherm_gw device."""
gateway = OpenThermGateway(discovery_info) gateway = OpenThermGateway(hass, discovery_info)
async_add_entities([gateway]) async_add_entities([gateway])
class OpenThermGateway(ClimateDevice): class OpenThermGateway(ClimateDevice):
"""Representation of a climate device.""" """Representation of a climate device."""
def __init__(self, config): def __init__(self, hass, config):
"""Initialize the device.""" """Initialize the device."""
import pyotgw
self.pyotgw = pyotgw
self.friendly_name = config.get(CONF_NAME) self.friendly_name = config.get(CONF_NAME)
self.floor_temp = config.get(CONF_FLOOR_TEMP) self.floor_temp = config.get(CONF_FLOOR_TEMP)
self.temp_precision = config.get(CONF_PRECISION) self.temp_precision = config.get(CONF_PRECISION)
self._gateway = hass.data[DATA_OPENTHERM_GW][DATA_DEVICE]
self._gw_vars = hass.data[DATA_OPENTHERM_GW][DATA_GW_VARS]
self._current_operation = STATE_IDLE self._current_operation = STATE_IDLE
self._current_temperature = 0.0 self._current_temperature = 0.0
self._target_temperature = 0.0 self._target_temperature = 0.0
@ -55,39 +52,39 @@ class OpenThermGateway(ClimateDevice):
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Connect to the OpenTherm Gateway device.""" """Connect to the OpenTherm Gateway device."""
_LOGGER.debug("Added device {}".format(self.friendly_name)) _LOGGER.debug("Added device %s", self.friendly_name)
async_dispatcher_connect(self.hass, SIGNAL_OPENTHERM_GW_UPDATE, async_dispatcher_connect(self.hass, SIGNAL_OPENTHERM_GW_UPDATE,
self.receive_report) self.receive_report)
async def receive_report(self, status): async def receive_report(self, status):
"""Receive and handle a new report from the Gateway.""" """Receive and handle a new report from the Gateway."""
_LOGGER.debug("Received report: %s", status) _LOGGER.debug("Received report: %s", status)
ch_active = status.get(self.pyotgw.DATA_SLAVE_CH_ACTIVE) ch_active = status.get(self._gw_vars.DATA_SLAVE_CH_ACTIVE)
flame_on = status.get(self.pyotgw.DATA_SLAVE_FLAME_ON) flame_on = status.get(self._gw_vars.DATA_SLAVE_FLAME_ON)
cooling_active = status.get(self.pyotgw.DATA_SLAVE_COOLING_ACTIVE) cooling_active = status.get(self._gw_vars.DATA_SLAVE_COOLING_ACTIVE)
if ch_active and flame_on: if ch_active and flame_on:
self._current_operation = STATE_HEAT self._current_operation = STATE_HEAT
elif cooling_active: elif cooling_active:
self._current_operation = STATE_COOL self._current_operation = STATE_COOL
else: else:
self._current_operation = STATE_IDLE self._current_operation = STATE_IDLE
self._current_temperature = status.get(self.pyotgw.DATA_ROOM_TEMP) self._current_temperature = status.get(self._gw_vars.DATA_ROOM_TEMP)
temp = status.get(self.pyotgw.DATA_ROOM_SETPOINT_OVRD) temp = status.get(self._gw_vars.DATA_ROOM_SETPOINT_OVRD)
if temp is None: if temp is None:
temp = status.get(self.pyotgw.DATA_ROOM_SETPOINT) temp = status.get(self._gw_vars.DATA_ROOM_SETPOINT)
self._target_temperature = temp self._target_temperature = temp
# GPIO mode 5: 0 == Away # GPIO mode 5: 0 == Away
# GPIO mode 6: 1 == Away # GPIO mode 6: 1 == Away
gpio_a_state = status.get(self.pyotgw.OTGW_GPIO_A) gpio_a_state = status.get(self._gw_vars.OTGW_GPIO_A)
if gpio_a_state == 5: if gpio_a_state == 5:
self._away_mode_a = 0 self._away_mode_a = 0
elif gpio_a_state == 6: elif gpio_a_state == 6:
self._away_mode_a = 1 self._away_mode_a = 1
else: else:
self._away_mode_a = None self._away_mode_a = None
gpio_b_state = status.get(self.pyotgw.OTGW_GPIO_B) gpio_b_state = status.get(self._gw_vars.OTGW_GPIO_B)
if gpio_b_state == 5: if gpio_b_state == 5:
self._away_mode_b = 0 self._away_mode_b = 0
elif gpio_b_state == 6: elif gpio_b_state == 6:
@ -95,11 +92,11 @@ class OpenThermGateway(ClimateDevice):
else: else:
self._away_mode_b = None self._away_mode_b = None
if self._away_mode_a is not None: if self._away_mode_a is not None:
self._away_state_a = (status.get(self.pyotgw.OTGW_GPIO_A_STATE) == self._away_state_a = (status.get(
self._away_mode_a) self._gw_vars.OTGW_GPIO_A_STATE) == self._away_mode_a)
if self._away_mode_b is not None: if self._away_mode_b is not None:
self._away_state_b = (status.get(self.pyotgw.OTGW_GPIO_B_STATE) == self._away_state_b = (status.get(
self._away_mode_b) self._gw_vars.OTGW_GPIO_B_STATE) == self._away_mode_b)
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()
@property @property
@ -161,7 +158,7 @@ class OpenThermGateway(ClimateDevice):
"""Set new target temperature.""" """Set new target temperature."""
if ATTR_TEMPERATURE in kwargs: if ATTR_TEMPERATURE in kwargs:
temp = float(kwargs[ATTR_TEMPERATURE]) temp = float(kwargs[ATTR_TEMPERATURE])
self._target_temperature = await self.gateway.set_target_temp( self._target_temperature = await self._gateway.set_target_temp(
temp) temp)
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()

View File

@ -1,21 +1,32 @@
import asyncio """
Support for OpenTherm Gateway devices.
For more details about this component, please refer to the documentation at
http://home-assistant.io/components/opentherm_gw/
"""
import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.helpers.discovery import (async_load_platform, from homeassistant.helpers.discovery import async_load_platform
async_listen_platform)
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.const import (CONF_BINARY_SENSORS, CONF_DEVICE, from homeassistant.const import (CONF_DEVICE, CONF_MONITORED_VARIABLES,
CONF_MONITORED_VARIABLES, CONF_NAME, CONF_NAME, PRECISION_HALVES, PRECISION_TENTHS,
CONF_SENSORS, PRECISION_HALVES, PRECISION_WHOLE)
PRECISION_TENTHS, PRECISION_WHOLE)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
DOMAIN = 'opentherm_gw' DOMAIN = 'opentherm_gw'
COMP_SENSOR = 'sensor'
COMP_BINARY_SENSOR = 'binary_sensor'
CONF_CLIMATE = 'climate' CONF_CLIMATE = 'climate'
CONF_FLOOR_TEMP = 'floor_temperature' CONF_FLOOR_TEMP = 'floor_temperature'
CONF_PRECISION = 'precision' CONF_PRECISION = 'precision'
DATA_DEVICE = 'device'
DATA_GW_VARS = 'gw_vars'
DATA_OPENTHERM_GW = 'opentherm_gw'
SIGNAL_OPENTHERM_GW_UPDATE = 'opentherm_gw_update' SIGNAL_OPENTHERM_GW_UPDATE = 'opentherm_gw_update'
CLIMATE_SCHEMA = vol.Schema({ CLIMATE_SCHEMA = vol.Schema({
@ -25,42 +36,41 @@ CLIMATE_SCHEMA = vol.Schema({
vol.Optional(CONF_FLOOR_TEMP, default=False): cv.boolean, vol.Optional(CONF_FLOOR_TEMP, default=False): cv.boolean,
}) })
SENSOR_SCHEMA = vol.Schema({
vol.Optional(CONF_MONITORED_VARIABLES, default=[]): cv.ensure_list,
})
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
vol.Required(CONF_DEVICE): cv.string, vol.Required(CONF_DEVICE): cv.string,
vol.Optional(CONF_CLIMATE, default=CLIMATE_SCHEMA({})): vol.Optional(CONF_CLIMATE, default=CLIMATE_SCHEMA({})):
CLIMATE_SCHEMA, CLIMATE_SCHEMA,
vol.Optional(CONF_SENSORS, default=SENSOR_SCHEMA({})): SENSOR_SCHEMA, vol.Optional(CONF_MONITORED_VARIABLES, default=[]): cv.ensure_list,
vol.Optional(CONF_BINARY_SENSORS, default=SENSOR_SCHEMA({})):
SENSOR_SCHEMA,
}), }),
}, extra = vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
REQUIREMENTS = ['pyotgw==0.1b0'] REQUIREMENTS = ['pyotgw==0.1b0']
_LOGGER = logging.getLogger(__name__)
async def async_setup(hass, config): async def async_setup(hass, config):
"""Set up the OpenTherm Gateway component.""" """Set up the OpenTherm Gateway component."""
conf = config.get(DOMAIN) conf = config.get(DOMAIN)
if conf is None: if conf is None:
return True return True
import pyotgw
hass.data[DATA_OPENTHERM_GW] = {
DATA_DEVICE: pyotgw.pyotgw(),
DATA_GW_VARS: pyotgw.vars,
}
hass.async_add_job(connect_and_subscribe, hass, conf) hass.async_add_job(connect_and_subscribe, hass, conf)
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(async_load_platform( hass.async_add_job(setup_monitored_vars, hass,
# hass, 'sensor', DOMAIN, conf.get(CONF_MONITORED_VARIABLES))) conf.get(CONF_MONITORED_VARIABLES))
#hass.async_create_task(async_load_platform(
# hass, 'binary_sensor', DOMAIN, conf.get(CONF_MONITORED_VARIABLES)))
return True return True
async def connect_and_subscribe(hass, conf): async def connect_and_subscribe(hass, conf):
"""Connect to serial device and subscribe report handler.""" """Connect to serial device and subscribe report handler."""
import pyotgw gateway = hass.data[DATA_OPENTHERM_GW][DATA_DEVICE]
gateway = pyotgw.pyotgw()
await gateway.connect(hass.loop, conf[CONF_DEVICE]) await gateway.connect(hass.loop, conf[CONF_DEVICE])
async def handle_report(status): async def handle_report(status):
@ -68,7 +78,96 @@ async def connect_and_subscribe(hass, conf):
async_dispatcher_send(hass, SIGNAL_OPENTHERM_GW_UPDATE, status) async_dispatcher_send(hass, SIGNAL_OPENTHERM_GW_UPDATE, status)
gateway.subscribe(handle_report) gateway.subscribe(handle_report)
async def setup_monitored_vars(hass, monitored_vars):
# class OpenThermSensor(Entity): """Setup requested sensors and binary_sensors."""
# """Basic functionality for opentherm_gw sensor.""" gw_vars = hass.data[DATA_OPENTHERM_GW][DATA_GW_VARS]
# sensor_type_map = {
gw_vars.DATA_MASTER_CH_ENABLED: COMP_BINARY_SENSOR,
gw_vars.DATA_MASTER_DHW_ENABLED: COMP_BINARY_SENSOR,
gw_vars.DATA_MASTER_COOLING_ENABLED: COMP_BINARY_SENSOR,
gw_vars.DATA_MASTER_OTC_ENABLED: COMP_BINARY_SENSOR,
gw_vars.DATA_MASTER_CH2_ENABLED: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_FAULT_IND: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_CH_ACTIVE: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_DHW_ACTIVE: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_FLAME_ON: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_COOLING_ACTIVE: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_CH2_ACTIVE: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_DIAG_IND: COMP_BINARY_SENSOR,
gw_vars.DATA_CONTROL_SETPOINT: COMP_SENSOR,
gw_vars.DATA_MASTER_MEMBERID: COMP_SENSOR,
gw_vars.DATA_SLAVE_DHW_PRESENT: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_CONTROL_TYPE: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_COOLING_SUPPORTED: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_DHW_CONFIG: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_MASTER_LOW_OFF_PUMP: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_CH2_PRESENT: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_MEMBERID: COMP_SENSOR,
gw_vars.DATA_SLAVE_SERVICE_REQ: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_REMOTE_RESET: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_LOW_WATER_PRESS: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_GAS_FAULT: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_AIR_PRESS_FAULT: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_WATER_OVERTEMP: COMP_BINARY_SENSOR,
gw_vars.DATA_SLAVE_OEM_FAULT: COMP_SENSOR,
gw_vars.DATA_REMOTE_TRANSFER_DHW: COMP_BINARY_SENSOR,
gw_vars.DATA_REMOTE_TRANSFER_MAX_CH: COMP_BINARY_SENSOR,
gw_vars.DATA_REMOTE_RW_DHW: COMP_BINARY_SENSOR,
gw_vars.DATA_REMOTE_RW_MAX_CH: COMP_BINARY_SENSOR,
gw_vars.DATA_COOLING_CONTROL: COMP_SENSOR,
gw_vars.DATA_CONTROL_SETPOINT_2: COMP_SENSOR,
gw_vars.DATA_ROOM_SETPOINT_OVRD: COMP_SENSOR,
gw_vars.DATA_SLAVE_MAX_RELATIVE_MOD: COMP_SENSOR,
gw_vars.DATA_SLAVE_MAX_CAPACITY: COMP_SENSOR,
gw_vars.DATA_SLAVE_MIN_MOD_LEVEL: COMP_SENSOR,
gw_vars.DATA_ROOM_SETPOINT: COMP_SENSOR,
gw_vars.DATA_REL_MOD_LEVEL: COMP_SENSOR,
gw_vars.DATA_CH_WATER_PRESS: COMP_SENSOR,
gw_vars.DATA_DHW_FLOW_RATE: COMP_SENSOR,
gw_vars.DATA_ROOM_SETPOINT_2: COMP_SENSOR,
gw_vars.DATA_ROOM_TEMP: COMP_SENSOR,
gw_vars.DATA_CH_WATER_TEMP: COMP_SENSOR,
gw_vars.DATA_DHW_TEMP: COMP_SENSOR,
gw_vars.DATA_OUTSIDE_TEMP: COMP_SENSOR,
gw_vars.DATA_RETURN_WATER_TEMP: COMP_SENSOR,
gw_vars.DATA_SOLAR_STORAGE_TEMP: COMP_SENSOR,
gw_vars.DATA_SOLAR_COLL_TEMP: COMP_SENSOR,
gw_vars.DATA_CH_WATER_TEMP_2: COMP_SENSOR,
gw_vars.DATA_DHW_TEMP_2: COMP_SENSOR,
gw_vars.DATA_EXHAUST_TEMP: COMP_SENSOR,
gw_vars.DATA_SLAVE_DHW_MAX_SETP: COMP_SENSOR,
gw_vars.DATA_SLAVE_DHW_MIN_SETP: COMP_SENSOR,
gw_vars.DATA_SLAVE_CH_MAX_SETP: COMP_SENSOR,
gw_vars.DATA_SLAVE_CH_MIN_SETP: COMP_SENSOR,
gw_vars.DATA_DHW_SETPOINT: COMP_SENSOR,
gw_vars.DATA_MAX_CH_SETPOINT: COMP_SENSOR,
gw_vars.DATA_ROVRD_MAN_PRIO: COMP_BINARY_SENSOR,
gw_vars.DATA_ROVRD_AUTO_PRIO: COMP_BINARY_SENSOR,
gw_vars.DATA_OEM_DIAG: COMP_SENSOR,
gw_vars.DATA_CH_BURNER_STARTS: COMP_SENSOR,
gw_vars.DATA_CH_PUMP_STARTS: COMP_SENSOR,
gw_vars.DATA_DHW_PUMP_STARTS: COMP_SENSOR,
gw_vars.DATA_DHW_BURNER_STARTS: COMP_SENSOR,
gw_vars.DATA_CH_BURNER_HOURS: COMP_SENSOR,
gw_vars.DATA_CH_PUMP_HOURS: COMP_SENSOR,
gw_vars.DATA_DHW_PUMP_HOURS: COMP_SENSOR,
gw_vars.DATA_DHW_BURNER_HOURS: COMP_SENSOR,
gw_vars.DATA_MASTER_OT_VERSION: COMP_SENSOR,
gw_vars.DATA_SLAVE_OT_VERSION: COMP_SENSOR,
gw_vars.DATA_MASTER_PRODUCT_TYPE: COMP_SENSOR,
gw_vars.DATA_MASTER_PRODUCT_VERSION: COMP_SENSOR,
gw_vars.DATA_SLAVE_PRODUCT_TYPE: COMP_SENSOR,
gw_vars.DATA_SLAVE_PRODUCT_VERSION: COMP_SENSOR,
}
sensors = {COMP_SENSOR: [], COMP_BINARY_SENSOR: []}
for var in monitored_vars:
if var not in sensor_type_map:
_LOGGER.error("Monitored variable not supported: %s", var)
continue
sensors[sensor_type_map[var]].append(var)
if sensors[COMP_SENSOR]:
hass.async_create_task(async_load_platform(
hass, COMP_SENSOR, DOMAIN, sensors[COMP_SENSOR]))
if sensors[COMP_BINARY_SENSOR]:
hass.async_create_task(async_load_platform(
hass, COMP_BINARY_SENSOR, DOMAIN, sensors[COMP_BINARY_SENSOR]))

View File

@ -0,0 +1,183 @@
"""
Support for OpenTherm Gateway sensors.
For more details about this platform, please refer to the documentation at
http://home-assistant.io/components/opentherm_gw/
"""
import logging
from homeassistant.components.opentherm_gw import (
DATA_GW_VARS, DATA_OPENTHERM_GW, SIGNAL_OPENTHERM_GW_UPDATE)
from homeassistant.components.sensor import ENTITY_ID_FORMAT
from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity, async_generate_entity_id
UNIT_BAR = 'bar'
UNIT_HOUR = 'h'
UNIT_KW = 'kW'
UNIT_L_MIN = 'L/min'
UNIT_PERCENT = '%'
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 sensors."""
gw_vars = hass.data[DATA_OPENTHERM_GW][DATA_GW_VARS]
sensor_info = {
# [device_class, unit, friendly_name]
gw_vars.DATA_CONTROL_SETPOINT: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Control Setpoint"],
gw_vars.DATA_MASTER_MEMBERID: [None, None, "Thermostat Member ID"],
gw_vars.DATA_SLAVE_MEMBERID: [None, None, "Boiler Member ID"],
gw_vars.DATA_SLAVE_OEM_FAULT: [None, None, "Boiler OEM Fault Code"],
gw_vars.DATA_COOLING_CONTROL: [
None, UNIT_PERCENT, "Cooling Control Signal"],
gw_vars.DATA_CONTROL_SETPOINT_2: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Control Setpoint 2"],
gw_vars.DATA_ROOM_SETPOINT_OVRD: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Room Setpoint Override"],
gw_vars.DATA_SLAVE_MAX_RELATIVE_MOD: [
None, UNIT_PERCENT, "Boiler Maximum Relative Modulation"],
gw_vars.DATA_SLAVE_MAX_CAPACITY: [
None, UNIT_KW, "Boiler Maximum Capacity"],
gw_vars.DATA_SLAVE_MIN_MOD_LEVEL: [
None, UNIT_PERCENT, "Boiler Minimum Modulation Level"],
gw_vars.DATA_ROOM_SETPOINT: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Room Setpoint"],
gw_vars.DATA_REL_MOD_LEVEL: [
None, UNIT_PERCENT, "Relative Modulation Level"],
gw_vars.DATA_CH_WATER_PRESS: [
None, UNIT_BAR, "Central Heating Water Pressure"],
gw_vars.DATA_DHW_FLOW_RATE: [None, UNIT_L_MIN, "Hot Water Flow Rate"],
gw_vars.DATA_ROOM_SETPOINT_2: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Room Setpoint 2"],
gw_vars.DATA_ROOM_TEMP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Room Temperature"],
gw_vars.DATA_CH_WATER_TEMP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Central Heating Water Temperature"],
gw_vars.DATA_DHW_TEMP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Hot Water Temperature"],
gw_vars.DATA_OUTSIDE_TEMP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Outside Temperature"],
gw_vars.DATA_RETURN_WATER_TEMP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Return Water Temperature"],
gw_vars.DATA_SOLAR_STORAGE_TEMP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Solar Storage Temperature"],
gw_vars.DATA_SOLAR_COLL_TEMP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Solar Collector Temperature"],
gw_vars.DATA_CH_WATER_TEMP_2: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Central Heating 2 Water Temperature"],
gw_vars.DATA_DHW_TEMP_2: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Hot Water 2 Temperature"],
gw_vars.DATA_EXHAUST_TEMP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Exhaust Temperature"],
gw_vars.DATA_SLAVE_DHW_MAX_SETP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Hot Water Maximum Setpoint"],
gw_vars.DATA_SLAVE_DHW_MIN_SETP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Hot Water Minimum Setpoint"],
gw_vars.DATA_SLAVE_CH_MAX_SETP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Boiler Maximum Central Heating Setpoint"],
gw_vars.DATA_SLAVE_CH_MIN_SETP: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Boiler Minimum Central Heating Setpoint"],
gw_vars.DATA_DHW_SETPOINT: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, "Hot Water Setpoint"],
gw_vars.DATA_MAX_CH_SETPOINT: [
DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS,
"Maximum Central Heating Setpoint"],
gw_vars.DATA_OEM_DIAG: [None, None, "OEM Diagnostic Code"],
gw_vars.DATA_CH_BURNER_STARTS: [
None, None, "Central Heating Burner Starts"],
gw_vars.DATA_CH_PUMP_STARTS: [None, None, "Central Heating Pump Starts"],
gw_vars.DATA_DHW_PUMP_STARTS: [None, None, "Hot Water Pump Starts"],
gw_vars.DATA_DHW_BURNER_STARTS: [None, None, "Hot Water Burner Starts"],
gw_vars.DATA_CH_BURNER_HOURS: [
None, UNIT_HOUR, "Central Heating Burner Hours"],
gw_vars.DATA_CH_PUMP_HOURS: [
None, UNIT_HOUR, "Central Heating Pump Hours"],
gw_vars.DATA_DHW_PUMP_HOURS: [None, UNIT_HOUR, "Hot Water Pump Hours"],
gw_vars.DATA_DHW_BURNER_HOURS: [
None, UNIT_HOUR, "Hot Water Burner Hours"],
gw_vars.DATA_MASTER_OT_VERSION: [
None, None, "Thermostat OpenTherm Version"],
gw_vars.DATA_SLAVE_OT_VERSION: [None, None, "Boiler OpenTherm Version"],
gw_vars.DATA_MASTER_PRODUCT_TYPE: [None, None, "Thermostat Product Type"],
gw_vars.DATA_MASTER_PRODUCT_VERSION: [
None, None, "Thermostat Product Version"],
gw_vars.DATA_SLAVE_PRODUCT_TYPE: [None, None, "Boiler Product Type"],
gw_vars.DATA_SLAVE_PRODUCT_VERSION: [
None, None, "Boiler Product Version"],
}
sensors = []
for var in discovery_info:
device_class = sensor_info[var][0]
unit = sensor_info[var][1]
friendly_name = sensor_info[var][2]
sensors.append(
OpenThermSensor(hass, var, device_class, unit, friendly_name))
async_add_entities(sensors)
class OpenThermSensor(Entity):
"""Representation of an OpenTherm Gateway sensor."""
def __init__(self, hass, var, device_class, unit, friendly_name):
"""Initialize the sensor."""
self.entity_id = async_generate_entity_id(ENTITY_ID_FORMAT, var,
hass=hass)
self._var = var
self._value = None
self._device_class = device_class
self._unit = unit
self._friendly_name = friendly_name
async def async_added_to_hass(self):
"""Subscribe to updates from the component."""
_LOGGER.debug("Added OpenTherm Gateway 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."""
value = status.get(self._var)
if isinstance(value, float):
value = '{:2.1f}'.format(value)
self._value = value
self.async_schedule_update_ha_state()
@property
def name(self):
"""Return the friendly name of the sensor."""
return self._friendly_name
@property
def device_class(self):
"""Return the device class."""
return self._device_class
@property
def state(self):
"""Return the state of the device."""
return self._value
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit
@property
def should_poll(self):
"""Return False because entity pushes its state."""
return False