From 9a7d76fed5530592e5e7fdf6e176a9ef8e0d05a9 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Thu, 30 Apr 2020 21:27:25 +0100 Subject: [PATCH 1/6] Fixes for HA v109.0 I/O issues --- custom_components/wiser/__init__.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/custom_components/wiser/__init__.py b/custom_components/wiser/__init__.py index c1d844c..6808eb2 100755 --- a/custom_components/wiser/__init__.py +++ b/custom_components/wiser/__init__.py @@ -11,6 +11,7 @@ # import time from datetime import datetime, timedelta +from functools import partial import voluptuous as vol from wiserHeatingAPI.wiserHub import ( wiserHub, @@ -125,6 +126,8 @@ async def async_setup_entry(hass, config_entry): config_entry.data[CONF_PASSWORD], ) + await data.async_connect() + @callback def retryWiserHubSetup(): hass.async_create_task(wiserHubSetup()) @@ -214,7 +217,7 @@ def __init__(self, hass, config_entry, ip, secret): self._name = config_entry.data[CONF_NAME] self.ip = ip self.secret = secret - self.wiserhub = wiserHub(self.ip, self.secret) + self.wiserhub = None self.minimum_temp = TEMP_MINIMUM self.maximum_temp = TEMP_MAXIMUM self.boost_temp = config_entry.data.get(CONF_BOOST_TEMP, DEFAULT_BOOST_TEMP) @@ -223,6 +226,11 @@ def __init__(self, hass, config_entry, ip, secret): ) self.timer_handle = None + async def async_connect(self): + self.wiserhub = await self._hass.async_add_executor_job( + partial(wiserHub, self.ip, self.secret) + ) + @callback def do_hub_update(self): self._hass.async_create_task(self.async_update()) From 08fcf6cb4beb3b41623891ba7c80925d96a95131 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Thu, 30 Apr 2020 21:27:45 +0100 Subject: [PATCH 2/6] updated translation dir as per HA109.0 --- custom_components/wiser/translations/de.json | 41 ++++++++++++++++++++ custom_components/wiser/translations/en.json | 41 ++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 custom_components/wiser/translations/de.json create mode 100755 custom_components/wiser/translations/en.json diff --git a/custom_components/wiser/translations/de.json b/custom_components/wiser/translations/de.json new file mode 100644 index 0000000..81d2996 --- /dev/null +++ b/custom_components/wiser/translations/de.json @@ -0,0 +1,41 @@ +{ + "config": { + "abort": { + "already_configured": "Dieses Ger\u00E4t ist bereits konfiguriert.", + "already_in_progress": "Der Konfigurationsablauf f\u00fcr Wiser Heat Hub wird bereits ausgef\u00fchrt.", + "auth_failure": "Authentifizierung mit Wiser Heat Hub fehlgeschlagen. Pr\u00fcfe den API Key und versuche es erneut.", + "not_successful": "Verbindung mit Wiser Hub fehlgeschlagen.", + "not_wiser_device": "Dieses Ger\u00E4t wird nicht unterst\u00fctzt.", + "one_instance_only": "Nur eine Instanz pro Wiser Heat Hub ist erlaubt. Pr\u00fcfe deine ignoriereten Ger\u00E4te", + "timeout_error": "Timeout bei der Verbindung zum Wiser Heat Hub. Pr\u00fcfe die IP Adresse und versuche es erneut." + }, + "flow_title": "Wiser Heat Hub: {name}", + "step": { + "user": { + "data": { + "boost_temp": "Boost Temperatur", + "boost_time": "Boost Dauer", + "host": "IP Adresse", + "password": "API Schl\u00fcssel", + "scan_interval": "Scan Intervall" + }, + "description": "Bitte gib die IP-Adresse und API Schl\u00fcssel vom Wiser Heat Hub ein", + "title": "Wiser Heat Hub Setup" + } + }, + "title": "Wiser Heat Hub" + }, + "options": { + "step": { + "user": { + "data": { + "boost_temp": "Boost Temperatur", + "boost_time": "Boost Dauer", + "scan_interval": "Scan Intervall" + }, + "description": "Amend Wiser parameters.", + "title": "Wiser Heat Hub Options" + } + } + } +} \ No newline at end of file diff --git a/custom_components/wiser/translations/en.json b/custom_components/wiser/translations/en.json new file mode 100755 index 0000000..8b0f821 --- /dev/null +++ b/custom_components/wiser/translations/en.json @@ -0,0 +1,41 @@ +{ + "config": { + "abort": { + "already_configured": "This device is already configured.", + "already_in_progress": "Wiser Heat Hub configuration is already in progress.", + "auth_failure": "Unable to authenticate with the Wiser Hub. Check the secret key and try again.", + "not_successful": "Unable to connect to the Wiser hub.", + "not_wiser_device": "This device is currently not supported.", + "one_instance_only": "Only 1 instance of the wiser hub is supported. Check in ignored devices.", + "timeout_error": "Connection to the Wiser Hub has timed out. Check the IP address and try again." + }, + "flow_title": "Wiser Heat Hub: {name}", + "step": { + "user": { + "data": { + "boost_temp": "Default Boost Temperature", + "boost_time": "Default Boost Duration", + "host": "IP Address", + "password": "Secret Key", + "scan_interval": "Scan Interval" + }, + "description": "Please enter the ip address and secret key obtained from the hub.", + "title": "Wiser Heat Hub Setup" + } + }, + "title": "Wiser Heat Hub" + }, + "options": { + "step": { + "user": { + "data": { + "boost_temp": "Default Boost Temperature", + "boost_time": "Default Boost Duration", + "scan_interval": "Scan Interval" + }, + "description": "Amend Wiser parameters.", + "title": "Wiser Heat Hub Options" + } + } + } +} \ No newline at end of file From 329194dd9c822a243723d686b421e23e55dd4b93 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Thu, 30 Apr 2020 21:28:21 +0100 Subject: [PATCH 3/6] updated translation dir as per HA109.0 --- custom_components/wiser/.translations/de.json | 41 ------------------- custom_components/wiser/.translations/en.json | 41 ------------------- 2 files changed, 82 deletions(-) delete mode 100644 custom_components/wiser/.translations/de.json delete mode 100755 custom_components/wiser/.translations/en.json diff --git a/custom_components/wiser/.translations/de.json b/custom_components/wiser/.translations/de.json deleted file mode 100644 index 81d2996..0000000 --- a/custom_components/wiser/.translations/de.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "config": { - "abort": { - "already_configured": "Dieses Ger\u00E4t ist bereits konfiguriert.", - "already_in_progress": "Der Konfigurationsablauf f\u00fcr Wiser Heat Hub wird bereits ausgef\u00fchrt.", - "auth_failure": "Authentifizierung mit Wiser Heat Hub fehlgeschlagen. Pr\u00fcfe den API Key und versuche es erneut.", - "not_successful": "Verbindung mit Wiser Hub fehlgeschlagen.", - "not_wiser_device": "Dieses Ger\u00E4t wird nicht unterst\u00fctzt.", - "one_instance_only": "Nur eine Instanz pro Wiser Heat Hub ist erlaubt. Pr\u00fcfe deine ignoriereten Ger\u00E4te", - "timeout_error": "Timeout bei der Verbindung zum Wiser Heat Hub. Pr\u00fcfe die IP Adresse und versuche es erneut." - }, - "flow_title": "Wiser Heat Hub: {name}", - "step": { - "user": { - "data": { - "boost_temp": "Boost Temperatur", - "boost_time": "Boost Dauer", - "host": "IP Adresse", - "password": "API Schl\u00fcssel", - "scan_interval": "Scan Intervall" - }, - "description": "Bitte gib die IP-Adresse und API Schl\u00fcssel vom Wiser Heat Hub ein", - "title": "Wiser Heat Hub Setup" - } - }, - "title": "Wiser Heat Hub" - }, - "options": { - "step": { - "user": { - "data": { - "boost_temp": "Boost Temperatur", - "boost_time": "Boost Dauer", - "scan_interval": "Scan Intervall" - }, - "description": "Amend Wiser parameters.", - "title": "Wiser Heat Hub Options" - } - } - } -} \ No newline at end of file diff --git a/custom_components/wiser/.translations/en.json b/custom_components/wiser/.translations/en.json deleted file mode 100755 index 8b0f821..0000000 --- a/custom_components/wiser/.translations/en.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "config": { - "abort": { - "already_configured": "This device is already configured.", - "already_in_progress": "Wiser Heat Hub configuration is already in progress.", - "auth_failure": "Unable to authenticate with the Wiser Hub. Check the secret key and try again.", - "not_successful": "Unable to connect to the Wiser hub.", - "not_wiser_device": "This device is currently not supported.", - "one_instance_only": "Only 1 instance of the wiser hub is supported. Check in ignored devices.", - "timeout_error": "Connection to the Wiser Hub has timed out. Check the IP address and try again." - }, - "flow_title": "Wiser Heat Hub: {name}", - "step": { - "user": { - "data": { - "boost_temp": "Default Boost Temperature", - "boost_time": "Default Boost Duration", - "host": "IP Address", - "password": "Secret Key", - "scan_interval": "Scan Interval" - }, - "description": "Please enter the ip address and secret key obtained from the hub.", - "title": "Wiser Heat Hub Setup" - } - }, - "title": "Wiser Heat Hub" - }, - "options": { - "step": { - "user": { - "data": { - "boost_temp": "Default Boost Temperature", - "boost_time": "Default Boost Duration", - "scan_interval": "Scan Interval" - }, - "description": "Amend Wiser parameters.", - "title": "Wiser Heat Hub Options" - } - } - } -} \ No newline at end of file From 8ae2f92f4377ba8954dbaea909cfcff328571ee1 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Thu, 30 Apr 2020 22:00:36 +0100 Subject: [PATCH 4/6] improved connection issue handling at startup --- custom_components/wiser/__init__.py | 57 ++++++++++++++--------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/custom_components/wiser/__init__.py b/custom_components/wiser/__init__.py index 6808eb2..daab868 100755 --- a/custom_components/wiser/__init__.py +++ b/custom_components/wiser/__init__.py @@ -126,8 +126,6 @@ async def async_setup_entry(hass, config_entry): config_entry.data[CONF_PASSWORD], ) - await data.async_connect() - @callback def retryWiserHubSetup(): hass.async_create_task(wiserHubSetup()) @@ -135,33 +133,38 @@ def retryWiserHubSetup(): async def wiserHubSetup(): _LOGGER.info("Initiating WiserHub connection") try: - if await data.async_update(): - if data.wiserhub.getDevices is None: - _LOGGER.error("No Wiser devices found to set up") - return False - - hass.data[DOMAIN] = data - - for platform in WISER_PLATFORMS: - hass.async_create_task( - hass.config_entries.async_forward_entry_setup( - config_entry, platform + if await data.async_connect(): + if await data.async_update(): + if data.wiserhub.getDevices is None: + _LOGGER.error("No Wiser devices found to set up") + return False + + hass.data[DOMAIN] = data + + for platform in WISER_PLATFORMS: + hass.async_create_task( + hass.config_entries.async_forward_entry_setup( + config_entry, platform + ) ) - ) - _LOGGER.info("Wiser Component Setup Completed") - return True - else: - await scheduleWiserHubSetup() - return True + _LOGGER.info("Wiser Component Setup Completed") + await data.async_update_device_registry() + return True + else: + await scheduleWiserHubSetup() + return True except (asyncio.TimeoutError): await scheduleWiserHubSetup() return True except WiserHubTimeoutException: await scheduleWiserHubSetup() return True + except Exception: + await scheduleWiserHubSetup() + return True - async def scheduleWiserHubSetup(interval=30): + async def scheduleWiserHubSetup(interval=10): _LOGGER.error( "Unable to connect to the Wiser Hub, retrying in {} seconds".format( interval @@ -170,8 +173,7 @@ async def scheduleWiserHubSetup(interval=30): hass.loop.call_later(interval, retryWiserHubSetup) return - hass.async_create_task(wiserHubSetup()) - await data.async_update_device_registry() + await wiserHubSetup() return True @@ -230,6 +232,7 @@ async def async_connect(self): self.wiserhub = await self._hass.async_add_executor_job( partial(wiserHub, self.ip, self.secret) ) + return True @callback def do_hub_update(self): @@ -264,7 +267,7 @@ async def async_update(self, no_throttle: bool = False): dispatcher_send(self._hass, "WiserHubUpdateMessage") return True else: - _LOGGER.error("**Unable to update from wiser hub**") + _LOGGER.error("Unable to update from wiser hub") return False except json.decoder.JSONDecodeError as JSONex: _LOGGER.error( @@ -273,15 +276,11 @@ async def async_update(self, no_throttle: bool = False): ) return False except WiserHubTimeoutException as ex: - _LOGGER.error( - "***Failed to get update from Wiser hub due to timeout error***" - ) + _LOGGER.error("Unable to update from Wiser hub due to timeout error") _LOGGER.debug("Error is {}".format(ex)) return False except Exception as ex: - _LOGGER.error( - "***Failed to get update from Wiser hub due to unknown error***" - ) + _LOGGER.error("Unable to update from Wiser hub due to unknown error") _LOGGER.debug("Error is {}".format(ex)) return False From 38f69bce58dbae9f206a842ec65e810cd231a9fd Mon Sep 17 00:00:00 2001 From: msp1974 Date: Thu, 30 Apr 2020 22:54:21 +0100 Subject: [PATCH 5/6] Additional IO improvements --- custom_components/wiser/__init__.py | 24 ++++++++++++++++-------- custom_components/wiser/climate.py | 21 +++++++++++++++++---- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/custom_components/wiser/__init__.py b/custom_components/wiser/__init__.py index daab868..1d75334 100755 --- a/custom_components/wiser/__init__.py +++ b/custom_components/wiser/__init__.py @@ -304,22 +304,26 @@ async def async_update_device_registry(self): async def set_away_mode(self, away, away_temperature): mode = "AWAY" if away else "HOME" if self.wiserhub is None: - self.wiserhub = wiserHub(self.ip, self.secret) + self.wiserhub = await self.async_connect() _LOGGER.debug( "Setting away mode to {} with temp {}.".format(mode, away_temperature) ) try: - self.wiserhub.setHomeAwayMode(mode, away_temperature) + await self._hass.async_add_executor_job( + partial(self.wiserhub.setHomeAwayMode, mode, away_temperature) + ) await self.async_update(no_throttle=True) except BaseException as e: _LOGGER.debug("Error setting away mode! {}".format(str(e))) async def set_system_switch(self, switch, mode): if self.wiserhub is None: - self.wiserhub = wiserHub(self.ip, self.secret) + self.wiserhub = await self.async_connect() _LOGGER.debug("Setting {} system switch to {}.".format(switch, mode)) try: - self.wiserhub.setSystemSwitch(switch, mode) + await self._hass.async_add_executor_job( + partial(self.wiserhub.setSystemSwitch, switch, mode) + ) await self.async_update(no_throttle=True) except BaseException as e: _LOGGER.debug("Error setting {} system switch! {}".format(switch, str(e))) @@ -332,11 +336,13 @@ async def set_smart_plug_state(self, plug_id, state): :return: """ if self.wiserhub is None: - self.wiserhub = wiserHub(self.ip, self.secret) + self.wiserhub = await self.async_connect() _LOGGER.info("Setting SmartPlug {} to {} ".format(plug_id, state)) try: - self.wiserhub.setSmartPlugState(plug_id, state) + await self._hass.async_add_executor_job( + partial(self.wiserhub.setSmartPlugState, plug_id, state) + ) # Add small delay to allow hub to update status before refreshing await asyncio.sleep(0.5) await self.async_update(no_throttle=True) @@ -353,14 +359,16 @@ async def set_hotwater_mode(self, hotwater_mode): """ if self.wiserhub is None: - self.wiserhub = wiserHub(self.ip, self.secret) + self.wiserhub = await self.async_connect() _LOGGER.info("Setting Hotwater to {} ".format(hotwater_mode)) # Add small delay to allow hub to update status before refreshing await asyncio.sleep(0.5) await self.async_update(no_throttle=True) try: - self.wiserhub.setHotwaterMode(hotwater_mode) + await self._hass.async_add_executor_job( + partial(self.wiserhub.setHotwaterMode, hotwater_mode) + ) except BaseException as e: _LOGGER.debug( diff --git a/custom_components/wiser/climate.py b/custom_components/wiser/climate.py index f720db2..542d089 100755 --- a/custom_components/wiser/climate.py +++ b/custom_components/wiser/climate.py @@ -10,6 +10,7 @@ import voluptuous as vol +from functools import partial from homeassistant.components.climate import ClimateDevice from homeassistant.core import callback @@ -477,7 +478,11 @@ async def async_set_temperature(self, **kwargs): _LOGGER.debug( "Setting temperature for {} to {}".format(self.name, target_temperature) ) - self.data.wiserhub.setRoomTemperature(self.room_id, target_temperature) + await self.hass.async_add_executor_job( + partial( + self.data.wiserhub.setRoomTemperature, self.room_id, target_temperature + ) + ) self._force_update = True await self.async_update_ha_state(True) @@ -490,7 +495,11 @@ async def set_room_mode(self, room_id, mode, boost_temp=None, boost_time=None): _LOGGER.debug( "Setting Room Mode to {} for roomId {}".format(mode, self.room_id) ) - self.data.wiserhub.setRoomMode(room_id, mode, boost_temp, boost_time) + await self.hass.async_add_executor_job( + partial( + self.data.wiserhub.setRoomMode, room_id, mode, boost_temp, boost_time + ) + ) self._force_update = True await self.async_update_ha_state(True) return True @@ -498,7 +507,9 @@ async def set_room_mode(self, room_id, mode, boost_temp=None, boost_time=None): async def set_room_schedule(self, room_id, scheduleData): if scheduleData != None: scheduleData = convert_to_wiser_schedule(scheduleData) - self.data.wiserhub.setRoomSchedule(room_id, scheduleData) + await self.hass.async_add_executor_job( + partial(self.data.wiserhub.setRoomSchedule, room_id, scheduleData) + ) _LOGGER.debug("Set room schedule for {}".format(self.name)) self._force_update = True await self.async_update_ha_state(True) @@ -507,7 +518,9 @@ async def set_room_schedule(self, room_id, scheduleData): return False async def copy_room_schedule(self, room_id, to_room_id): - self.data.wiserhub.copyRoomSchedule(room_id, to_room_id) + await self.hass.async_add_executor_job( + partial(self.data.wiserhub.copyRoomSchedule, room_id, to_room_id) + ) _LOGGER.debug( "Copied room schedule from {} to {}".format( self.name, self.data.wiserhub.getRoom(to_room_id).get("Name") From 4941e70b184ec5cfd1ea4ccf7df7c564be7599dd Mon Sep 17 00:00:00 2001 From: msp1974 Date: Thu, 30 Apr 2020 23:37:07 +0100 Subject: [PATCH 6/6] Fix for issue #98 --- custom_components/wiser/climate.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/custom_components/wiser/climate.py b/custom_components/wiser/climate.py index 542d089..80db8b6 100755 --- a/custom_components/wiser/climate.py +++ b/custom_components/wiser/climate.py @@ -15,6 +15,8 @@ from homeassistant.core import callback from homeassistant.components.climate.const import ( + CURRENT_HVAC_HEAT, + CURRENT_HVAC_IDLE, HVAC_MODE_AUTO, SUPPORT_TARGET_TEMPERATURE, SUPPORT_PRESET_MODE, @@ -332,6 +334,13 @@ def device_info(self): "model": ROOM.title(), } + @property + def hvac_action(self): + if self.data.wiserhub.getRoom(self.room_id).get("ControlOutputState") == "On": + return CURRENT_HVAC_HEAT + else: + return CURRENT_HVAC_IDLE + @property def hvac_mode(self): state = self.data.wiserhub.getRoom(self.room_id).get("Mode")