Introduction

I've got three of my radiators controlled and monitored from a central PC using, Z-Wave for comms. This page describes all the basics, problems and what I've done. This is about as close as I'm getting to IoT, with it strictly being an intranet of things. But first, a couple of pretty graphs, showing a typical cold few days:

Graphs showing temperature and valve position for my radiators
  1. My heating system
  2. Radiator valves
  3. Valve standards
  4. Z-Wave
    1. Using z-wave devices
  5. Eurotronic Spirit Z-wave Plus
    1. Using the Spirit
    2. Software view of spirit
  6. Software
    1. Spirit vs Home assistant
    2. Break out the python
    3. Some gotchas in Open ZWave
  7. Trick one: Cooler in the day
  8. Trick two: Dealing with Spirit getting too hot
    1. Detecting overheat
    2. Turning it really off
  9. Future ideas

My heating system

The heating system I have is a typical UK gas fired boiler, which is controlled off a single, centrally mounted thermostat, and which heats water that is pumped around a set of radiators, typically one or two per room. The radiators each have a radiator valve; there's no connection between this valve and anything central normally.
The boiler is also on a time clock, so it's switched off from about 11pm to 6:30am. In the graph above you can see how the rooms get colder over night, until the boiler pings back on and it starts to warm up again. The same boiler also switches to doing hot-water supply whenever the hot tap is open, and that's independent of the time-clock or central thermostat. As is normal now, it's a 'combi' boiler that can actually only do heating or hot-water at a time; so it priorities hot water use, which means if someone is taking a shower, the heating gets a bit colder.

Note, so far at least I've not touched the actual central thermostat or time clock; all I've done is fiddle with the radiators.

Radiator valves

The radiators each have a valve, which is typically based on a wax cylinder that expands and contracts with temperature - these are 'TRVs' - 'Thermostatic Radiator Valves'; they typically have non-calibrated settings (e.g. 1-5) and vaguely control the temperature. I've been getting annoyed by just how uncontollable they are.

The valve is actually made of two parts that are held together with a screw thread; the actual valve part that sits in the water flow, and the thermostatic 'head' with the control on which connects to it. The two are connected by a short plunger which the head presses to decrease the flow. Since they're separate you can replace the thermostatic bit without having to deal with the actual valve and hence you don't need to deal with plumbers or drain the system.

There are various replacements you can buy, from simple digital thermostatic things, to wirelessly controlled things, which is where I looked at.

Valve standards

It looks like very little was standardised, although it's getting better. The screw thread between the actual valve and the head seems to have settled out on newer things, but can be an arbitrary pitch or height. The travel on the plunger, and it's heighest and lowest points aren't standardised. Whether the valve is in the incoming or return water flow varies (although it's now tending to be on the return side). The orientation of the valve also varies. Many electronic TRVs come with a selection of converters for different radiator valves. In my case two of my radiators took the standard fitting, and one I had to buy a metal converter and then forcibly tweak it by adding a piece of brass offset to get the height just right.

Z-Wave

There are various wireless protocols for communicating between IoT devices, all of which are incompatible. These include Zigbee, low power bluetooth variants, and WiFi - and Z-Wave. WiFi is generally not used on smaller devices, like TRVs, because it's too power hungry to last for ages on a battery.

Z-Wave is low power, supports encryption, and importantly for me is supported by the Open-zwave project, and a lot of projects that build upon it.
You need something somewhere as a controller (or potentially two controllers); most are little USB dongles such as the UZBthat I'm using. Note that the frequency of controllers and devices varies depending on some geographic regions so you might need to check which hardware you've got or at least how it's configured.
I'm finding it's OKish spanning one floor of a largish house; my z-wave dongle is at one side of the house, and there's a couple of walls and stuff in between the furthest radiator; sometimes it struggles a bit. It's probably not helped by UK radiators having the valves near the bottom, and also being radiators they're big chunks of metal that get in the way. But I've even seen problems in shorter spaces when something (e.g. me) gets in the way.
In theory Z-wave devices can form a mesh to find a better RF path from dongle to device; but the gotcha there is that only 'powered' devices can act as mesh repeaters; which since all my devices are battery powered TRVs doesn't help me.

Note actually most devices these days are Z-Wave Plus, and it's generally best to check all devices in the set are.

Using z-wave devices

Once you've set up your controller on your host, when you get a Z-Wave device you have to 'include' it in your network; this normally involves telling the controller to go into an include mode and then pressing some sequence of keys on the device. You can kick a device off the network later by doing an 'exclude'. During an 'include' the device gets assigned an 'id' unique to your network; if you exclude and include it again the id changes.

