From fdcab632daa59cd62582765493d0c17066edc0b7 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Sat, 11 Jan 2020 17:17:53 +0000 Subject: [PATCH 1/6] Updated: Added timeout setting to all requests --- wiserHeatingAPI/wiserHub.py | 48 +++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/wiserHeatingAPI/wiserHub.py b/wiserHeatingAPI/wiserHub.py index c41d78f..fced349 100755 --- a/wiserHeatingAPI/wiserHub.py +++ b/wiserHeatingAPI/wiserHub.py @@ -23,6 +23,7 @@ WISERSETROOMTEMP= "http://{}//data/domain/Room/{}" WISERROOM="http://{}//data/domain/Room/{}" +TIMEOUT=10 class wiserHub(): @@ -43,24 +44,29 @@ def refreshData(self): """ smartValves=[] _LOGGER.info("Updating Wiser Hub Data") - self.wiserHubData = requests.get(WISERHUBURL.format( - self.hubIP), headers=self.headers).json() - _LOGGER.debug("Wiser Hub Data received {} ".format(self.wiserHubData)) - if self.getRooms()!=None: - for room in self.getRooms(): - roomStatId=room.get("RoomStatId") - if roomStatId!=None: - #RoomStat found add it to the list - self.device2roomMap[roomStatId]={"roomId":room.get("id"), "roomName":room.get("Name")} - smartValves=room.get("SmartValveIds") - if smartValves!=None: - for valveId in smartValves: + try: + self.wiserHubData = requests.get(WISERHUBURL.format( + self.hubIP), headers=self.headers, timeout=TIMEOUT).json() + _LOGGER.debug("Wiser Hub Data received {} ".format(self.wiserHubData)) + if self.getRooms()!=None: + for room in self.getRooms(): + roomStatId=room.get("RoomStatId") + if roomStatId!=None: + #RoomStat found add it to the list + self.device2roomMap[roomStatId]={"roomId":room.get("id"), "roomName":room.get("Name")} + smartValves=room.get("SmartValveIds") + if smartValves!=None: + for valveId in smartValves: self.device2roomMap[valveId]={"roomId":room.get("id"), "roomName":room.get("Name")} - else: - _LOGGER.warning(" Room doesnt contain any smart valves, maybe an error/corruption?? ") - _LOGGER.debug(" valve2roomMap{} ".format(self.device2roomMap)) - else: - _LOGGER.warning("Wiser found no rooms") + else: + _LOGGER.warning("Room doesnt contain any smart valves, maybe an error/corruption?? ") + _LOGGER.debug(" valve2roomMap{} ".format(self.device2roomMap)) + else: + _LOGGER.warning("Wiser found no rooms") + except requests.Timeout: + _LOGGER.debug("Connection timed out trying to update from Wiser Hub") + except requests.ConnectionError: + _LOGGER.debug("Connection error trying to update from Wiser Hub") return self.wiserHubData @@ -242,7 +248,7 @@ def setHomeAwayMode(self,mode,temperature=10): else: self.patchData={"type":0,"setPoint":0} _LOGGER.debug ("patchdata {} ".format(self.patchData)) - self.response = requests.patch(url=WISERMODEURL.format(self.hubIP), headers=self.headers,json =self.patchData ) + self.response = requests.patch(url=WISERMODEURL.format(self.hubIP), headers=self.headers, json=self.patchData, timeout=TIMEOUT) if (self.response.status_code!=200): _LOGGER.debug("Set Home/Away Response code = {}".format(self.response.status_code)) raise Exception("Error setting Home/Away , error {} {}".format(self.response.status_code, self.response.text)) @@ -261,7 +267,7 @@ def setRoomTemperature(self, roomId, temperature): apitemp=temperature*10 patchData={"RequestOverride":{"Type":"Manual","SetPoint":apitemp}} self.response = requests.patch(WISERSETROOMTEMP.format( - self.hubIP,roomId), headers=self.headers,json=patchData) + self.hubIP,roomId), headers=self.headers, json=patchData, timeout=TIMEOUT) if self.response.status_code != 200: _LOGGER.error("Set Room {} Temperature to = {} resulted in {}".format(roomId,temperature,self.response.status_code)) @@ -314,14 +320,14 @@ def setRoomMode(self,roomId, mode,boost_temp=20,boost_temp_time=30): if (mode.lower()!="boost"): cancelBoostPostData={"RequestOverride":{"Type":"None","DurationMinutes": 0, "SetPoint":0, "Originator":"App"}} - self.response = requests.patch(WISERROOM.format(self.hubIP,roomId), headers=self.headers,json=cancelBoostPostData) + self.response = requests.patch(WISERROOM.format(self.hubIP,roomId), headers=self.headers, json=cancelBoostPostData, timeout=TIMEOUT) if (self.response.status_code != 200): _LOGGER.error("Cancelling boost resulted in {}".format(self.response.status_code)) raise Exception("Error cancelling boost {} ".format(mode)) # Set new mode self.response = requests.patch(WISERROOM.format( - self.hubIP,roomId), headers=self.headers,json=patchData) + self.hubIP,roomId), headers=self.headers, json=patchData, timeout=TIMEOUT) if self.response.status_code != 200: _LOGGER.error("Set Room mode to {} resulted in {}".format(mode,self.response.status_code)) raise Exception("Error setting mode to error {} ".format(mode)) From 06e8370fede9b985795f6737adec42b8d80b3dd5 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Sat, 11 Jan 2020 17:43:44 +0000 Subject: [PATCH 2/6] Added: Functions to convert between wiser temp value and decimal temp value - issue #4 Added: Function to check temperature is in valid range in set functions Updated: Improved logging output for setRoomMode errors Fixed: Manual mode temp will be set to min temp when scheduled temp is below minimum - issue #3 Updated: Created constants for off, min and max temp and used in functions instead of values --- wiserHeatingAPI/wiserHub.py | 53 ++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/wiserHeatingAPI/wiserHub.py b/wiserHeatingAPI/wiserHub.py index fced349..45a7443 100755 --- a/wiserHeatingAPI/wiserHub.py +++ b/wiserHeatingAPI/wiserHub.py @@ -23,8 +23,11 @@ WISERSETROOMTEMP= "http://{}//data/domain/Room/{}" WISERROOM="http://{}//data/domain/Room/{}" +ATTR_TEMP_MINIMUM = 5 +ATTR_TEMP_MAXIMUM = 30 TIMEOUT=10 + class wiserHub(): @@ -37,6 +40,18 @@ def __init__(self,hubIP,secret): self.device2roomMap={} # Dict holding Valve2Room mapping convinience variable self.refreshData() # Issue first refresh in init + def __toWiserTemp(self,temp): + temp = int(temp*10) + return temp + + def __fromWiserTemp(self,temp): + temp = round(temp/10,1) + return temp + + @property + def max_temp(self): + return MAXTEMP + def refreshData(self): """ Forces a refresh of data @@ -239,12 +254,12 @@ def setHomeAwayMode(self,mode,temperature=10): if (mode=="AWAY"): if temperature==None: raise Exception("setAwayHome set to AWAY but not temperature set") - if temperature== -20 or temperature <0 or temperature>30: - raise Exception("setAwayHome temperature can only be between 5 and 30 or -20(Off)") + if ((temperature!=-20) and (temperature<5 or temperature>30)): + raise Exception("setAwayHome temperature can only be between 5 and 30 or -20(Off)") _LOGGER.info("Setting Home/Away : {}".format(mode)) - temperature=temperature*10 + if (mode=="AWAY"): - self.patchData={"type":2,"setPoint":temperature} + self.patchData={"type":2,"setPoint":self.__toWiserTemp(temperature)} else: self.patchData={"type":0,"setPoint":0} _LOGGER.debug ("patchdata {} ".format(self.patchData)) @@ -264,8 +279,8 @@ def setRoomTemperature(self, roomId, temperature): _LOGGER.info("Set Room {} Temperature to = {} ".format(roomId,temperature)) if ((temperature!=-20) and (temperature<5 or temperature>30)): raise Exception("SetRoomTemperature : value of temperature must be between 5 and 30 OR -20 (off)") - apitemp=temperature*10 - patchData={"RequestOverride":{"Type":"Manual","SetPoint":apitemp}} + + patchData={"RequestOverride":{"Type":"Manual","SetPoint":self.__toWiserTemp(temperature)}} self.response = requests.patch(WISERSETROOMTEMP.format( self.hubIP,roomId), headers=self.headers, json=patchData, timeout=TIMEOUT) @@ -299,20 +314,21 @@ def setRoomMode(self,roomId, mode,boost_temp=20,boost_temp_time=30): #Do Auto patchData= {"Mode":"Auto"} elif (mode.lower()=="boost"): - temp=boost_temp*10 - _LOGGER.debug("Setting Boost Temp to {}".format(temp)) - patchData={"RequestOverride":{"Type":"Manual","DurationMinutes": boost_temp_time, "SetPoint":temp, "Originator":"App"}} + if (boost_temp < 5 or boost_temp > 30): + raise Exception("Boost temperature is set to {}. Boost temperature can only be between 5 and 30.".format(boost_temp)) + _LOGGER.debug("Setting room {} to boost mode with temp of {} for {} mins".format(roomId, boost_temp, boost_temp_time)) + patchData={"RequestOverride":{"Type":"Manual","DurationMinutes": boost_temp_time, "SetPoint":self.__toWiserTemp(boost_temp), "Originator":"App"}} elif (mode.lower()=="manual"): - # When setting back to manual , set the temp to the scheduled temp - newTemp=self.getRoom(roomId).get("ScheduledSetPoint") + # When setting to manual , set the temp to the current scheduled temp + setTemp=self.__fromWiserTemp(self.getRoom(roomId).get("ScheduledSetPoint")) + #If current scheduled temp is less than 5C then set to min temp + setTemp = setTemp if setTemp >= ATTR_TEMP_MINIMUM else ATTR_TEMP_MINIMUM patchData = {"Mode": "Manual", "RequestOverride": {"Type": "Manual", - "SetPoint": newTemp}} - - + "SetPoint": self.__toWiserTemp(setTemp)}} # Implement trv off as per https://github.com/asantaga/wiserheatingapi/issues/3 elif (mode.lower()=="off"): - patchData = {"Mode": "Manual","RequestOverride": {"Type": "Manual","SetPoint": -200}} + patchData = {"Mode": "Manual","RequestOverride": {"Type": "Manual","SetPoint": self.__toWiserTemp(-20)}} else: raise Exception("Error setting setting room mode, received {} but should be auto,boost,off or manual ".format(mode)) @@ -327,10 +343,11 @@ def setRoomMode(self,roomId, mode,boost_temp=20,boost_temp_time=30): # Set new mode self.response = requests.patch(WISERROOM.format( - self.hubIP,roomId), headers=self.headers, json=patchData, timeout=TIMEOUT) + self.hubIP,roomId), headers=self.headers, json=patchData, timeout=TIMEOUT) if self.response.status_code != 200: - _LOGGER.error("Set Room mode to {} resulted in {}".format(mode,self.response.status_code)) - raise Exception("Error setting mode to error {} ".format(mode)) + _LOGGER.error("Set Room {} to Mode {} resulted in {}".format(roomId,mode,self.response.status_code)) + raise Exception("Error setting mode to {}, error {} ".format(mode, self.response.text)) + _LOGGER.debug("Set room mode, error {} ({})".format(self.response.status_code, self.response.text)) From 3698855965b78c2a2d47b6e0920e61eab11f3e26 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Sat, 11 Jan 2020 17:53:28 +0000 Subject: [PATCH 3/6] Updated: Added function descriptions Updated: Replaced remaining values with off,min,max constants --- wiserHeatingAPI/wiserHub.py | 39 +++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/wiserHeatingAPI/wiserHub.py b/wiserHeatingAPI/wiserHub.py index 45a7443..7302577 100755 --- a/wiserHeatingAPI/wiserHub.py +++ b/wiserHeatingAPI/wiserHub.py @@ -23,8 +23,10 @@ WISERSETROOMTEMP= "http://{}//data/domain/Room/{}" WISERROOM="http://{}//data/domain/Room/{}" -ATTR_TEMP_MINIMUM = 5 -ATTR_TEMP_MAXIMUM = 30 +TEMP_MINIMUM = 5 +TEMP_MAXIMUM = 30 +TEMP_OFF = -20 + TIMEOUT=10 @@ -41,17 +43,34 @@ def __init__(self,hubIP,secret): self.refreshData() # Issue first refresh in init def __toWiserTemp(self,temp): + """ + Converts from temperature to wiser hub format + param temp: The temperature to convert + return: Integer + """ temp = int(temp*10) return temp def __fromWiserTemp(self,temp): + """ + Conerts from wiser hub temperature format to decimal value + param temp: The wiser temperature to convert + return: Float + """ temp = round(temp/10,1) return temp - @property - def max_temp(self): - return MAXTEMP - + def __checkTempRange(self,temp): + """ + Validates temperatures are within the allowed range for the wiser hub + param temp: The temperature to check + return: Boolean + """ + if (temp != TEMP_OFF and (temp < TEMP_MINIMUM or temp > TEMP_MAXIMUM)): + return False + else: + return True + def refreshData(self): """ Forces a refresh of data @@ -254,7 +273,7 @@ def setHomeAwayMode(self,mode,temperature=10): if (mode=="AWAY"): if temperature==None: raise Exception("setAwayHome set to AWAY but not temperature set") - if ((temperature!=-20) and (temperature<5 or temperature>30)): + if not (__checkTempRange(temperature)): raise Exception("setAwayHome temperature can only be between 5 and 30 or -20(Off)") _LOGGER.info("Setting Home/Away : {}".format(mode)) @@ -277,7 +296,7 @@ def setRoomTemperature(self, roomId, temperature): param temperature: The temperature in celcius from 5 to 30, -20 for Off """ _LOGGER.info("Set Room {} Temperature to = {} ".format(roomId,temperature)) - if ((temperature!=-20) and (temperature<5 or temperature>30)): + if not (__checkTempRange(temperature)): raise Exception("SetRoomTemperature : value of temperature must be between 5 and 30 OR -20 (off)") patchData={"RequestOverride":{"Type":"Manual","SetPoint":self.__toWiserTemp(temperature)}} @@ -314,7 +333,7 @@ def setRoomMode(self,roomId, mode,boost_temp=20,boost_temp_time=30): #Do Auto patchData= {"Mode":"Auto"} elif (mode.lower()=="boost"): - if (boost_temp < 5 or boost_temp > 30): + if (boost_temp < TEMP_MINIMUM or boost_temp > TEMP_MAXIMUM): raise Exception("Boost temperature is set to {}. Boost temperature can only be between 5 and 30.".format(boost_temp)) _LOGGER.debug("Setting room {} to boost mode with temp of {} for {} mins".format(roomId, boost_temp, boost_temp_time)) patchData={"RequestOverride":{"Type":"Manual","DurationMinutes": boost_temp_time, "SetPoint":self.__toWiserTemp(boost_temp), "Originator":"App"}} @@ -328,7 +347,7 @@ def setRoomMode(self,roomId, mode,boost_temp=20,boost_temp_time=30): "SetPoint": self.__toWiserTemp(setTemp)}} # Implement trv off as per https://github.com/asantaga/wiserheatingapi/issues/3 elif (mode.lower()=="off"): - patchData = {"Mode": "Manual","RequestOverride": {"Type": "Manual","SetPoint": self.__toWiserTemp(-20)}} + patchData = {"Mode": "Manual","RequestOverride": {"Type": "Manual","SetPoint": self.__toWiserTemp(TEMP_OFF)}} else: raise Exception("Error setting setting room mode, received {} but should be auto,boost,off or manual ".format(mode)) From 8fb20da201a35a73969d6a96947928d0d21ab103 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Sat, 11 Jan 2020 18:09:29 +0000 Subject: [PATCH 4/6] Corrected typo in setRoomMode --- wiserHeatingAPI/wiserHub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiserHeatingAPI/wiserHub.py b/wiserHeatingAPI/wiserHub.py index 7302577..d6b54b9 100755 --- a/wiserHeatingAPI/wiserHub.py +++ b/wiserHeatingAPI/wiserHub.py @@ -341,7 +341,7 @@ def setRoomMode(self,roomId, mode,boost_temp=20,boost_temp_time=30): # When setting to manual , set the temp to the current scheduled temp setTemp=self.__fromWiserTemp(self.getRoom(roomId).get("ScheduledSetPoint")) #If current scheduled temp is less than 5C then set to min temp - setTemp = setTemp if setTemp >= ATTR_TEMP_MINIMUM else ATTR_TEMP_MINIMUM + setTemp = setTemp if setTemp >= TEMP_MINIMUM else TEMP_MINIMUM patchData = {"Mode": "Manual", "RequestOverride": {"Type": "Manual", "SetPoint": self.__toWiserTemp(setTemp)}} From 2d28fc44a188e96963dbc41b8a92c39e1750d519 Mon Sep 17 00:00:00 2001 From: msp1974 Date: Sat, 11 Jan 2020 18:28:20 +0000 Subject: [PATCH 5/6] Fix for issue #1. Only shows warning if room has no TRVs or RoomStats --- wiserHeatingAPI/wiserHub.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wiserHeatingAPI/wiserHub.py b/wiserHeatingAPI/wiserHub.py index d6b54b9..4932b58 100755 --- a/wiserHeatingAPI/wiserHub.py +++ b/wiserHeatingAPI/wiserHub.py @@ -92,8 +92,10 @@ def refreshData(self): if smartValves!=None: for valveId in smartValves: self.device2roomMap[valveId]={"roomId":room.get("id"), "roomName":room.get("Name")} - else: - _LOGGER.warning("Room doesnt contain any smart valves, maybe an error/corruption?? ") + #Show warning if room contains no devices. + if roomStatId is None and smartValves is None: + #No devices in room + _LOGGER.warning("Room {} doesn't contain any smart valves or thermostats.".format(room.get("Name"))) _LOGGER.debug(" valve2roomMap{} ".format(self.device2roomMap)) else: _LOGGER.warning("Wiser found no rooms") From c51b4a7b1cc9f4afa262bbcd469d80bb3dc709ed Mon Sep 17 00:00:00 2001 From: msp1974 Date: Sat, 11 Jan 2020 19:14:28 +0000 Subject: [PATCH 6/6] Fixed: Error calling temp range check --- wiserHeatingAPI/wiserHub.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiserHeatingAPI/wiserHub.py b/wiserHeatingAPI/wiserHub.py index 4932b58..f5bc9f6 100755 --- a/wiserHeatingAPI/wiserHub.py +++ b/wiserHeatingAPI/wiserHub.py @@ -275,7 +275,7 @@ def setHomeAwayMode(self,mode,temperature=10): if (mode=="AWAY"): if temperature==None: raise Exception("setAwayHome set to AWAY but not temperature set") - if not (__checkTempRange(temperature)): + if not (self.__checkTempRange(temperature)): raise Exception("setAwayHome temperature can only be between 5 and 30 or -20(Off)") _LOGGER.info("Setting Home/Away : {}".format(mode)) @@ -298,7 +298,7 @@ def setRoomTemperature(self, roomId, temperature): param temperature: The temperature in celcius from 5 to 30, -20 for Off """ _LOGGER.info("Set Room {} Temperature to = {} ".format(roomId,temperature)) - if not (__checkTempRange(temperature)): + if not (self.__checkTempRange(temperature)): raise Exception("SetRoomTemperature : value of temperature must be between 5 and 30 OR -20 (off)") patchData={"RequestOverride":{"Type":"Manual","SetPoint":self.__toWiserTemp(temperature)}}