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
This commit is contained in:
David Bonnes 2019-08-04 23:06:36 +01:00 committed by Martin Hjelmare
parent 0d95ad3857
commit b0c79c271d
7 changed files with 50 additions and 79 deletions

View file

@ -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,
)

View file

@ -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()

View file

@ -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]]:

View file

@ -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"]

View file

@ -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}

View file

@ -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."""

View file

@ -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