Z-Wave is designed to be low power, so can work in a mode where the device only transmits when something interesting happens (e.g. it notices a temperature change or a valve level change), but this can be fragile with battery powered setups, so you can also just poll, at the expense of faster battery usage.

Eurotronic Spirit Z-wave Plus

The Spirit is at the time of writing one of the newer devices from Eurotronic and caught my eye because, it had a nice big display, said it was compatible with most valves, I noticed it could read the valve position over z-wave, and set it (but see below), and it was pretty cheap. I find the valve position interesting to see if the reason a room is cold is because the hot water supply isn't hot enough. I bought mine from Reichelt.

Spirit TRV on radiatorA Spirit in place on a radiator, with a converter.

Since it's the only device I've used I can't compare with others, but they're pretty good, but have some quirks which I'll describe below. I've changed one set of batteries on one of the devices after about 6 months (when it dropped below 15%). It's not silent, but it's not too annoying for me.

Using the Spirit

When you unpack the spirit and add batteries the first thing it wants to do is to be included into your Z-Wave network. You can do this away from the radiator it's going to be used on; this is useful since some of the discovery stuff for inclusion seems to be lower power. Once you've included it in your network, it then wants to be placed on your valve. When you do this and press the buttons, it 'learns' the valve by pusing the plunger and seeing how far it goes and seeing when it first touches it. That's pretty neat, because as I say above, there's no standard for the valves. If it doesn't like a valve (e.g. when I tried a converter) it spits an error saying it can't find one limit of the range.

Once connected, it looks like a fairly boring thermostatic valve with +/- buttons to change the current temperature setting. Tapping the big square button gives a few minute 'full' power boost. Holding the square button does the exclude and other features like that. I've found in most cases where the Z-Wave setup puts it in an odd state, pressing + gets it back to it's normal 'heat' mode.

Picking a temperature can be tricky, especially on the radiators where it's on the inlet side, since the temperature being read is heavily affected by the water temperature rather than the room temperature, so you have to set it a bit higher than you want the room.

Software view of spirit

The spirit mostly looks like a thermostat to Z-Wave (i.e. it responds to the thermostat command class); however it's a bit more complex than that because it's got a number of 'modes'; 'Heat', 'Heat Eco', 'Off', and 'Furnace/Full'. The normal is 'Heat', and 'Heat Eco' has a separate set-point temperature. 'Off' isn't actually off, but it just keeps it above freezing. The 'Furnace/Full' is something I've not tried.

However, the Spirit also looks like a 'multilevel' (aka Dimmer) because of the reading/setting of the valve level.

Software

On Linux, Z-Wave controllers are pretty much ignored by the kernel - the controller I use just looks like a USB-serial controller (which it probably has before a Z-Wave chip). The normal way to control it is through things built on Open ZWave, which has bindings for lots of languages. It also has configs for lots of devices, including the Spirit. One of the larger 'easy' projects is Home assistant which can control lots of things using lots of different protocols, including ZWave.

Note that because the controller isn't really known to the kernel, and the kernel doesn't know about the Z-Wave protocol, there's no way to share a controller between processes, or for example assign one Z-Wave TRV to one process directly. Only one thing can be using the Z-Wave controller at once. In reality things like Home assitatn have their own ways of dealing with it, and there are other schemes built around queuing systems.

Another more trivial program is the Open zwave control panelaka OZWCP; it's clunky but it lets you do the basics like include/exclude devices and prod to see the state of things and poke at device configs (e.g. invert the LCD orientation on the Spirit).

Spirit vs Home assistant

I found Home assistant didn't get on with the Spirit that well; each of the separate modes were shown as separate dials, showing 3 separate temperature readings from one device. The valve state wasn't anywhere to be seen. There's some discussions on how to make these available, and it might be better now, but it's not something I pursued.

Break out the python

I started looking at some of the Open ZWave python binding examples and it looked easy and pretty well documented, and it's worked out pretty well. In a little under 200 lines, I've got full graphing of everything (using my existing grafana installation) and I've got two 'specials' that I'll describe below. Here is my code, I should warn you Python is not my best language!

I'm polling every 10 minutes that works out OK for the graphs, and the tricks I suggest below, but a bit faster could be nice for some of the overheating problems.

Some gotchas in Open ZWave

I found I got a lot of dropped/failed commands at first with weak signals. I added an:

  options.set_driver_max_attempts(7)
  
which seems to get it to retry OK most of the time. I graph round trip times and that shows me when it's having problems.

