From b0c79c271d7246acb5844a8e85e241d3d6535b68 Mon Sep 17 00:00:00 2001 From: David Bonnes Date: Sun, 4 Aug 2019 23:06:36 +0100 Subject: [PATCH] Bump geniushub client, handle dead devices, handle raise_for_status (#25687) * Initial commit * tweak error logging * bump client * correct regression * small coding tweak * debug logging to one entry * refactor for self.data['attr'] * bump client * small tidy-up --- .../components/geniushub/__init__.py | 53 ++++++++----------- .../components/geniushub/binary_sensor.py | 15 +++--- homeassistant/components/geniushub/climate.py | 24 ++++----- .../components/geniushub/manifest.json | 2 +- homeassistant/components/geniushub/sensor.py | 18 +++---- .../components/geniushub/water_heater.py | 15 ++---- requirements_all.txt | 2 +- 7 files changed, 50 insertions(+), 79 deletions(-) diff --git a/homeassistant/components/geniushub/__init__.py b/homeassistant/components/geniushub/__init__.py index 3bbec4258bc..e4b723d595b 100644 --- a/homeassistant/components/geniushub/__init__.py +++ b/homeassistant/components/geniushub/__init__.py @@ -2,6 +2,7 @@ from datetime import timedelta import logging +import aiohttp import voluptuous as vol from geniushubclient import GeniusHubClient @@ -41,32 +42,23 @@ async def async_setup(hass, hass_config): args = (kwargs.pop(CONF_TOKEN),) hass.data[DOMAIN] = {} - data = hass.data[DOMAIN]["data"] = GeniusData(hass, args, kwargs) + broker = GeniusBroker(hass, args, kwargs) + try: - await data._client.hub.update() # pylint: disable=protected-access - except AssertionError: # assert response.status == HTTP_OK - _LOGGER.warning("Setup failed, check your configuration.", exc_info=True) + await broker._client.hub.update() # pylint: disable=protected-access + except aiohttp.ClientResponseError as err: + _LOGGER.error("Setup failed, check your configuration, %s", err) return False + broker.make_debug_log_entries() - _LOGGER.debug( - # noqa; pylint: disable=protected-access - "zones_raw = %s", - data._client.hub._zones_raw, - ) - _LOGGER.debug( - # noqa; pylint: disable=protected-access - "devices_raw = %s", - data._client.hub._devices_raw, - ) - - async_track_time_interval(hass, data.async_update, SCAN_INTERVAL) + async_track_time_interval(hass, broker.async_update, SCAN_INTERVAL) for platform in ["climate", "water_heater"]: hass.async_create_task( async_load_platform(hass, platform, DOMAIN, {}, hass_config) ) - if data._client.api_version == 3: # pylint: disable=protected-access + if broker._client.api_version == 3: # pylint: disable=protected-access for platform in ["sensor", "binary_sensor"]: hass.async_create_task( async_load_platform(hass, platform, DOMAIN, {}, hass_config) @@ -75,7 +67,7 @@ async def async_setup(hass, hass_config): return True -class GeniusData: +class GeniusBroker: """Container for geniushub client and data.""" def __init__(self, hass, args, kwargs): @@ -89,19 +81,18 @@ class GeniusData: """Update the geniushub client's data.""" try: await self._client.hub.update() - except AssertionError: # assert response.status == HTTP_OK - _LOGGER.warning("Update failed.", exc_info=True) + except aiohttp.ClientResponseError as err: + _LOGGER.warning("Update failed, %s", err) return - - _LOGGER.debug( - # noqa; pylint: disable=protected-access - "zones_raw = %s", - self._client.hub._zones_raw, - ) - _LOGGER.debug( - # noqa; pylint: disable=protected-access - "devices_raw = %s", - self._client.hub._devices_raw, - ) + self.make_debug_log_entries() async_dispatcher_send(self._hass, DOMAIN) + + def make_debug_log_entries(self): + """Make any useful debug log entries.""" + # pylint: disable=protected-access + _LOGGER.debug( + "Raw JSON: \n\nhub._raw_zones = %s \n\nhub._raw_devices = %s", + self._client.hub._raw_zones, + self._client.hub._raw_devices, + ) diff --git a/homeassistant/components/geniushub/binary_sensor.py b/homeassistant/components/geniushub/binary_sensor.py index afdc0ef5f89..feb2e0da33e 100644 --- a/homeassistant/components/geniushub/binary_sensor.py +++ b/homeassistant/components/geniushub/binary_sensor.py @@ -1,6 +1,4 @@ """Support for Genius Hub binary_sensor devices.""" -import logging - from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -8,8 +6,6 @@ from homeassistant.util.dt import utc_from_timestamp from . import DOMAIN -_LOGGER = logging.getLogger(__name__) - GH_IS_SWITCH = ["Dual Channel Receiver", "Electric Switch", "Smart Plug"] @@ -17,9 +13,10 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= """Set up the Genius Hub sensor entities.""" client = hass.data[DOMAIN]["client"] - devices = [d for d in client.hub.device_objs if d.type is not None] switches = [ - GeniusBinarySensor(client, d) for d in devices if d.type[:21] in GH_IS_SWITCH + GeniusBinarySensor(client, d) + for d in client.hub.device_objs + if d.type[:21] in GH_IS_SWITCH ] async_add_entities(switches) @@ -59,16 +56,16 @@ class GeniusBinarySensor(BinarySensorDevice): @property def is_on(self): """Return the status of the sensor.""" - return self._device.state["outputOnOff"] + return self._device.data["state"]["outputOnOff"] @property def device_state_attributes(self): """Return the device state attributes.""" attrs = {} - attrs["assigned_zone"] = self._device.assignedZones[0]["name"] + attrs["assigned_zone"] = self._device.data["assignedZones"][0]["name"] # noqa; pylint: disable=protected-access - last_comms = self._device._raw_json["childValues"]["lastComms"]["val"] + last_comms = self._device._raw_data["childValues"]["lastComms"]["val"] if last_comms != 0: attrs["last_comms"] = utc_from_timestamp(last_comms).isoformat() diff --git a/homeassistant/components/geniushub/climate.py b/homeassistant/components/geniushub/climate.py index ae1d714dd2b..cee737c09f8 100644 --- a/homeassistant/components/geniushub/climate.py +++ b/homeassistant/components/geniushub/climate.py @@ -1,5 +1,4 @@ """Support for Genius Hub climate devices.""" -import logging from typing import Any, Awaitable, Dict, Optional, List from homeassistant.components.climate import ClimateDevice @@ -17,8 +16,6 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from . import DOMAIN -_LOGGER = logging.getLogger(__name__) - ATTR_DURATION = "duration" GH_ZONES = ["radiator"] @@ -40,13 +37,10 @@ async def async_setup_platform( """Set up the Genius Hub climate entities.""" client = hass.data[DOMAIN]["client"] - async_add_entities( - [ - GeniusClimateZone(client, z) - for z in client.hub.zone_objs - if z.type in GH_ZONES - ] - ) + entities = [ + GeniusClimateZone(client, z) for z in client.hub.zone_objs if z.type in GH_ZONES + ] + async_add_entities(entities) class GeniusClimateZone(ClimateDevice): @@ -78,7 +72,7 @@ class GeniusClimateZone(ClimateDevice): @property def device_state_attributes(self) -> Dict[str, Any]: """Return the device state attributes.""" - tmp = self._zone.__dict__.items() + tmp = self._zone.data.items() return {"status": {k: v for k, v in tmp if k in GH_STATE_ATTRS}} @property @@ -94,12 +88,12 @@ class GeniusClimateZone(ClimateDevice): @property def current_temperature(self) -> Optional[float]: """Return the current temperature.""" - return self._zone.temperature + return self._zone.data["temperature"] @property def target_temperature(self) -> Optional[float]: """Return the temperature we try to reach.""" - return self._zone.setpoint + return self._zone.data["setpoint"] @property def min_temp(self) -> float: @@ -124,7 +118,7 @@ class GeniusClimateZone(ClimateDevice): @property def hvac_mode(self) -> str: """Return hvac operation ie. heat, cool mode.""" - return GH_HVAC_TO_HA.get(self._zone.mode, HVAC_MODE_HEAT) + return GH_HVAC_TO_HA.get(self._zone.data["mode"], HVAC_MODE_HEAT) @property def hvac_modes(self) -> List[str]: @@ -134,7 +128,7 @@ class GeniusClimateZone(ClimateDevice): @property def preset_mode(self) -> Optional[str]: """Return the current preset mode, e.g., home, away, temp.""" - return GH_PRESET_TO_HA.get(self._zone.mode) + return GH_PRESET_TO_HA.get(self._zone.data["mode"]) @property def preset_modes(self) -> Optional[List[str]]: diff --git a/homeassistant/components/geniushub/manifest.json b/homeassistant/components/geniushub/manifest.json index 98145ea0944..0721c4ff389 100644 --- a/homeassistant/components/geniushub/manifest.json +++ b/homeassistant/components/geniushub/manifest.json @@ -3,7 +3,7 @@ "name": "Genius Hub", "documentation": "https://www.home-assistant.io/components/geniushub", "requirements": [ - "geniushub-client==0.5.4" + "geniushub-client==0.5.8" ], "dependencies": [], "codeowners": ["@zxdavb"] diff --git a/homeassistant/components/geniushub/sensor.py b/homeassistant/components/geniushub/sensor.py index f87c957d3da..65bfcb7fe9b 100644 --- a/homeassistant/components/geniushub/sensor.py +++ b/homeassistant/components/geniushub/sensor.py @@ -1,6 +1,5 @@ """Support for Genius Hub sensor devices.""" from datetime import timedelta -import logging from homeassistant.const import DEVICE_CLASS_BATTERY from homeassistant.core import callback @@ -10,8 +9,6 @@ from homeassistant.util.dt import utc_from_timestamp, utcnow from . import DOMAIN -_LOGGER = logging.getLogger(__name__) - GH_HAS_BATTERY = ["Room Thermostat", "Genius Valve", "Room Sensor", "Radiator Valve"] GH_LEVEL_MAPPING = { @@ -26,17 +23,16 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= client = hass.data[DOMAIN]["client"] sensors = [ - GeniusDevice(client, d) + GeniusBattery(client, d) for d in client.hub.device_objs if d.type in GH_HAS_BATTERY ] - issues = [GeniusIssue(client, i) for i in list(GH_LEVEL_MAPPING)] async_add_entities(sensors + issues, update_before_add=True) -class GeniusDevice(Entity): +class GeniusBattery(Entity): """Representation of a Genius Hub sensor.""" def __init__(self, client, device): @@ -63,7 +59,7 @@ class GeniusDevice(Entity): def icon(self): """Return the icon of the sensor.""" # noqa; pylint: disable=protected-access - values = self._device._raw_json["childValues"] + values = self._device._raw_data["childValues"] last_comms = utc_from_timestamp(values["lastComms"]["val"]) if "WakeUp_Interval" in values: @@ -74,7 +70,7 @@ class GeniusDevice(Entity): if last_comms < utcnow() - interval * 3: return "mdi:battery-unknown" - battery_level = self._device.state["batteryLevel"] + battery_level = self._device.data["state"]["batteryLevel"] if battery_level == 255: return "mdi:battery-unknown" if battery_level < 40: @@ -104,17 +100,17 @@ class GeniusDevice(Entity): @property def state(self): """Return the state of the sensor.""" - level = self._device.state.get("batteryLevel", 255) + level = self._device.data["state"].get("batteryLevel", 255) return level if level != 255 else 0 @property def device_state_attributes(self): """Return the device state attributes.""" attrs = {} - attrs["assigned_zone"] = self._device.assignedZones[0]["name"] + attrs["assigned_zone"] = self._device.data["assignedZones"][0]["name"] # noqa; pylint: disable=protected-access - last_comms = self._device._raw_json["childValues"]["lastComms"]["val"] + last_comms = self._device._raw_data["childValues"]["lastComms"]["val"] attrs["last_comms"] = utc_from_timestamp(last_comms).isoformat() return {**attrs} diff --git a/homeassistant/components/geniushub/water_heater.py b/homeassistant/components/geniushub/water_heater.py index 9e27ec5f190..feb4235d4dd 100644 --- a/homeassistant/components/geniushub/water_heater.py +++ b/homeassistant/components/geniushub/water_heater.py @@ -1,6 +1,4 @@ """Support for Genius Hub water_heater devices.""" -import logging - from homeassistant.components.water_heater import ( WaterHeaterDevice, SUPPORT_TARGET_TEMPERATURE, @@ -15,8 +13,6 @@ from . import DOMAIN STATE_AUTO = "auto" STATE_MANUAL = "manual" -_LOGGER = logging.getLogger(__name__) - GH_HEATERS = ["hot water temperature"] GH_SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE @@ -82,7 +78,7 @@ class GeniusWaterHeater(WaterHeaterDevice): @property def device_state_attributes(self): """Return the device state attributes.""" - tmp = self._boiler.__dict__.items() + tmp = self._boiler.data.items() return {"status": {k: v for k, v in tmp if k in GH_STATE_ATTRS}} @property @@ -93,15 +89,12 @@ class GeniusWaterHeater(WaterHeaterDevice): @property def current_temperature(self): """Return the current temperature.""" - try: - return self._boiler.temperature - except AttributeError: - return None + return self._boiler.data.get("temperature") @property def target_temperature(self): """Return the temperature we try to reach.""" - return self._boiler.setpoint + return self._boiler.data["setpoint"] @property def min_temp(self): @@ -131,7 +124,7 @@ class GeniusWaterHeater(WaterHeaterDevice): @property def current_operation(self): """Return the current operation mode.""" - return GH_STATE_TO_HA[self._boiler.mode] + return GH_STATE_TO_HA[self._boiler.data["mode"]] async def async_set_operation_mode(self, operation_mode): """Set a new operation mode for this boiler.""" diff --git a/requirements_all.txt b/requirements_all.txt index a37437b6330..2a610756ca1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -517,7 +517,7 @@ gearbest_parser==1.0.7 geizhals==0.0.9 # homeassistant.components.geniushub -geniushub-client==0.5.4 +geniushub-client==0.5.8 # homeassistant.components.geo_json_events # homeassistant.components.nsw_rural_fire_service_feed