Add incomfort sensor and binary_sensor (#23812)

* Initial commit - add sensors to incomfort

* improve temp heuristics

* remove self._hass

* device_state_attributes shoudln't be None

* bump client

* refactor to reduce duplication of attributes

* refactor binary_sensor to simplify

* refactor binary_sensor to simplify 2

* delint

* fix rebase regression

* small refactor

* delint

* remove DEVICE_CLASS for CV pressure

* tidy up exception handling

* delint

* fix exception handling

* use differnt icon for boiler temp
pull/24624/head
David Bonnes 2019-06-19 17:03:18 +01:00 committed by Paulus Schoutsen
parent d63c44f778
commit c1d441b0ac
5 changed files with 190 additions and 16 deletions

View File

@ -1,6 +1,7 @@
"""Support for an Intergas boiler via an InComfort/Intouch Lan2RF gateway."""
import logging
from aiohttp import ClientResponseError
import voluptuous as vol
from incomfortclient import Gateway as InComfortGateway
@ -30,21 +31,20 @@ async def async_setup(hass, hass_config):
credentials = dict(hass_config[DOMAIN])
hostname = credentials.pop(CONF_HOST)
try:
client = incomfort_data['client'] = InComfortGateway(
hostname, **credentials, session=async_get_clientsession(hass)
)
try:
heater = incomfort_data['heater'] = list(await client.heaters)[0]
await heater.update()
except AssertionError: # assert response.status == HTTP_OK
except ClientResponseError as err:
_LOGGER.warning(
"Setup failed, check your configuration.",
exc_info=True)
"Setup failed, check your configuration, message is: %s", err)
return False
for platform in ['water_heater', 'climate']:
await heater.update()
for platform in ['water_heater', 'binary_sensor', 'sensor', 'climate']:
hass.async_create_task(async_load_platform(
hass, platform, DOMAIN, {}, hass_config))

View File

@ -0,0 +1,52 @@
"""Support for an Intergas boiler via an InComfort/InTouch Lan2RF gateway."""
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import DOMAIN
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up an InComfort/InTouch binary_sensor device."""
async_add_entities([
IncomfortFailed(hass.data[DOMAIN]['client'],
hass.data[DOMAIN]['heater'])
])
class IncomfortFailed(BinarySensorDevice):
"""Representation of an InComfort Failed sensor."""
def __init__(self, client, boiler):
"""Initialize the binary sensor."""
self._client = client
self._boiler = boiler
async def async_added_to_hass(self):
"""Set up a listener when this entity is added to HA."""
async_dispatcher_connect(self.hass, DOMAIN, self._refresh)
@callback
def _refresh(self):
self.async_schedule_update_ha_state(force_refresh=True)
@property
def name(self):
"""Return the name of the sensor."""
return 'Fault state'
@property
def is_on(self):
"""Return the status of the sensor."""
return self._boiler.status['is_failed']
@property
def device_state_attributes(self):
"""Return the device state attributes."""
return {'fault_code': self._boiler.status['fault_code']}
@property
def should_poll(self) -> bool:
"""Return False as this device should never be polled."""
return False

View File

@ -0,0 +1,110 @@
"""Support for an Intergas boiler via an InComfort/InTouch Lan2RF gateway."""
from homeassistant.const import (
PRESSURE_BAR, TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE)
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from . import DOMAIN
INTOUCH_HEATER_TEMP = 'CV Temp'
INTOUCH_PRESSURE = 'CV Pressure'
INTOUCH_TAP_TEMP = 'Tap Temp'
INTOUCH_MAP_ATTRS = {
INTOUCH_HEATER_TEMP: ['heater_temp', 'is_pumping'],
INTOUCH_TAP_TEMP: ['tap_temp', 'is_tapping'],
}
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up an InComfort/InTouch sensor device."""
client = hass.data[DOMAIN]['client']
heater = hass.data[DOMAIN]['heater']
async_add_entities([
IncomfortPressure(client, heater, INTOUCH_PRESSURE),
IncomfortTemperature(client, heater, INTOUCH_HEATER_TEMP),
IncomfortTemperature(client, heater, INTOUCH_TAP_TEMP)
])
class IncomfortSensor(Entity):
"""Representation of an InComfort/InTouch sensor device."""
def __init__(self, client, boiler):
"""Initialize the sensor."""
self._client = client
self._boiler = boiler
self._name = None
self._device_class = None
self._unit_of_measurement = None
async def async_added_to_hass(self):
"""Set up a listener when this entity is added to HA."""
async_dispatcher_connect(self.hass, DOMAIN, self._refresh)
@callback
def _refresh(self):
self.async_schedule_update_ha_state(force_refresh=True)
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def device_class(self):
"""Return the device class of the sensor."""
return self._device_class
@property
def unit_of_measurement(self):
"""Return the unit of measurement of the sensor."""
return self._unit_of_measurement
@property
def should_poll(self) -> bool:
"""Return False as this device should never be polled."""
return False
class IncomfortPressure(IncomfortSensor):
"""Representation of an InTouch CV Pressure sensor."""
def __init__(self, client, boiler, name):
"""Initialize the sensor."""
super().__init__(client, boiler)
self._name = name
self._unit_of_measurement = PRESSURE_BAR
@property
def state(self):
"""Return the state/value of the sensor."""
return self._boiler.status['pressure']
class IncomfortTemperature(IncomfortSensor):
"""Representation of an InTouch Temperature sensor."""
def __init__(self, client, boiler, name):
"""Initialize the signal strength sensor."""
super().__init__(client, boiler)
self._name = name
self._device_class = DEVICE_CLASS_TEMPERATURE
self._unit_of_measurement = TEMP_CELSIUS
@property
def state(self):
"""Return the state of the sensor."""
return self._boiler.status[INTOUCH_MAP_ATTRS[self._name][0]]
@property
def device_state_attributes(self):
"""Return the device state attributes."""
key = INTOUCH_MAP_ATTRS[self._name][1]
return {key: self._boiler.status[key]}

