Bump geniushub client (#26084)

* bump geniushub client

* delint

* remove unsused lint hints
This commit is contained in:
David Bonnes 2019-08-20 19:43:39 +02:00 committed by Paulus Schoutsen
parent 97d3f49bb8
commit 33c35a6c3c
7 changed files with 113 additions and 168 deletions

View File

@ -1,17 +1,23 @@
"""Support for a Genius Hub system.""" """Support for a Genius Hub system."""
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Awaitable
import aiohttp import aiohttp
import voluptuous as vol 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.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 import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.discovery import async_load_platform 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 from homeassistant.helpers.event import async_track_time_interval
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -45,7 +51,7 @@ async def async_setup(hass, hass_config):
broker = GeniusBroker(hass, args, kwargs) broker = GeniusBroker(hass, args, kwargs)
try: try:
await broker._client.hub.update() # pylint: disable=protected-access await broker.client.update()
except aiohttp.ClientResponseError as err: except aiohttp.ClientResponseError as err:
_LOGGER.error("Setup failed, check your configuration, %s", err) _LOGGER.error("Setup failed, check your configuration, %s", err)
return False return False
@ -58,7 +64,7 @@ async def async_setup(hass, hass_config):
async_load_platform(hass, platform, DOMAIN, {}, 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"]: for platform in ["sensor", "binary_sensor"]:
hass.async_create_task( hass.async_create_task(
async_load_platform(hass, platform, DOMAIN, {}, hass_config) async_load_platform(hass, platform, DOMAIN, {}, hass_config)
@ -72,27 +78,53 @@ class GeniusBroker:
def __init__(self, hass, args, kwargs): def __init__(self, hass, args, kwargs):
"""Initialize the geniushub client.""" """Initialize the geniushub client."""
self._hass = hass self.hass = hass
self._client = hass.data[DOMAIN]["client"] = GeniusHubClient( self.client = hass.data[DOMAIN]["client"] = GeniusHub(
*args, **kwargs, session=async_get_clientsession(hass) *args, **kwargs, session=async_get_clientsession(hass)
) )
async def async_update(self, now, **kwargs): async def async_update(self, now, **kwargs):
"""Update the geniushub client's data.""" """Update the geniushub client's data."""
try: try:
await self._client.hub.update() await self.client.update()
except aiohttp.ClientResponseError as err: except aiohttp.ClientResponseError as err:
_LOGGER.warning("Update failed, %s", err) _LOGGER.warning("Update failed, %s", err)
return return
self.make_debug_log_entries() self.make_debug_log_entries()
async_dispatcher_send(self._hass, DOMAIN) async_dispatcher_send(self.hass, DOMAIN)
def make_debug_log_entries(self): def make_debug_log_entries(self):
"""Make any useful debug log entries.""" """Make any useful debug log entries."""
# pylint: disable=protected-access # pylint: disable=protected-access
_LOGGER.debug( _LOGGER.debug(
"Raw JSON: \n\nhub._raw_zones = %s \n\nhub._raw_devices = %s", "Raw JSON: \n\nclient._zones = %s \n\nclient._devices = %s",
self._client.hub._raw_zones, self.client._zones,
self._client.hub._raw_devices, 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

View File

@ -1,10 +1,10 @@
"""Support for Genius Hub binary_sensor devices.""" """Support for Genius Hub binary_sensor devices."""
from typing import Any, Dict
from homeassistant.components.binary_sensor import BinarySensorDevice 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 homeassistant.util.dt import utc_from_timestamp
from . import DOMAIN from . import DOMAIN, GeniusEntity
GH_IS_SWITCH = ["Dual Channel Receiver", "Electric Switch", "Smart Plug"] 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"] client = hass.data[DOMAIN]["client"]
switches = [ switches = [
GeniusBinarySensor(client, d) GeniusBinarySensor(d) for d in client.device_objs if d.type[:21] in GH_IS_SWITCH
for d in client.hub.device_objs
if d.type[:21] in GH_IS_SWITCH
] ]
async_add_entities(switches) async_add_entities(switches)
class GeniusBinarySensor(BinarySensorDevice): class GeniusBinarySensor(GeniusEntity, BinarySensorDevice):
"""Representation of a Genius Hub binary_sensor.""" """Representation of a Genius Hub binary_sensor."""
def __init__(self, client, device): def __init__(self, device) -> None:
"""Initialize the binary sensor.""" """Initialize the binary sensor."""
self._client = client super().__init__()
self._device = device
self._device = device
if device.type[:21] == "Dual Channel Receiver": if device.type[:21] == "Dual Channel Receiver":
self._name = "Dual Channel Receiver {}".format(device.id) self._name = "Dual Channel Receiver {}".format(device.id)
else: else:
self._name = "{} {}".format(device.type, device.id) 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 @property
def name(self): def is_on(self) -> bool:
"""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):
"""Return the status of the sensor.""" """Return the status of the sensor."""
return self._device.data["state"]["outputOnOff"] return self._device.data["state"]["outputOnOff"]
@property @property
def device_state_attributes(self): def device_state_attributes(self) -> Dict[str, Any]:
"""Return the device state attributes.""" """Return the device state attributes."""
attrs = {} attrs = {}
attrs["assigned_zone"] = self._device.data["assignedZones"][0]["name"] attrs["assigned_zone"] = self._device.data["assignedZones"][0]["name"]
# noqa; pylint: disable=protected-access # pylint: disable=protected-access
last_comms = self._device._raw_data["childValues"]["lastComms"]["val"] last_comms = self._device._raw["childValues"]["lastComms"]["val"]
if last_comms != 0: if last_comms != 0:
attrs["last_comms"] = utc_from_timestamp(last_comms).isoformat() attrs["last_comms"] = utc_from_timestamp(last_comms).isoformat()

View File

@ -11,10 +11,8 @@ from homeassistant.components.climate.const import (
SUPPORT_PRESET_MODE, SUPPORT_PRESET_MODE,
) )
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS 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" ATTR_DURATION = "duration"
@ -38,32 +36,24 @@ async def async_setup_platform(
client = hass.data[DOMAIN]["client"] client = hass.data[DOMAIN]["client"]
entities = [ 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) async_add_entities(entities)
class GeniusClimateZone(ClimateDevice): class GeniusClimateZone(GeniusEntity, ClimateDevice):
"""Representation of a Genius Hub climate device.""" """Representation of a Genius Hub climate device."""
def __init__(self, client, zone): def __init__(self, zone) -> None:
"""Initialize the climate device.""" """Initialize the climate device."""
self._client = client super().__init__()
self._zone = zone
self._zone = zone
if hasattr(self._zone, "occupied"): # has a movement sensor if hasattr(self._zone, "occupied"): # has a movement sensor
self._preset_modes = list(HA_PRESET_TO_GH) self._preset_modes = list(HA_PRESET_TO_GH)
else: else:
self._preset_modes = [PRESET_BOOST] 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 @property
def name(self) -> str: def name(self) -> str:
"""Return the name of the climate device.""" """Return the name of the climate device."""
@ -75,11 +65,6 @@ class GeniusClimateZone(ClimateDevice):
tmp = self._zone.data.items() tmp = self._zone.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 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 @property
def icon(self) -> str: def icon(self) -> str:
"""Return the icon to use in the frontend UI.""" """Return the icon to use in the frontend UI."""
@ -91,7 +76,7 @@ class GeniusClimateZone(ClimateDevice):
return self._zone.data["temperature"] return self._zone.data["temperature"]
@property @property
def target_temperature(self) -> Optional[float]: def target_temperature(self) -> float:
"""Return the temperature we try to reach.""" """Return the temperature we try to reach."""
return self._zone.data["setpoint"] return self._zone.data["setpoint"]

View File

@ -3,7 +3,7 @@
"name": "Genius Hub", "name": "Genius Hub",
"documentation": "https://www.home-assistant.io/components/geniushub", "documentation": "https://www.home-assistant.io/components/geniushub",
"requirements": [ "requirements": [
"geniushub-client==0.5.8" "geniushub-client==0.6.5"
], ],
"dependencies": [], "dependencies": [],
"codeowners": ["@zxdavb"] "codeowners": ["@zxdavb"]

View File

@ -1,13 +1,11 @@
"""Support for Genius Hub sensor devices.""" """Support for Genius Hub sensor devices."""
from datetime import timedelta from datetime import timedelta
from typing import Any, Awaitable, Dict
from homeassistant.const import DEVICE_CLASS_BATTERY 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 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"] 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.""" """Set up the Genius Hub sensor entities."""
client = hass.data[DOMAIN]["client"] client = hass.data[DOMAIN]["client"]
sensors = [ sensors = [GeniusBattery(d) for d in client.device_objs if d.type in GH_HAS_BATTERY]
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)] issues = [GeniusIssue(client, i) for i in list(GH_LEVEL_MAPPING)]
async_add_entities(sensors + issues, update_before_add=True) async_add_entities(sensors + issues, update_before_add=True)
class GeniusBattery(Entity): class GeniusBattery(GeniusEntity):
"""Representation of a Genius Hub sensor.""" """Representation of a Genius Hub sensor."""
def __init__(self, client, device): def __init__(self, device) -> None:
"""Initialize the sensor.""" """Initialize the sensor."""
self._client = client super().__init__()
self._device = device
self._device = device
self._name = "{} {}".format(device.type, device.id) 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 @property
def name(self): def icon(self) -> str:
"""Return the name of the sensor."""
return self._name
@property
def icon(self):
"""Return the icon of the sensor.""" """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"]) last_comms = utc_from_timestamp(values["lastComms"]["val"])
if "WakeUp_Interval" in values: if "WakeUp_Interval" in values:
@ -83,78 +64,57 @@ class GeniusBattery(Entity):
return icon return icon
@property @property
def device_class(self): def device_class(self) -> str:
"""Return the device class of the sensor.""" """Return the device class of the sensor."""
return DEVICE_CLASS_BATTERY return DEVICE_CLASS_BATTERY
@property @property
def unit_of_measurement(self): def unit_of_measurement(self) -> str:
"""Return the unit of measurement of the sensor.""" """Return the unit of measurement of the sensor."""
return "%" return "%"
@property @property
def should_poll(self) -> bool: def state(self) -> str:
"""Return False as the geniushub devices should not be polled."""
return False
@property
def state(self):
"""Return the state of the sensor.""" """Return the state of the sensor."""
level = self._device.data["state"].get("batteryLevel", 255) level = self._device.data["state"].get("batteryLevel", 255)
return level if level != 255 else 0 return level if level != 255 else 0
@property @property
def device_state_attributes(self): def device_state_attributes(self) -> Dict[str, Any]:
"""Return the device state attributes.""" """Return the device state attributes."""
attrs = {} attrs = {}
attrs["assigned_zone"] = self._device.data["assignedZones"][0]["name"] attrs["assigned_zone"] = self._device.data["assignedZones"][0]["name"]
# noqa; pylint: disable=protected-access # pylint: disable=protected-access
last_comms = self._device._raw_data["childValues"]["lastComms"]["val"] last_comms = self._device._raw["childValues"]["lastComms"]["val"]
attrs["last_comms"] = utc_from_timestamp(last_comms).isoformat() attrs["last_comms"] = utc_from_timestamp(last_comms).isoformat()
return {**attrs} return {**attrs}
class GeniusIssue(Entity): class GeniusIssue(GeniusEntity):
"""Representation of a Genius Hub sensor.""" """Representation of a Genius Hub sensor."""
def __init__(self, client, level): def __init__(self, hub, level) -> None:
"""Initialize the sensor.""" """Initialize the sensor."""
self._hub = client.hub super().__init__()
self._hub = hub
self._name = GH_LEVEL_MAPPING[level] self._name = GH_LEVEL_MAPPING[level]
self._level = level self._level = level
self._issues = [] 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 @property
def name(self): def state(self) -> str:
"""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):
"""Return the number of issues.""" """Return the number of issues."""
return len(self._issues) return len(self._issues)
@property @property
def device_state_attributes(self): def device_state_attributes(self) -> Dict[str, Any]:
"""Return the device state attributes.""" """Return the device state attributes."""
return {"{}_list".format(self._level): self._issues} 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.""" """Process the sensor's state data."""
self._issues = [ self._issues = [
i["description"] for i in self._hub.issues if i["level"] == self._level i["description"] for i in self._hub.issues if i["level"] == self._level

View File

@ -1,14 +1,14 @@
"""Support for Genius Hub water_heater devices.""" """Support for Genius Hub water_heater devices."""
from typing import Any, Awaitable, Dict, Optional, List
from homeassistant.components.water_heater import ( from homeassistant.components.water_heater import (
WaterHeaterDevice, WaterHeaterDevice,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE,
SUPPORT_OPERATION_MODE, SUPPORT_OPERATION_MODE,
) )
from homeassistant.const import ATTR_TEMPERATURE, STATE_OFF, TEMP_CELSIUS 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_AUTO = "auto"
STATE_MANUAL = "manual" STATE_MANUAL = "manual"
@ -44,93 +44,81 @@ async def async_setup_platform(
client = hass.data[DOMAIN]["client"] client = hass.data[DOMAIN]["client"]
entities = [ entities = [
GeniusWaterHeater(client, z) GeniusWaterHeater(z) for z in client.zone_objs if z.data["type"] in GH_HEATERS
for z in client.hub.zone_objs
if z.type in GH_HEATERS
] ]
async_add_entities(entities) async_add_entities(entities)
class GeniusWaterHeater(WaterHeaterDevice): class GeniusWaterHeater(GeniusEntity, WaterHeaterDevice):
"""Representation of a Genius Hub water_heater device.""" """Representation of a Genius Hub water_heater device."""
def __init__(self, client, boiler): def __init__(self, boiler) -> None:
"""Initialize the water_heater device.""" """Initialize the water_heater device."""
self._client = client super().__init__()
self._boiler = boiler
self._boiler = boiler
self._operation_list = list(HA_OPMODE_TO_GH) 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 @property
def name(self): def name(self) -> str:
"""Return the name of the water_heater device.""" """Return the name of the water_heater device."""
return self._boiler.name return self._boiler.name
@property @property
def device_state_attributes(self): def device_state_attributes(self) -> Dict[str, Any]:
"""Return the device state attributes.""" """Return the device state attributes."""
tmp = self._boiler.data.items() return {
return {"status": {k: v for k, v in tmp if k in GH_STATE_ATTRS}} "status": {
k: v for k, v in self._boiler.data.items() if k in GH_STATE_ATTRS
}
}
@property @property
def should_poll(self) -> bool: def current_temperature(self) -> Optional[float]:
"""Return False as the geniushub devices should not be polled."""
return False
@property
def current_temperature(self):
"""Return the current temperature.""" """Return the current temperature."""
return self._boiler.data.get("temperature") return self._boiler.data.get("temperature")
@property @property
def target_temperature(self): def target_temperature(self) -> float:
"""Return the temperature we try to reach.""" """Return the temperature we try to reach."""
return self._boiler.data["setpoint"] return self._boiler.data["setpoint"]
@property @property
def min_temp(self): def min_temp(self) -> float:
"""Return max valid temperature that can be set.""" """Return max valid temperature that can be set."""
return GH_MIN_TEMP return GH_MIN_TEMP
@property @property
def max_temp(self): def max_temp(self) -> float:
"""Return max valid temperature that can be set.""" """Return max valid temperature that can be set."""
return GH_MAX_TEMP return GH_MAX_TEMP
@property @property
def temperature_unit(self): def temperature_unit(self) -> str:
"""Return the unit of measurement.""" """Return the unit of measurement."""
return TEMP_CELSIUS return TEMP_CELSIUS
@property @property
def supported_features(self): def supported_features(self) -> int:
"""Return the list of supported features.""" """Return the list of supported features."""
return GH_SUPPORT_FLAGS return GH_SUPPORT_FLAGS
@property @property
def operation_list(self): def operation_list(self) -> List[str]:
"""Return the list of available operation modes.""" """Return the list of available operation modes."""
return self._operation_list return self._operation_list
@property @property
def current_operation(self): def current_operation(self) -> str:
"""Return the current operation mode.""" """Return the current operation mode."""
return GH_STATE_TO_HA[self._boiler.data["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.""" """Set a new operation mode for this boiler."""
await self._boiler.set_mode(HA_OPMODE_TO_GH[operation_mode]) 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.""" """Set a new target temperature for this boiler."""
temperature = kwargs[ATTR_TEMPERATURE] temperature = kwargs[ATTR_TEMPERATURE]
await self._boiler.set_override(temperature, 3600) # 1 hour await self._boiler.set_override(temperature, 3600) # 1 hour

View File

@ -518,7 +518,7 @@ gearbest_parser==1.0.7
geizhals==0.0.9 geizhals==0.0.9
# homeassistant.components.geniushub # homeassistant.components.geniushub
geniushub-client==0.5.8 geniushub-client==0.6.5
# homeassistant.components.geo_json_events # homeassistant.components.geo_json_events
# homeassistant.components.nsw_rural_fire_service_feed # homeassistant.components.nsw_rural_fire_service_feed