Each of the values associated with a node is accessed through a value id; note these are different even for multiple instances of the same device. So at initialisation time I go through and extract the value id from the label (e.g. Mode) and store it away on the node for later use; I'm surprised that Open ZWave doesn't do this for you, but I don't see it. The net result is the fairly easy:

  temp=node.values[node.dg_valid_temp].data_as_string
  
for getting the current temperature.

Trick one: Cooler in the day

The first trick I've taught it, is to turn my bedroom radiator down during the day and turn it back up in the evening. At the moment these are just midday and 6pm times but it would be interesting to change those based on outside temperature. I do the difference in temperature by setting the Spirit's 'Heat Eco' mode to a cooler temperature and flipping it into 'Heat Eco' at midday-ish, and back to 'Heat' at 6pm. Note this means if you hand modify the temperature with the +/- buttons this changes back to Heat and remembers your new setting in Heat mode, which is nice and transparent. The code to do all this is pretty simple:

    # Bedroom doesn't need to be heated much in afternoon
  if (not "david_trv_afternoon" in today_done) and now_hour == 12:
    today_done["david_trv_afternoon"] = 1
    TRV_davids_node.values[TRV_davids_node.dg_valid_mode].data = "Heat Eco"
    print("Davids bedroom afternoon cool")

  # Bedroom does need to be warm in the evening
  if (not "david_trv_evening" in today_done) and now_hour == 18:
    today_done["david_trv_evening"] = 1
    TRV_davids_node.values[TRV_davids_node.dg_valid_mode].data = "Heat"
    print("Davids bedroom evening warm")
  

Trick two: Dealing with Spirit getting too hot

While I find Spirit's behaviour on cold days to be pretty good; I'm finding it's hot day behaviour to be poor:
overheating
When the boiler switches off due to the central thermostat on a hot day, if the temperature on a given TRV is below the set-point, the Spirit keeps opening the valve in a desperate attempt to get some heat, so over time it will hit fully open. This is especially true on TRVs on the inlet side where you set the temperature quite a bit higher than you want it, and when the water goes cold that offset isn't valid any more.
When the boiler comes back on, the spirit starts decreasing the valve level, but for no apparent reason (and Eurotronic didn't reply to my query) stops decreasing and levels out much more slowly. There's no programmatic control over it's feedback system. So now you're left with hot water and a fairly open valve, so you rapidly go over temperature.

Detecting overheat

I check the valve level is fairly open, and the temperature is well above the threshold and it stays that way for 2 sample periods:

    if mode == "Off":
    ....
    else:
        # It's on, see if it's over temperature and the level is high
        if ((temp+offset) > (heat+0.0)) and (level > 10):
          node.dg_overheat_count +=1

        if (node.dg_overheat_count >= 2):
          do something....
  

The 2 sample periods (10 mins each) is a bit long here, it still overshoots by a few degrees; I might reduce the sample period or make a second threshold where if the level is much too high on the first sample it starts earlier.
The apparently obvious thing to do was to set it to 'Off', except experimentation showed this didn't actually turn it off; I think 'Off' is really a special 5c setting rather than really off. This got me into using the direct control of the valve.

Turning it really off

The docs say that you have to put it into the special 'Manufacturer specific' mode to have direct control, I ended up with:

        node.values[node.dg_valid_mode].data = "Off"
        time.sleep(5.0)
        node.values[node.dg_valid_mode].data = "Manufacturer Specific"
        node.set_dimmer(node.dg_valid_dimmer, 0)
  
which seems to do the trick - but I did find I couldn't set any other value that 0; I've never managed to set a higher valve level.
When reading back the mode, it never comes back as 'Manufacturer Specific', it seems mainly to come back as the previous mode, which is why I set it to 'Off' here, so I can then check it to know whether I should be thinking about switching it back on.
Note that when it's in valve mode, the display on the Spirit changes to just a level value without the decimal point.

It's also a bit tricky getting out of that mode, I've seen it flip betwene modes by itself, even though I've apparently not sent any other command; my current code switches it to 'Off' and then 'Heat' but it doesn't actually recover for a second cycle of doing that.

The results are nice though:
shut off
Where we can see that when the boiler kicks in at around 10pm, the Spirit starts cutting back, and then for some reason plateaus, and then we see the sharp drop from the code above.

Future ideas

I've got quite a few ideas; e.g. detecting when I'm writing stuff at 3am and deciding that my office doesn't need to be warm the next morning since I'll still be in bed.

(c)David Alan Gilbert 2019

mail: fromwebpage@treblig.org irc: penguin42 on freenode | matrix: penguin42 on matrix.org | mastodon: penguin42 on mastodon.org.uk

My home page