View File

@ -2,8 +2,10 @@
import asyncio
import logging
from aiohttp import ClientResponseError
from homeassistant.components.water_heater import WaterHeaterDevice
from homeassistant.const import TEMP_CELSIUS
from homeassistant.helpers.dispatcher import async_dispatcher_send
from . import DOMAIN
@ -16,8 +18,8 @@ HEATER_MIN_TEMP = 30.0
HEATER_NAME = 'Boiler'
HEATER_ATTRS = [
'display_code', 'display_text', 'fault_code', 'is_burning', 'is_failed',
'is_pumping', 'is_tapping', 'heater_temp', 'tap_temp', 'pressure']
'display_code', 'display_text', 'is_burning',
'rf_message_rssi', 'nodenr', 'rfstatus_cntr']
async def async_setup_platform(hass, hass_config, async_add_entities,
@ -43,6 +45,11 @@ class IncomfortWaterHeater(WaterHeaterDevice):
"""Return the name of the water_heater device."""
return HEATER_NAME
@property
def icon(self):
"""Return the icon of the water_heater device."""
return "mdi:oil-temperature"
@property
def device_state_attributes(self):
"""Return the device state attributes."""
@ -55,7 +62,9 @@ class IncomfortWaterHeater(WaterHeaterDevice):
"""Return the current temperature."""
if self._heater.is_tapping:
return self._heater.tap_temp
if self._heater.is_pumping:
return self._heater.heater_temp
return max(self._heater.heater_temp, self._heater.tap_temp)
@property
def min_temp(self):
@ -81,7 +90,7 @@ class IncomfortWaterHeater(WaterHeaterDevice):
def current_operation(self):
"""Return the current operation mode."""
if self._heater.is_failed:
return "Failed ({})".format(self._heater.fault_code)
return "Fault code: {}".format(self._heater.fault_code)
return self._heater.display_text
@ -90,5 +99,7 @@ class IncomfortWaterHeater(WaterHeaterDevice):
try:
await self._heater.update()
except (AssertionError, asyncio.TimeoutError) as err:
_LOGGER.warning("Update failed, message: %s", err)
except (ClientResponseError, asyncio.TimeoutError) as err:
_LOGGER.warning("Update failed, message is: %s", err)
async_dispatcher_send(self.hass, DOMAIN)

View File

@ -346,6 +346,7 @@ LENGTH_MILES = 'mi' # type: str
# Pressure units
PRESSURE_PA = 'Pa' # type: str
PRESSURE_HPA = 'hPa' # type: str
PRESSURE_BAR = 'bar' # type: str
PRESSURE_MBAR = 'mbar' # type: str
PRESSURE_INHG = 'inHg' # type: str
PRESSURE_PSI = 'psi' # type: str