ZHA Thermostat

I re-downloaded and now the climate.py is included in the zha directory. Not sure why it was missing the first time. I am currently traveling, so I will retry later this week to see if it now works. I suppose it should work since the HA Zigbee Management detects all the clusters. So, it looks to be pretty much standard and doesn’t use vendor specific clusters.

I just tried again with a version that included climate.py. But now my zha fails completely since it can’t initialize the zigbee device (/dev/ttyUSB0).

2019-06-20 14:52:51 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry /dev/ttyUSB0 for zha
Traceback (most recent call last):
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/config_entries.py”, line 310, in async_setup
hass, self)
File “/home/homeassistant/.homeassistant/custom_components/zha/init.py”, line 94, in async_setup_entry
await zha_gateway.async_initialize(config_entry)
File “/home/homeassistant/.homeassistant/custom_components/zha/core/gateway.py”, line 69, in async_initialize
self.zha_storage = await async_get_registry(self._hass)
File “/home/homeassistant/.homeassistant/custom_components/zha/core/store.py”, line 160, in async_get_registry
return cast(ZhaDeviceStorage, await task)
File “/usr/lib/python3.5/asyncio/futures.py”, line 380, in iter
yield self # This tells Task to wait for completion.
File “/usr/lib/python3.5/asyncio/tasks.py”, line 304, in _wakeup
future.result()
File “/usr/lib/python3.5/asyncio/futures.py”, line 293, in result
raise self._exception
File “/usr/lib/python3.5/asyncio/tasks.py”, line 239, in _step
result = coro.send(None)
File “/home/homeassistant/.homeassistant/custom_components/zha/core/store.py”, line 155, in _load_reg
await registry.async_load()
File “/home/homeassistant/.homeassistant/custom_components/zha/core/store.py”, line 112, in async_load
power_source=device[‘power_source’],
KeyError: ‘power_source’

looks like this error is unrelated to the ZHA thermostat implementation. If I remove the custom_components directory I still get this error.
Crap, my ZHA worked before and now it has broken. It must have been the last (or the one before last) update that broke it, because I haven’t changed anything except testing this custom ZHA thermostat deployment.

EDIT:
I found the error with my ZHA in general. 0.90 broke it when the store.py was introduced. When I go back to 0.89.2 my ZHA works again.

Now the bad news for me and your thermostat custom component - your component is apparently also based off the 0.9x release since you have a store.py and I get the same error I was getting before downgrading to 0.89.2. You think there is any way of getting your climate component working in the 0.89.2 HA release?

I guess you could apply the branch diff to 0.89.2 and see what happens? Although your should probably figure out why your ZHA doesn’t work on 0.90. Maybe you need to edit your ZHA database.

Yeah, from looking at the store.py file and the errors I get it looks like it us looking for keys in the DB (power_source) that don‘t exist. The question is what should I fix in the DB? I know how to modify SQLite DBs. But I did delete the DB I had and let it be recreated after reinstalling the ZHA integration while in 0.9x. So, I suspect the issue is not in the general DB structure. Maybe certain data is not added to the DB for my Zigbee USB device when ZHA is reinstalled and associated with the device using ezsp. Do you have any idea what the power_source (the one in the line after it in store.py) data would be that needs to be associated with a zigbee USB stick?
I would like to fix 0.9x instead of remaining on 0.86.2.

OK, I got it fixed. There was a messed up file (zha.storage) in the homeassistant users directory structure.
Now my ZHA works in 0.9x and your custom component works as well. Although the standard thermostat card in Lovelace doesn’t seen to work properly. If I change the temperature in that “dial” it doesn’t change the heat set point on my thermostat. The only thing that seems to work in that card is the “Off” button. Unfortunately, hitting it a second time doesn’t turn the thermostat back on.
So, I need to look for a better thermostat card for this thermostat. Maybe this custom simple thermostat card will do the trick: Lovelace: Simple thermostat card

I am using the Lovelace cards and it works ok for me.

What is the ctrl_seqe_of_oper attribute set to in the Thermostat cluster?

