asantaga / wiserheatingapi Goto Github PK
View Code? Open in Web Editor NEWThis is a simple python API for interacting with the wiser heating system
License: MIT License
This is a simple python API for interacting with the wiser heating system
License: MIT License
While investigating some of the other functions of the wiser app that are not yet supported in this api, I found that the wiser app uses a v2 api to the hub.
For reading the hub domain data this is significantly faster and it also separates schedule data into a different api call with different json format.
I suspect that a future hub firmware update may remove this v1 api in favor of v2, so we should have on the enhancement list to migrate to the v2 version.
As a side note, found a really great app for phone or tablet to monitor http calls from apps similar to fiddler called HTTPCanary. Was very useful to do the function in the app and see the calls to the api.
Since the 6th August, all of my TRVs have started to report 0 percent battery into HA
Via the app, they are still reporting fine - could this be a regression?
I am currently running integration v3.1.3
Cheers!
During testing noticed this error
File "wiserapitest.py", line 142, in <module>
wh.setSmartPlugState(smartPlugId, originalPlugState)
File "/home/asantaga/src/wiserheatingapi/wiserHeatingAPI/wiserHub.py", line 791, in setSmartPlugState
if smartPlugState.title() not in ["On", "Off"]:
AttributeError: 'NoneType' object has no attribute 'title'
I have just installed wiserHomeAssistantPlatform - thank you very much for the work you have put into it. I did have one issue that stopped it from working, as follows:
After installation and configuration, it didn't seem that anything worked, as nothing appeared on the dashboard. Digging around in the logs returned this error:
2020-03-26 20:18:22 ERROR (MainThread) [homeassistant.setup] Error during setup of component wiser
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/setup.py", line 170, in _async_setup_component
hass, processed_config
File "/config/custom_components/wiser/__init__.py", line 69, in async_setup
data = WiserHubHandle(hass, config, host, secret)
File "/config/custom_components/wiser/__init__.py", line 116, in __init__
self.wiserhub = wiserHub(self.ip, self.secret)
File "/usr/local/lib/python3.7/site-packages/wiserHeatingAPI/wiserHub.py", line 101, in __init__
self.refreshData() # Issue first refresh in init
File "/usr/local/lib/python3.7/site-packages/wiserHeatingAPI/wiserHub.py", line 191, in refreshData
self.hubIP), headers=self.headers, timeout=TIMEOUT).json()
File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 890, in json
self.content.decode(encoding), **kwargs
File "/usr/local/lib/python3.7/site-packages/simplejson/__init__.py", line 525, in loads
return _default_decoder.decode(s)
File "/usr/local/lib/python3.7/site-packages/simplejson/decoder.py", line 370, in decode
obj, end = self.raw_decode(s)
File "/usr/local/lib/python3.7/site-packages/simplejson/decoder.py", line 400, in raw_decode
return self.scan_once(s, idx=_w(s, idx).end())
simplejson.errors.JSONDecodeError: Invalid control character '\x18' at: line 1 column 1185 (char 1184)
After a bit of hacking to print out the actual body of the response, the following was appearing in the binary string returned by the Wiser Heat Hub:
{"SSID":"\r!","Channel":6,"SecurityMode":"WPA_WPA2_PSK","RSSI":-91},{"SSID":"\x13!","Channel":6,"SecurityMode":"WPA_WPA2_PSK","RSSI":-94}
and according to https://jsonlint.com this isn't valid JSON.
I have solved this on my local copy by taking the body of the response, removing non-printable characters, and then passing that to json.loads(). I'll raise a PR for that shortly.
From scooper1/Issue46 (8th Feb)
return self.wiserHubData.get("Device")
AttributeError: 'NoneType' object has no attribute 'get'
This is happening because the return from wiserHub is not NoneType safe. Need to protect response and return an empty JSON array if no devices found.
This will prevent other errors from happening
Based on comments by @scooper1 asantaga/wiserHomeAssistantPlatform#46
it would be nice to have the ability to set schedules for devices. This would allow rather clever automation from products such as Home assistant, node-red etc and if the wiser app stops working then we could implement an alternative app..
Data for schedules is available from REST GET data/domain/Schedule/{scheduleid}
Shouldnt be too hard to create a service function which is simply get/set schedule for which HA could then use
It might not be common, but it is valid, for instance if you buy the 3 zone kit:
https://www.draytoncontrols.co.uk/products/Smart-Heating/Wiser/wiser-thermostat-kit-3
it doesn't come with any TRVs.
Looking at the openhab impl this can be done by using the following patch command
"{"RequestOutput":"" + (outputState ? "On" : "Off") + ""}";
"data/domain/SmartPlug/ is the endpoint
Required to resolve issue asantaga/wiserHomeAssistantPlatform#34
Hi, thank you for your great work on this and the Home Assistant plugin!
I just wondered if the api supports opening/closing a TRV manually rather than through setting the temperature (perhaps with the v2 api)?
I'll try to explain my reasoning behind this and what I'm trying to achieve. I have most of the radiators controlled with the smart TRVs and whilst I can set a minimum temperature for each room, once the temperature reaches this point it closes the TRV. What I would like to be able to do is perhaps set a maximum temperature as well so that the TRV remains open until that point but doesn't actually call the boiler for heat unless it's below the minimum temperature.
An example:
I don't need the spare room radiator to have a high minimum temperature because I'm not in there very often, but, if the living room/hallway radiators are calling for heat then it would be good for the spare room TRV to be open too to make use of that heat in case there's washing drying in there or something.
I have considered setting up some sort of automation via home assistant (if it's even possible) where if a radiator is calling for heat because it is below the minimum temperature, then those other TRVs which have not yet reached their max temperature automatically get set to 30 degrees (or something high) which would force them open. Then, once all radiators are over their minimum temperature, all TRVs get set back to their scheduled value as specified by the wiser app.
I hope that makes sense?
Thank you
Charles
I have seen a situation whereby setting the boost temp when calling setRoomMode causes an error from the hub that it is expecting an integer.
I think this is caused by the fact that passing a float value (ie 21.5) to the method maintains a float when passing to the hub.
Line
temp=boost_temp*10
needs to be
temp=int(boost_temp*10)
to ensure this cannot happen
Thx Mark
Hi,
Hope you don't mind these issues and appreciate input to this great HA integration.
One of the things that seems to be missing from the api is the ability to turn off a TRV, ie set to manual mode and set temp to -200.
I am thinking that if in setRoomMode if it should accept an 'off' mode which would have the following patchData
patchData={"Mode":"Manual","RequestOverride":{"Type":"Manual","SetPoint":-200}}
I have tested this with both postman and adding into the api and it seems to work.
The only issue I am not sure how to resolve is that if you then put it back to manual mode, the temp is still set to -200 and cannot be adjusted through lovelace thermostat card. I have, for now, done it so that when setting manual mode it uses the patchData above but uses the boost temp. I think it should have some logic to determine the temp set point when setting manual mode (current setpoint if coming from auto mode and some pre-determined setpoint if coming from off mode) or the ability to pass in the setpoint temp when going to manual.
What do you think?
Mark
Can anyone please advise. I have the following crash, which seems to be due to requests, and I'm not sure why:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/urllib3/response.py", line 437, in _error_catcher
yield
File "/usr/local/lib/python3.7/site-packages/urllib3/response.py", line 767, in read_chunked
chunk = self._handle_chunk(amt)
File "/usr/local/lib/python3.7/site-packages/urllib3/response.py", line 720, in _handle_chunk
returned_chunk = self._fp._safe_read(self.chunk_left)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 620, in _safe_read
chunk = self.fp.read(min(amt, MAXAMOUNT))
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socket.py", line 589, in readinto
return self._sock.recv_into(b)
socket.timeout: timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 751, in generate
for chunk in self.raw.stream(chunk_size, decode_content=True):
File "/usr/local/lib/python3.7/site-packages/urllib3/response.py", line 572, in stream
for line in self.read_chunked(amt, decode_content=decode_content):
File "/usr/local/lib/python3.7/site-packages/urllib3/response.py", line 793, in read_chunked
self._original_response.close()
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/contextlib.py", line 130, in __exit__
self.gen.throw(type, value, traceback)
File "/usr/local/lib/python3.7/site-packages/urllib3/response.py", line 442, in _error_catcher
raise ReadTimeoutError(self._pool, None, "Read timed out.")
urllib3.exceptions.ReadTimeoutError: HTTPConnectionPool(host='10.104.1.82', port=80): Read timed out.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "wiserloop.py", line 78, in <module>
wh.refreshData()
File "/Users/mh/wiser/wiserheatingapi-master/wiserHeatingAPI/wiserHub.py", line 161, in refreshData
WISERHUBURL.format(self.hubIP), headers=self.headers, timeout=TIMEOUT
File "/usr/local/lib/python3.7/site-packages/requests/api.py", line 76, in get
return request('get', url, params=params, **kwargs)
File "/usr/local/lib/python3.7/site-packages/requests/api.py", line 61, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python3.7/site-packages/requests/sessions.py", line 530, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python3.7/site-packages/requests/sessions.py", line 683, in send
r.content
File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 829, in content
self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b''
File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 758, in generate
raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='10.104.1.82', port=80): Read timed out.
This is my simplified code:
print ("connecing")
wh = wiserHub.wiserHub(wiserip, wiserkey)
p = pyprowl.Prowl('xxxxx')
try:
p.verify_key()
print("Prowl API key successfully verified!")
except Exception as e:
print("Error verifying Prowl API key: {}".format(e))
exit()
print("-------------------------------")
print("starting up")
print("-------------------------------")
print ("Model # {}".format(wh.getWiserHubName()))
heating = wh.getHeatingRelayStatus()
hotwater = wh.getHotwaterRelayStatus()
while 1:
wh.refreshData()
if not (hotwater == wh.getHotwaterRelayStatus()):
hotwater = wh.getHotwaterRelayStatus()
print(datetime.datetime.now().time().strftime('%H:%M:%S'), end = ' ')
print("Hot water status {} ".format(hotwater))
sendWaterNotification(datetime.datetime.now().time().strftime('%H:%M:%S') +' '+ hotwater)
if not (heating == wh.getHeatingRelayStatus()):
heating = wh.getHeatingRelayStatus()
print(datetime.datetime.now().time().strftime('%H:%M:%S'), end = ' ')
print("Heating status {} ".format(heating))
sendHeatingNotification(datetime.datetime.now().time().strftime('%H:%M:%S') +' '+ heating)
time.sleep(30)
The error occurs after a random amount of time - minutes to hours. Any help would be appreciated, thank you.
On line 1010 of wiserHub.py currently is 'return plug.get("ScheduledState")'
This line should be returning the output state, I suspec this is a coding error when the function body was copied and pasted from elsewhere.
As a result it always reads "None" as the output state. I corrected this line in my code to:
return plug.get("OutputState")
Running wiserapitest.py I get an error. Here is the relevant part of the error report:-
......\wiserHeatingAPI\wiserHub.py", line 323, in getRoomSchedule
scheduleId = self.getRoom(roomId).get("ScheduleId")
AttributeError: 'NoneType' object has no attribute 'get'
I am running Drayton Wiser Hub API v 1.0.5 with Python 3.8.1 in Win 10 Version 10.0.18363.592
Hi,
When trying to set a temperature set point on a iTRV, the limit imposed by the Wiser Hub is between 5C and 30C ie (50 and 300) or -200 - being Off.
In the api this limit is set between 1C and 40C and will not allow -20C to allow turning off of the iTRV.
Please could this be updated to allow the correct restrictions of the Hub.
For note, you could remove these restrictions all together as setting outside these parameters gives an Error 400 with the below message returned.
{
"Error": "Manual override requires a 'SetPoint' between 50 and 300 or -200 (i.e. from 5 to 30 degreesC or Off)"
}
This could suffice as the error message?
Thanks and thanks for a great api!
Mark
Possible to get events that happened on the hub e.g. sending signal to boiler to switch off/on? Or even thermostat sending signal event to the hub? Want to capture these info for analytics.
Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.