From 33c35a6c3c3675a16dae509c3df821ba1b1c3930 Mon Sep 17 00:00:00 2001 From: David Bonnes Date: Tue, 20 Aug 2019 19:43:39 +0200 Subject: [PATCH] Bump geniushub client (#26084) * bump geniushub client * delint * remove unsused lint hints --- .../components/geniushub/__init__.py | 54 +++++++++--- .../components/geniushub/binary_sensor.py | 44 +++------- homeassistant/components/geniushub/climate.py | 29 ++---- .../components/geniushub/manifest.json | 2 +- homeassistant/components/geniushub/sensor.py | 88 +++++-------------- .../components/geniushub/water_heater.py | 62 ++++++------- requirements_all.txt | 2 +- 7 files changed, 113 insertions(+), 168 deletions(-) diff --git a/homeassistant/components/geniushub/__init__.py b/homeassistant/components/geniushub/__init__.py index e4b723d595b..45f3f91cd6d 100644 --- a/homeassistant/components/geniushub/__init__.py +++ b/homeassistant/components/geniushub/__init__.py @@ -1,17 +1,23 @@ """Support for a Genius Hub system.""" from datetime import timedelta import logging +from typing import Awaitable import aiohttp import voluptuous as vol -from geniushubclient import GeniusHubClient +from geniushubclient import GeniusHub from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_TOKEN, CONF_USERNAME +from homeassistant.core import callback 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 -from homeassistant.helpers.dispatcher import async_dispatcher_send +from homeassistant.helpers.dispatcher import ( + async_dispatcher_send, + async_dispatcher_connect, +) +from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import async_track_time_interval _LOGGER = logging.getLogger(__name__) @@ -45,7 +51,7 @@ async def async_setup(hass, hass_config): broker = GeniusBroker(hass, args, kwargs) try: - await broker._client.hub.update() # pylint: disable=protected-access + await broker.client.update() except aiohttp.ClientResponseError as err: _LOGGER.error("Setup failed, check your configuration, %s", err) return False @@ -58,7 +64,7 @@ async def async_setup(hass, hass_config): async_load_platform(hass, platform, DOMAIN, {}, hass_config) ) - if broker._client.api_version == 3: # pylint: disable=protected-access + if broker.client.api_version == 3: # pylint: disable=no-member for platform in ["sensor", "binary_sensor"]: hass.async_create_task( async_load_platform(hass, platform, DOMAIN, {}, hass_config) @@ -72,27 +78,53 @@ class GeniusBroker: def __init__(self, hass, args, kwargs): """Initialize the geniushub client.""" - self._hass = hass - self._client = hass.data[DOMAIN]["client"] = GeniusHubClient( + self.hass = hass + self.client = hass.data[DOMAIN]["client"] = GeniusHub( *args, **kwargs, session=async_get_clientsession(hass) ) async def async_update(self, now, **kwargs): """Update the geniushub client's data.""" try: - await self._client.hub.update() + await self.client.update() except aiohttp.ClientResponseError as err: _LOGGER.warning("Update failed, %s", err) return self.make_debug_log_entries() - async_dispatcher_send(self._hass, DOMAIN) + 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, + "Raw JSON: \n\nclient._zones = %s \n\nclient._devices = %s", + self.client._zones, + self.client._devices, ) + + +class GeniusEntity(Entity): + """Base for all Genius Hub endtities.""" + + def __init__(self): + """Initialize the entity.""" + self._name = None + + async def async_added_to_hass(self) -> Awaitable[None]: + """Set up a listener when this entity is added to HA.""" + async_dispatcher_connect(self.hass, DOMAIN, self._refresh) + + @callback + def _refresh(self) -> None: + self.async_schedule_update_ha_state(force_refresh=True) + + @property + def name(self) -> str: + """Return the name of the geniushub entity.""" + return self._name + + @property + def should_poll(self) -> bool: + """Return False as geniushub entities should not be polled.""" + return False diff --git a/homeassistant/components/geniushub/binary_sensor.py b/homeassistant/components/geniushub/binary_sensor.py index feb2e0da33e..1cc8cd3f406 100644 --- a/homeassistant/components/geniushub/binary_sensor.py +++ b/homeassistant/components/geniushub/binary_sensor.py @@ -1,10 +1,10 @@ """Support for Genius Hub binary_sensor devices.""" +from typing import Any, Dict + from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.core import callback -from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.util.dt import utc_from_timestamp -from . import DOMAIN +from . import DOMAIN, GeniusEntity GH_IS_SWITCH = ["Dual Channel Receiver", "Electric Switch", "Smart Plug"] @@ -14,58 +14,38 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= client = hass.data[DOMAIN]["client"] switches = [ - GeniusBinarySensor(client, d) - for d in client.hub.device_objs - if d.type[:21] in GH_IS_SWITCH + GeniusBinarySensor(d) for d in client.device_objs if d.type[:21] in GH_IS_SWITCH ] async_add_entities(switches) -class GeniusBinarySensor(BinarySensorDevice): +class GeniusBinarySensor(GeniusEntity, BinarySensorDevice): """Representation of a Genius Hub binary_sensor.""" - def __init__(self, client, device): + def __init__(self, device) -> None: """Initialize the binary sensor.""" - self._client = client - self._device = device + super().__init__() + self._device = device if device.type[:21] == "Dual Channel Receiver": self._name = "Dual Channel Receiver {}".format(device.id) else: self._name = "{} {}".format(device.type, device.id) - 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 should_poll(self) -> bool: - """Return False as the geniushub devices should not be polled.""" - return False - - @property - def is_on(self): + def is_on(self) -> bool: """Return the status of the sensor.""" return self._device.data["state"]["outputOnOff"] @property - def device_state_attributes(self): + def device_state_attributes(self) -> Dict[str, Any]: """Return the device state attributes.""" attrs = {} attrs["assigned_zone"] = self._device.data["assignedZones"][0]["name"] - # noqa; pylint: disable=protected-access - last_comms = self._device._raw_data["childValues"]["lastComms"]["val"] + # pylint: disable=protected-access + last_comms = self._device._raw["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 cee737c09f8..a856e48438f 100644 --- a/homeassistant/components/geniushub/climate.py +++ b/homeassistant/components/geniushub/climate.py @@ -11,10 +11,8 @@ from homeassistant.components.climate.const import ( SUPPORT_PRESET_MODE, ) from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS -from homeassistant.core import callback -from homeassistant.helpers.dispatcher import async_dispatcher_connect -from . import DOMAIN +from . import DOMAIN, GeniusEntity ATTR_DURATION = "duration" @@ -38,32 +36,24 @@ async def async_setup_platform( client = hass.data[DOMAIN]["client"] entities = [ - GeniusClimateZone(client, z) for z in client.hub.zone_objs if z.type in GH_ZONES + GeniusClimateZone(z) for z in client.zone_objs if z.data["type"] in GH_ZONES ] async_add_entities(entities) -class GeniusClimateZone(ClimateDevice): +class GeniusClimateZone(GeniusEntity, ClimateDevice): """Representation of a Genius Hub climate device.""" - def __init__(self, client, zone): + def __init__(self, zone) -> None: """Initialize the climate device.""" - self._client = client - self._zone = zone + super().__init__() + self._zone = zone if hasattr(self._zone, "occupied"): # has a movement sensor self._preset_modes = list(HA_PRESET_TO_GH) else: self._preset_modes = [PRESET_BOOST] - async def async_added_to_hass(self) -> Awaitable[None]: - """Run when entity about to be added.""" - async_dispatcher_connect(self.hass, DOMAIN, self._refresh) - - @callback - def _refresh(self) -> None: - self.async_schedule_update_ha_state(force_refresh=True) - @property def name(self) -> str: """Return the name of the climate device.""" @@ -75,11 +65,6 @@ class GeniusClimateZone(ClimateDevice): tmp = self._zone.data.items() return {"status": {k: v for k, v in tmp if k in GH_STATE_ATTRS}} - @property - def should_poll(self) -> bool: - """Return False as the geniushub devices should not be polled.""" - return False - @property def icon(self) -> str: """Return the icon to use in the frontend UI.""" @@ -91,7 +76,7 @@ class GeniusClimateZone(ClimateDevice): return self._zone.data["temperature"] @property - def target_temperature(self) -> Optional[float]: + def target_temperature(self) -> float: """Return the temperature we try to reach.""" return self._zone.data["setpoint"] diff --git a/homeassistant/components/geniushub/manifest.json b/homeassistant/components/geniushub/manifest.json index 0721c4ff389..12f7c266840 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.8" + "geniushub-client==0.6.5" ], "dependencies": [], "codeowners": ["@zxdavb"] diff --git a/homeassistant/components/geniushub/sensor.py b/homeassistant/components/geniushub/sensor.py index 65bfcb7fe9b..5e39be1620a 100644 --- a/homeassistant/components/geniushub/sensor.py +++ b/homeassistant/components/geniushub/sensor.py @@ -1,13 +1,11 @@ """Support for Genius Hub sensor devices.""" from datetime import timedelta +from typing import Any, Awaitable, Dict from homeassistant.const import DEVICE_CLASS_BATTERY -from homeassistant.core import callback -from homeassistant.helpers.dispatcher import async_dispatcher_connect -from homeassistant.helpers.entity import Entity from homeassistant.util.dt import utc_from_timestamp, utcnow -from . import DOMAIN +from . import DOMAIN, GeniusEntity GH_HAS_BATTERY = ["Room Thermostat", "Genius Valve", "Room Sensor", "Radiator Valve"] @@ -22,44 +20,27 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= """Set up the Genius Hub sensor entities.""" client = hass.data[DOMAIN]["client"] - sensors = [ - GeniusBattery(client, d) - for d in client.hub.device_objs - if d.type in GH_HAS_BATTERY - ] + sensors = [GeniusBattery(d) for d in client.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 GeniusBattery(Entity): +class GeniusBattery(GeniusEntity): """Representation of a Genius Hub sensor.""" - def __init__(self, client, device): + def __init__(self, device) -> None: """Initialize the sensor.""" - self._client = client - self._device = device + super().__init__() + self._device = device self._name = "{} {}".format(device.type, device.id) - 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 icon(self): + def icon(self) -> str: """Return the icon of the sensor.""" - # noqa; pylint: disable=protected-access - values = self._device._raw_data["childValues"] + + values = self._device._raw["childValues"] # pylint: disable=protected-access last_comms = utc_from_timestamp(values["lastComms"]["val"]) if "WakeUp_Interval" in values: @@ -83,78 +64,57 @@ class GeniusBattery(Entity): return icon @property - def device_class(self): + def device_class(self) -> str: """Return the device class of the sensor.""" return DEVICE_CLASS_BATTERY @property - def unit_of_measurement(self): + def unit_of_measurement(self) -> str: """Return the unit of measurement of the sensor.""" return "%" @property - def should_poll(self) -> bool: - """Return False as the geniushub devices should not be polled.""" - return False - - @property - def state(self): + def state(self) -> str: """Return the state of the sensor.""" level = self._device.data["state"].get("batteryLevel", 255) return level if level != 255 else 0 @property - def device_state_attributes(self): + def device_state_attributes(self) -> Dict[str, Any]: """Return the device state attributes.""" attrs = {} attrs["assigned_zone"] = self._device.data["assignedZones"][0]["name"] - # noqa; pylint: disable=protected-access - last_comms = self._device._raw_data["childValues"]["lastComms"]["val"] + # pylint: disable=protected-access + last_comms = self._device._raw["childValues"]["lastComms"]["val"] attrs["last_comms"] = utc_from_timestamp(last_comms).isoformat() return {**attrs} -class GeniusIssue(Entity): +class GeniusIssue(GeniusEntity): """Representation of a Genius Hub sensor.""" - def __init__(self, client, level): + def __init__(self, hub, level) -> None: """Initialize the sensor.""" - self._hub = client.hub + super().__init__() + + self._hub = hub self._name = GH_LEVEL_MAPPING[level] self._level = level self._issues = [] - 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 should_poll(self) -> bool: - """Return False as the geniushub devices should not be polled.""" - return False - - @property - def state(self): + def state(self) -> str: """Return the number of issues.""" return len(self._issues) @property - def device_state_attributes(self): + def device_state_attributes(self) -> Dict[str, Any]: """Return the device state attributes.""" return {"{}_list".format(self._level): self._issues} - async def async_update(self): + async def async_update(self) -> Awaitable[None]: """Process the sensor's state data.""" self._issues = [ i["description"] for i in self._hub.issues if i["level"] == self._level diff --git a/homeassistant/components/geniushub/water_heater.py b/homeassistant/components/geniushub/water_heater.py index feb4235d4dd..1086160e77c 100644 --- a/homeassistant/components/geniushub/water_heater.py +++ b/homeassistant/components/geniushub/water_heater.py @@ -1,14 +1,14 @@ """Support for Genius Hub water_heater devices.""" +from typing import Any, Awaitable, Dict, Optional, List + from homeassistant.components.water_heater import ( WaterHeaterDevice, SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE, ) from homeassistant.const import ATTR_TEMPERATURE, STATE_OFF, TEMP_CELSIUS -from homeassistant.core import callback -from homeassistant.helpers.dispatcher import async_dispatcher_connect -from . import DOMAIN +from . import DOMAIN, GeniusEntity STATE_AUTO = "auto" STATE_MANUAL = "manual" @@ -44,93 +44,81 @@ async def async_setup_platform( client = hass.data[DOMAIN]["client"] entities = [ - GeniusWaterHeater(client, z) - for z in client.hub.zone_objs - if z.type in GH_HEATERS + GeniusWaterHeater(z) for z in client.zone_objs if z.data["type"] in GH_HEATERS ] async_add_entities(entities) -class GeniusWaterHeater(WaterHeaterDevice): +class GeniusWaterHeater(GeniusEntity, WaterHeaterDevice): """Representation of a Genius Hub water_heater device.""" - def __init__(self, client, boiler): + def __init__(self, boiler) -> None: """Initialize the water_heater device.""" - self._client = client - self._boiler = boiler + super().__init__() + self._boiler = boiler self._operation_list = list(HA_OPMODE_TO_GH) - async def async_added_to_hass(self): - """Run when entity about to be added.""" - 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): + def name(self) -> str: """Return the name of the water_heater device.""" return self._boiler.name @property - def device_state_attributes(self): + def device_state_attributes(self) -> Dict[str, Any]: """Return the device state attributes.""" - tmp = self._boiler.data.items() - return {"status": {k: v for k, v in tmp if k in GH_STATE_ATTRS}} + return { + "status": { + k: v for k, v in self._boiler.data.items() if k in GH_STATE_ATTRS + } + } @property - def should_poll(self) -> bool: - """Return False as the geniushub devices should not be polled.""" - return False - - @property - def current_temperature(self): + def current_temperature(self) -> Optional[float]: """Return the current temperature.""" return self._boiler.data.get("temperature") @property - def target_temperature(self): + def target_temperature(self) -> float: """Return the temperature we try to reach.""" return self._boiler.data["setpoint"] @property - def min_temp(self): + def min_temp(self) -> float: """Return max valid temperature that can be set.""" return GH_MIN_TEMP @property - def max_temp(self): + def max_temp(self) -> float: """Return max valid temperature that can be set.""" return GH_MAX_TEMP @property - def temperature_unit(self): + def temperature_unit(self) -> str: """Return the unit of measurement.""" return TEMP_CELSIUS @property - def supported_features(self): + def supported_features(self) -> int: """Return the list of supported features.""" return GH_SUPPORT_FLAGS @property - def operation_list(self): + def operation_list(self) -> List[str]: """Return the list of available operation modes.""" return self._operation_list @property - def current_operation(self): + def current_operation(self) -> str: """Return the current operation mode.""" return GH_STATE_TO_HA[self._boiler.data["mode"]] - async def async_set_operation_mode(self, operation_mode): + async def async_set_operation_mode(self, operation_mode) -> Awaitable[None]: """Set a new operation mode for this boiler.""" await self._boiler.set_mode(HA_OPMODE_TO_GH[operation_mode]) - async def async_set_temperature(self, **kwargs): + async def async_set_temperature(self, **kwargs) -> Awaitable[None]: """Set a new target temperature for this boiler.""" temperature = kwargs[ATTR_TEMPERATURE] await self._boiler.set_override(temperature, 3600) # 1 hour diff --git a/requirements_all.txt b/requirements_all.txt index 746c23bc28a..657a7912159 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -518,7 +518,7 @@ gearbest_parser==1.0.7 geizhals==0.0.9 # homeassistant.components.geniushub -geniushub-client==0.5.8 +geniushub-client==0.6.5 # homeassistant.components.geo_json_events # homeassistant.components.nsw_rural_fire_service_feed