The ctrl_seq_of_oper value is 2.
The card can display the current temperature and it shows an off button (because the operations_list only has off in it). The off button apparently controls the system_mode cluster and sets it to 0. I can manually set it back into an operational state by using the ZHA management and setting the value to 4. Then the thermostat goes back into its normal operating state.
This thermostat has clusters for heat and cool set points (occupied and unoccupied), although the only one that needs to be set is the occupied_heating_setpoint cluster as all this thermostat does is switch a mains connection on or off (using it to turn a infrared heater on and off when the heat set point is reached). If I could only get the heat setpoint control to work, I think I would be set to go.
Currently the heat setpoint control of the standard card just shows me whatever I set it to. It never shows the current value or even changes the value on the thermostat.
I tried a custom thermostat card (Simple Thermostat - https://github.com/nervetattoo/simple-thermostat). But it has a similar behavior. It will show the current temperature and the current state (Heat or Off). But the setpoint always displays “N/A”. Even if I do set a value there, it will eventually return to N/A.

EDIT: just noticed that the ctrl_seqe_of_oper value 2 (or 0x02) means “Heating Only”. Makes sense, since it is only controlling a heater by turning it on and off when the heat setpoint is reached.
Question is, how can I get the card to understand that it only needs to set the occupied heat setpoint?

It uses a cached value on boot for ctrl_seqe_of_oper, maybe this didn’t get stored properly. You can look in the zigbee.db and see if that attribute is there. The climate component configures itself based on that value when it starts up.

It would look like INSERT INTO attributes VALUES('addr',ep,513,27,2), the “513,27,2” being the key values, and addr and ep being specific to your device.

If might actually be in there now that you read it manually. Perhaps a restart of HA is all that’s needed.

Yeah those values already exist in the DB. And I have restarted HA multiple times. So, I don’t think this is the reason for not being able to set heat set points from the card.

EDIT: interesting. Now the card is reading the existing heat set point and displaying it. So, now I see the current heat set point, temperature and status.
But, when I try to set a new heat setpoint I now get a traceback error in my HA log:

2019-06-27 13:42:43 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection.1747786992] name ‘ATTR_TEMPERATURE’ is not defined
Traceback (most recent call last):
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/websocket_api/commands.py”, line 121, in handle_call_service
connection.context(msg))
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/core.py”, line 1150, in async_call
self._execute_service(handler, service_call))
File “/usr/lib/python3.5/asyncio/futures.py”, line 380, in iter
yield self # This tells Task to wait for completion.
File “/usr/lib/python3.5/asyncio/tasks.py”, line 304, in _wakeup
future.result()
File “/usr/lib/python3.5/asyncio/futures.py”, line 293, in result
raise self._exception
File “/usr/lib/python3.5/asyncio/tasks.py”, line 239, in _step
result = coro.send(None)
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/core.py”, line 1172, in _execute_service
await handler.func(service_call)
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/entity_component.py”, line 194, in handle_service
required_features
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/service.py”, line 316, in entity_service_call
future.result() # pop exception if have
File “/usr/lib/python3.5/asyncio/futures.py”, line 293, in result
raise self._exception
File “/usr/lib/python3.5/asyncio/tasks.py”, line 239, in _step
result = coro.send(None)
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/service.py”, line 339, in _handle_service_platform_call
await func(entity, data)
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/climate/init.py”, line 559, in async_service_temperature_set
await entity.async_set_temperature(**kwargs)
File “/home/homeassistant/.homeassistant/custom_components/zha/climate.py”, line 389, in async_set_temperature
temperature = kwargs.get(ATTR_TEMPERATURE)
NameError: name ‘ATTR_TEMPERATURE’ is not defined

Ah yes there was a slight bug there. I do not have a heating only thermostat to test. Get the latest climate.py from my Github and try it again.

YES!! That fixed it. Awesome. I didn’t download a new version though. I just made the slight change manually (added the missing attribute).

Thanks a lot for your support.

Now I get this:
01

The Off button turns off heating and the “Fire” button can manually turn it back on. This is exactly what I was wanting.

