From 7181d639fd236ddd46af64780d9da335cd3ce138 Mon Sep 17 00:00:00 2001 From: David Bonnes Date: Tue, 7 May 2019 22:53:55 +0100 Subject: [PATCH] Add Intergas InComfort Lan2RF gateway (#23736) * fixed __init__.py * add sensors * switch to parent-child architecture * make binary_sensor the parent * revert parent - to water_heater * first working version * working, delinted (except TODO) * update to latest client library * remove debug code * delint * tweak device_state_attributes * tweak device_state_attrbutes * minor tweaks * bump client library for bugfix * improve state attributes for pumping * update .coverage * bugfix - binary sensors not updating * rename to incomfort from intouch * fix coveragerc regression * bump client (bugfix for /protected URL) * bump client (bugfix for /protected URL) 2 * bump client * remove debug code * ready for PR * fix regression * use xx._boiler instead of xx._objref * improve current_temperature and delint * use current_operation instead of state * refactor vol.Schema * remove unneeded instance attribute * remove unneeded instance attribute 2 * refactor device_state_attributes * change 'boiler' to 'heater' * change 'boiler' to 'heater' 2 * correct a typo * bugfix: add missing comma * small tidy-up --- .coveragerc | 1 + CODEOWNERS | 1 + .../components/incomfort/__init__.py | 50 ++++++++++ .../components/incomfort/manifest.json | 12 +++ .../components/incomfort/water_heater.py | 94 +++++++++++++++++++ requirements_all.txt | 3 + 6 files changed, 161 insertions(+) create mode 100644 homeassistant/components/incomfort/__init__.py create mode 100644 homeassistant/components/incomfort/manifest.json create mode 100644 homeassistant/components/incomfort/water_heater.py diff --git a/.coveragerc b/.coveragerc index 21cf4a9e5ad..2b5f328466c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -278,6 +278,7 @@ omit = homeassistant/components/imap_email_content/sensor.py homeassistant/components/influxdb/sensor.py homeassistant/components/insteon/* + homeassistant/components/incomfort/* homeassistant/components/ios/* homeassistant/components/iota/* homeassistant/components/iperf3/* diff --git a/CODEOWNERS b/CODEOWNERS index 069826dd071..90fb72378bc 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -113,6 +113,7 @@ homeassistant/components/huawei_lte/* @scop homeassistant/components/huawei_router/* @abmantis homeassistant/components/hue/* @balloob homeassistant/components/ign_sismologia/* @exxamalte +homeassistant/components/incomfort/* @zxdavb homeassistant/components/influxdb/* @fabaff homeassistant/components/input_boolean/* @home-assistant/core homeassistant/components/input_datetime/* @home-assistant/core diff --git a/homeassistant/components/incomfort/__init__.py b/homeassistant/components/incomfort/__init__.py new file mode 100644 index 00000000000..edff8c8299f --- /dev/null +++ b/homeassistant/components/incomfort/__init__.py @@ -0,0 +1,50 @@ +"""Support for an Intergas boiler via an InComfort/Intouch Lan2RF gateway.""" +import logging + +import voluptuous as vol +from incomfortclient import Gateway as InComfortGateway + +from homeassistant.const import ( + CONF_HOST, CONF_PASSWORD, CONF_USERNAME) +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.discovery import async_load_platform + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = 'incomfort' + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_HOST): cv.string, + vol.Inclusive(CONF_USERNAME, 'credentials'): cv.string, + vol.Inclusive(CONF_PASSWORD, 'credentials'): cv.string, + }) +}, extra=vol.ALLOW_EXTRA) + + +async def async_setup(hass, hass_config): + """Create an Intergas InComfort/Intouch system.""" + incomfort_data = hass.data[DOMAIN] = {} + + credentials = dict(hass_config[DOMAIN]) + hostname = credentials.pop(CONF_HOST) + + try: + client = incomfort_data['client'] = InComfortGateway( + hostname, **credentials, session=async_get_clientsession(hass) + ) + + heater = incomfort_data['heater'] = list(await client.heaters)[0] + await heater.update() + + except AssertionError: # assert response.status == HTTP_OK + _LOGGER.warning( + "Setup failed, check your configuration.", + exc_info=True) + return False + + hass.async_create_task(async_load_platform( + hass, 'water_heater', DOMAIN, {}, hass_config)) + + return True diff --git a/homeassistant/components/incomfort/manifest.json b/homeassistant/components/incomfort/manifest.json new file mode 100644 index 00000000000..028a741a673 --- /dev/null +++ b/homeassistant/components/incomfort/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "incomfort", + "name": "Intergas InComfort/Intouch Lan2RF gateway", + "documentation": "https://www.home-assistant.io/components/incomfort", + "requirements": [ + "incomfort-client==0.2.8" + ], + "dependencies": [], + "codeowners": [ + "@zxdavb" + ] +} diff --git a/homeassistant/components/incomfort/water_heater.py b/homeassistant/components/incomfort/water_heater.py new file mode 100644 index 00000000000..9223902f5a3 --- /dev/null +++ b/homeassistant/components/incomfort/water_heater.py @@ -0,0 +1,94 @@ +"""Support for an Intergas boiler via an InComfort/Intouch Lan2RF gateway.""" +import asyncio +import logging + +from homeassistant.components.water_heater import WaterHeaterDevice +from homeassistant.const import TEMP_CELSIUS + +from . import DOMAIN + +_LOGGER = logging.getLogger(__name__) + +HEATER_SUPPORT_FLAGS = 0 + +HEATER_MAX_TEMP = 80.0 +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'] + + +async def async_setup_platform(hass, hass_config, async_add_entities, + discovery_info=None): + """Set up an InComfort/Intouch water_heater device.""" + client = hass.data[DOMAIN]['client'] + heater = hass.data[DOMAIN]['heater'] + + async_add_entities([ + IncomfortWaterHeater(client, heater)], update_before_add=True) + + +class IncomfortWaterHeater(WaterHeaterDevice): + """Representation of an InComfort/Intouch water_heater device.""" + + def __init__(self, client, heater): + """Initialize the water_heater device.""" + self._client = client + self._heater = heater + + @property + def name(self): + """Return the name of the water_heater device.""" + return HEATER_NAME + + @property + def device_state_attributes(self): + """Return the device state attributes.""" + state = {k: self._heater.status[k] + for k in self._heater.status if k in HEATER_ATTRS} + return state + + @property + def current_temperature(self): + """Return the current temperature.""" + if self._heater.is_tapping: + return self._heater.tap_temp + return self._heater.heater_temp + + @property + def min_temp(self): + """Return max valid temperature that can be set.""" + return HEATER_MIN_TEMP + + @property + def max_temp(self): + """Return max valid temperature that can be set.""" + return HEATER_MAX_TEMP + + @property + def temperature_unit(self): + """Return the unit of measurement.""" + return TEMP_CELSIUS + + @property + def supported_features(self): + """Return the list of supported features.""" + return HEATER_SUPPORT_FLAGS + + @property + def current_operation(self): + """Return the current operation mode.""" + if self._heater.is_failed: + return "Failed ({})".format(self._heater.fault_code) + + return self._heater.display_text + + async def async_update(self): + """Get the latest state data from the gateway.""" + try: + await self._heater.update() + + except (AssertionError, asyncio.TimeoutError) as err: + _LOGGER.warning("Update failed, message: %s", err) diff --git a/requirements_all.txt b/requirements_all.txt index 7d1d17fcd07..cf60d4298d8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -601,6 +601,9 @@ iglo==1.2.7 # homeassistant.components.ihc ihcsdk==2.3.0 +# homeassistant.components.incomfort +incomfort-client==0.2.8 + # homeassistant.components.influxdb influxdb==5.2.0