Oh, and yes, it is actually that hot in the room right now. Very hot summer in Germany. :wink:

I’m glad it is working for you. :+1:

I see your thermostat also reports the currently active state, shown as “Off”. This is a nice optional feature, only one of my thermostats does that. Hopefully the new climate component supports this properly, with the old one it’s not technically supported.

If you update the mode or setpoint at the actual thermostat itself, HA should update in turn. Give it a try and let me know if there is a problem there.

Yes, it works as I wanted it to. The state changes between “Off” and “Heat” when the relay switches between on and off. And the two buttons below lets me manually switch between those two modes as well. The main difference being that the manual “Off” button turns the thermostat off independent whether the heat set point has been reached or not. So, very good.
And yes, when I change the heat set point on the thermostat directly it almost immediate reflects in the HA card.
Maybe you can help me with another thing I want to accomplish. I am new to HA and I am setting this up for a mobile home I have where we are installing two infrared heating panels. I wanted HA so I can remotely control these heaters (and potentially set up a few web cams). What I need to do is set a base temperature during the winter or while we aren’t occupying the mobile home and prior to driving up to the mobile home I would remotely set the temperature to normal temperature to warm up by the time we arrive. I could of course just manually dial in the temperature on both thermostats. But, I would like to have an easy button to set both thermostats to either a winter or living temperature. I tried setting up “Entity Buttons” for this, but first off they only apply to one entity (I can’t set two thermostats at once) and it doesn’t seem to keep the service_command I set. The service_command works initially, but as soon as I want to edit the Entity Button the configuration is gone.
Is there a better way to do this? With both a press and a hold function I could even accomplish this with one button (press = set normal temp, hold = set winter temp) if I could just set temperatures multiple entities at once.
I know this is typically what the occupied and unoccupied temperatures are for, but although my thermostat has the unoppucied_heating_setpoint cluster it doesn’t seem to be used in my thermostat. Or at least I haven’t figured out how to tell it whether it should be in occupied or unoccupied mode. The thermostat card only sets the occupied_heating_setpoint. I can manually set the unoccupied_heating_setpoint via the management console, but without being able to tell the thermostat to use that temperature it seems useless. That would be the easiest solution if I could just switch between “occupied” and “unoccupied” whereas the unoccupied temperature is set once and left alone.
Any suggestions?

The “occupied” setpoint only works if the thermostat itself has an occupancy sensor. This is really for a more advanced thermostat system, I doubt your simple thermostat has this. Does the Thermostat->occupancy attribute show something other than None? In any case my code does not support this.

What you want to do is use automations combined with an input_boolean. You will create a input_boolean called something like “Away mode”. This mode can be changed manually or by some other automation (like your smart phone location). Then you will set up two automations that are triggered, one by the mode changing to on and one for changing to off. And in those automations you will then set the thermostat setpoint using climate.set_temperature as desired.

Thanks. The occupancy cluster always shows 1 (occupied) and is read-only. So, like you say it would need an occupancy sensor (local or remote) to set it and the remote sensor cluster is set to None. So, I suppose it is not possible to make it use an external sensor.
But anyway, I did find a way via scripts. I created two scripts, one for setting the normal temperature and one for setting the unoccupied temperature (using climate.set_temperature) for both thermostats. I could then create one Entity Button with a push and a hold action to trigger the two scripts.
I actually think it would be more sensible to have Away and Present modes to trigger these. The end result would be the same I suppose, just more logical.

I have updated this for 0.96 with “Climate 1.0” and pushed to my repo.

@rpress, thanks for your work on this. It seems to be working perfectly with my Zen thermostats on HA 0.99.3. This gets me one step closer to ditching SmartThings.

Thanks again!

1 Like

@rpress, Thank you so much for this work. I’m at version 0.102.1. Can I try out your code using the same instructions that you gave before? That is,

“You can download that branch from my repo, and then copy the homeassistant/components/zha folder into a folder named custom_components/zha off your config directory. Restart hass and see what’s in your logs.”