Alternative code for handling TRVs (StellaZ and Danfoss)

Maybe…:flushed:
In novebner i bought 4 StellaZ valves, and 2 was wrong…

FYI I’ve just had a Stella replaced under warranty and the replacement one is also faulty. No LEDs showing at all…maybe a bad batch ?

Another one bites the dust.

Thanks, slajgaj and dmckenna, that’s very useful information. My supplier is now in contact with the manufacturer about this.

I have now started testing and implementing the new method. First impression is very good, testing at the moment with my Horstman thermostat, which was causing me most problems. Mainly as it seems to change the wakup time from 240 secs to 256 secs, without me doing anything.
One thing I would like to see if that is possible, is when the TRV lua code restarts the Vera, I would like to have a notification ideally via Vera alerts if that is somehow. For the reason I want to see which restarts are due to the TRV lua and which are caused by other problems. It doesn’t have to be Vera alerts, but that would probably the best way as I see all Vera restarts and reboots there.

Question. My Horstman main heating thermostat keeps changing its wakeup time to 256 seconds. All my TRV’s are set to 240 secs. Is that going to be a problem ? Or should I change the TRV’s to 256 secs as well ?

[quote=“dmckenna, post:42, topic:184764”]FYI I’ve just had a Stella replaced under warranty and the replacement one is also faulty. No LEDs showing at all…maybe a bad batch ?

Another one bites the dust.[/quote]

Okay, so my supplier went through each and every Stella-Z that they had in stock. Only a handful was working.

The good thing is that I will be getting a set of working Stella-Z very soon. The bad thing is that the manufacturer seem to have sent out quite a few bricked devices…

Was wandering if any one has tried this method with PLEG. I am aware that PLEG doesn’t work with global variables, maybe the experts can help.
David

@Dunked, (and anyone else)
Just back to the forums after a Christmas break, and thought I would pass on the changes I have been making to my TRV code. This is based on your original concept of waiting until just before the wakeup and sending the update, but I have bypassed the need to set up watches and wait for the first cycle to complete.
I have stopped trying to do the original callback in PLEG, as it was getting a bit horrendous, even with D McKenna’s spreadsheet version. So I am now using LUA and a delayed callback. This does not need the watch setting on each TRV update, and so reduces overheads.

When a change of setting is requested, the code checks when the TRV last woke up, adds 4 minutes onto that (less 5s) and sets a single delayed call to the update function.
Thus 5s before the TRV is due to wake up, the function is called, checks the value to be output, and writes it to the TRV. Simples!

I have not fully bomb-proofed it like your code, although I do check for non-responsive devices - but have been using this for a couple of months now without problems, I have not been getting the “sleepy valve”, or queued changes problem, as only one change is in the queue at any time. It also allows manual changes to be made through the normal TRV widget.
Another benefit I had not realised is that my temperature readings seem to vary quite normally, they are certainly not stuck at Setpoint + 1. I will have a look at doing a bit of substitution of this into your code, especially as the calling process I have looks very similar to your function e.g.
call:

TRV.SetRoom(TRV.Front_Guest,"RoomOccupied")

I have two basic functions - the first (SetRoom) is called with the device ID and a string, (which is a label for a general temp setting, eg “Frost” or “RoomOccupied”, This is looked up from

another Variable Container.) but it can also cope with a direct number being passed to it.
The function checks the current settings and if a change is needed, and there is no call pending, it sets up a luup.call_delay to the second function. This will fire 235s after the previous WakeUp. I save the required settings in a global variable, so, should there be multiple requests, only the latest value is output.

The second function (SetRoomDelayed) retrieves the Dev ID and the required setting, checks again that a change is needed, and issues it. This seems to be working - I have set a 5s lead time and 240s TRV update, with default polling. I have not observed it missing any calls (I have developed some other code that gives me a status panel to check on this).

There is also an initalisation process; the flag is set at startup so that the global arrays are populated on first call to SetRoom.

To use, I have a set of scenarios which call the function with the TRV ID and the desired setting. I can run these manually, but also call them from PLEG controllers.

Declarations:

--Device IDs for TRVs TRV = { Hall = 32, Back_Guest = 52, Lounge_Back = 57, Main_Bed =58, Front_Room = 59, Front_Guest = 60, Craft = 63, Lounge_Front =69, Kitchen = 72, arraySetting = {}, arrayChangeTime = {}, arrayTarget = {}, Service ="urn:upnp-org:serviceId:TemperatureSetpoint1_Heat", Wakeup ="urn:micasaverde-com:serviceId:ZWaveDevice1", Initial = true }


Primary function to set TRV:

[code]-------------------------------------------------------
function TRV.SetRoom (TRVid, Setting)

TRV.arraySetting[TRVid] = Setting – Save latest setting in array

–Get current value of TRV
local Current = luup.variable_get(TRV.Service, “CurrentSetpoint”, TRVid)
local Temp = tonumber(Setting) or VContainer.get(Setting) --look up setting in degs
local timeNow = os.time()
local nextCallTime = TRV.arrayChangeTime[TRVid] or timeNow
luup.log("SetTRV- Input: "… TRVid … “, Setting=” … Setting … Temp … "C, Current = " … Current… "C, Secs to next call: " … nextCallTime - timeNow )

if (Current ~= Temp) and (nextCallTime <= timeNow ) then – if already same or a timer is already running then drop out to end
local LWU = tonumber((luup.variable_get(TRV.Wakeup,“LastWakeup”, TRVid))) or 0 – Get last Wakeup or default
local strTRVid = “”… TRVid

–luup.log("SetTRV- Input: "… TRVid … ", " … Setting … "=Setting, LWU = " … LWU )
local Tdiff = timeNow - LWU
local delay = 0

if (Tdiff> 240) then – NOT new device or dead - don’t wait
delay = 1
elseif Tdiff > 235 then
delay = 475 - Tdiff – missed this one wait 240+240-5secs from last update
else
delay = 235 - Tdiff – wait for next wakeup
end

TRV.arrayChangeTime[TRVid] = timeNow + delay

luup.log(“SetTRV-Output: " … strTRVid … “, Wait: “… delay … “s, until: " … os.date(”%X”,TRV.arrayChangeTime[TRVid]) …”, Dev:” … strTRVid … “, to:” … Setting …“, t since last update:” … Tdiff)

if TRV.Initial ~= true then – on start just set up array values, leave current TRV settings as they are.
luup.call_delay(‘SetRoomDelayed’, delay, strTRVid)
end
end
end
------------------------------------------------------[/code]
Second function - called by system just before TRV is due to wake up:

[code]function SetRoomDelayed (strTRVid )

–Timer has expired, so TRV wakeup is due any second.

local TRVid = tonumber(strTRVid)
local Setting = TRV.arraySetting[TRVid] or “Frost”
– Get Setting from global array, ensures latest value is o/p, or Frost in case there has been a reset since the value was saved.

luup.log(“SetTRVDelayed: Dev:” … TRVid … " to: " … Setting)

–Get current value of TRV
local Current = luup.variable_get(TRV.Service, “CurrentSetpoint”, TRVid)

– If setting is number, then use that, otherwise look up corresponding temp in variable container from setting (Frost, Occupied etc)
local newTGT = tonumber(Setting) or VContainer.get(Setting)

TRV.arrayTarget[TRVid] = newTGT – Save new target temp

–IF they are different THEN output new value
if (newTGT ~= Current) then
luup.call_action(TRV.Service, “SetCurrentSetpoint”, {NewCurrentSetpoint = newTGT }, TRVid)

luup.log("SetTRV done.Id: " .. strTRVid .. " set to " .. TRV.arrayTarget[TRVid] .. "C" )

end
end
[/code]

Initialisation:

TRV.Set_Rooms(ToD) -- a function that sets all rooms depending on the Time of Day, using individual calls as per example above. In this case it will preload the global Array with the appropriate values whenever Vera restarts TRV.Initial = false -- clear initialisation flag

I am using the original my_TRV_module.lua v1.2. It is working well with my Stella Z’s. It does not play well with my Horstman room thermostat. It could be as my StellaZ’s are set to 240 secs wakeup, the Horstman will not do that, it always reverts back to 256 secs. I think that is the reason I sometimes have a lot of reloads and a long time for the new setpoint to change.
If we could have a variable in the next version, where I could set a wakeup time other than 240 secs, I could set everything to 256 secs which probably would improve things considerably.
Another thing I noticed, I get the occasional random setpoint sent to the Horstman. I have checked my PLEG’s, and its not sent by PLEG. It is a setpoint which can only be activated manually. Other times it changes my setpoint from the normal 20 degrees to 18 without any action from user or PLEG’s. The problem then is, I have to set it to 18 to be able to send 20 again. If I do a quick change down to 18 back up to 20 that does not work, so if it does these randon changes it takes quite a while to get it back to where it should be, unless I am at home and can turn it manually. Not sure whats happening there and why. But I checked all the PLEG’s and the wife, none of them was responsible for the changes…
But overall my system has become more responsive, and it is a very good solution

Am going to try giving this a go later on UI7 on EDGE, standby…

@Dunked - is 1.2 the latest version - which one ? (there’s two with the same title in the first post)
@Octoplayer - is your code above separate to 1.2, or your own, or a 1.2b release ?

Cheers

David

I’ve just uploaded version 1.3 to the first post in this thread (and deleted the older versions so save any confusion!).
Just a a few bug fixes and hopefully some improvements in the reload when stuck routines.
There is one new function I’ve added TRV.setall(tgt,boost) - best if run from the test luup code box. It sets all TRVs being managed to a setpoint of tgt for boost minutes (after the boost it puts it back to what it was when it started). tgt can be an absolute number like 20 (for 20 degrees) or a delta such as “+2” or “-1” which will set TRV to whatever it is plus or minus the delta - note if you do use a delta (esp with a plus sign) you need to put the tgt values in quotes e.g TRV.setall(“+2”,30) - set all TRVs up by 2 degrees for 30 minutes. If you miss out the boost bit (e.g TRV.setall(5) ) then all TRVs are changed without any boost so TRV.setall(5) will set them all to 5 effectively turning them off. I added that bit to help me with testing mass changes it seems quite handy - and it’s nice when it goes through all TRVs without any retries (it does happen occasionally!). Though I’m not sure what practical use it may be.

Horstmann Thermostats - I don’t have one of those so I haven’t tested with one so I’m stuck as to what may or may not be happening. If you think this routine might not be playing nicely with it then set TRV_curr_tgt to -1 (minus 1) then at least my code will leave it alone, then see if things improve or not. As to why the wakeup interval might be changing - maybe it’s a “feature” - StellaZ TRVs only seem to accept wakeup intervals in multiples of 240 seconds so if you set one to 300 you’ll still only get 240 - maybe the Horstmann’s doing that?
I have wondered myself about getting a z-wave room thermostat but figured if every radiator has a z-wave TRV on it then why bother? in theory I could leave the heating on 24x7 and just let the individual TRVs demand heat when needed - though yes practically I know that it might not be the most eco (ecological and economical) thing to do and it would probably just increase overall wear and tear especially on the pump and boiler. I do have 3 old fashioned twisty dial thermostats in the house but they’re always cranked way up.

VeraAlerts - that’s a good idea I use it myself on all 3 of my veras so I could add some code to send an alert to the default recipient when it decides to do a reload giving the reason why… please shout if you have any better ideas.

I mentioned earlier that I was trying to turn this into a plugin that work is progressing well and I’m learning as I go (I didn’t realise that plugins run in their own namespace - so that’s caused some fun and games!) - but I will keep on updating this code as well until that work is done.

… and finally time to eat humble pie and confess! I proudly mentioned earlier in this thread that I had moved all my TRVs to my main vera - well that did work, the TRVs worked nicely, and the rest of the system worked mostly ok - but there were just too many odd times when a light would take a second or two longer to come on, or a button pressed on a minimote would be just a little slow to do anything and the final straw being when my wife asked what I’d done as she’d noticed things going slower too! So I’ve put all my TRVs back onto their own dedicated Vera Lite - with a few non-critical z-wave plugs sprinkled around to spread the z-wave signal around a bit. So now the main house system is working well again and so are the TRVs.

… though I am getting regular E5 errors on the Danfoss LCs… cliffhanger to end on :slight_smile:

I am not sure of what you mean by

then set TRV_curr_tgt to -1 (minus 1)

How would I need to change what ? At the moment i use TRV.set_tgt(343,23) for the StellaZ’s as an example, embedded in the Luup section of a scene. I call that scene when i want to chaneg the rad settings. For the main thermostat, the Horstman, i use the same, TRV.set_tgt(246,18), but I have 4 different scenes for 4 different temperatures to set the main haeting to. I cannot got down the route of just controlling the rads, i have too many radiators (for example in bathrooms) which are not and cannot be controlled via TRV’s

Another observation, since v1.3 which I installed about 3 hours ago, i must have had about 30 or 40 restarts, without any TRV commands being sent in that time. I had a lot of restarts with v1.2, but it looks as if that has increased a lot.

@mikee123 - sorry TRV_curr_tgt is the variable name. if you run TRV.set_tgt(dev_id,-1) that will do it (that’s what comes of trying to rush an answer).
I’m a bit concerned by the many reloads you’re getting. I did change the last version to be a bit more aggressive but not that much.- I’m a little worried that I haven’t tested enough with the pre-emptive route as I tend to prefer wakeup catching. I’ll do that now.

Cheers

sorry! more humble pie! Vsn 1.3 did have a bug in it - when using pre-emptive timers it was counting unset wakeups wrongly and reloading far far too often. Vsn 1.4 is attached at the top of this thread - the only change is the fix for this problem.

I’ll test it more thoroughly next time :-\

I had turned the reloads_when_stuck to false on 1.3 due to the frequent reloads. Something else i noticed, these reloads were far more frequent then they should have been, i had set the max_wait_time = 1850, but reloads were about 10 mins apart, sometimes closer, so not sure if setting it to 1850 instead of 600 made a difference. Maybe keep an eye on that.
Uploading 1.4 now, lets see how it goes. Its already made a positive difference. Even with the reloads for the first time in months i had devices react instantaneously again. Great work.

Having been on 1.4 for a while now, I have hardly any startups, maybe 5 to 10 a day max. So that is working great. I am still experimenting with the unset_wakeup_limit , sometimes my StellaZ’s can take 1 hour (and then I get the startups which makes sense), so I probably haven’t got the right setting yet. I have tried 2, and now trying it set to 3.
Something else. I have notifications for every request to change TRV settings, as well as any requests to change the room stat setting. I also get a notification when it has been accepted. This way I can see what has been requested and how long it takes until it gets accepted.
I have noticed again a ‘ghost’ change of my room thermostat. I can see there has not been any request to change the setting, but it has been changed from 20 to 18. Without a request, that could normally only happen when changed manually on the thermostat, but that has not been touched. This does not happen very often, maybe once a week, but still is annoying and I would like to find out why. Any ideas ?

I should have vsn 1.5 ready in a few days - more tweaking and VeraAlerts detection.

on the ghost changes that is a puzzle - you haven’t got some long forgotten scene running changing it have you? or maybe it’s a default value caused sometimes on wakeups or reconfigures, or it could be what we used to call in my mainframe programming days a Transient Hardware Error (i.e. we have no idea!)

Have you tried wakeup catching rather than pre-emptive timers - I find that works better than pre-emptive, the pre-emptive concept is fine but it tends to rely on the devices waking up exactly when they should… and they don’t! my latest version shows in the log the last few actual wakeups for a TRV and they often wonder around a second or two either side of the set wakeupinterval. using wakeup catching that doesn’t matter so much. As a reminder to use wakeup catching just comment out the TRV_timer_offset line in the startup lua (e.g. --TRV_timer_offset=2) and reload, it’s easy enough to turn back on.

I have found that if the vera starts to hit the retry problem especially on a few TRVs then it can get itself properly messed up and it then starts doing retries almost randomly - in that case reloading is the only answer and waiting an hour for one seems far too long. When I’m watching the UI5 screen I can spot it happening - I just haven’t figured out anyway to spot it from code yet - so my view is more aggressive reload intervals is better all round.

I remember when I first implemented your code, I tried the wakeup catching, and the pre emptive worked better. But you have had quite a few improvements in the code since, so maybe worth trying again. But I think looking at my logs, I think I might have found a culprit. I have my heating set to 18 at 21.44, and 2 TRVs requesting change at 21.45. That caused a few startups. So I will spread out the changes a bit more. Apart from that, yesterday at least things were running fairly smooth, with 20 minutes the longest to set a TRV.
Over all, your code is brilliant. Its just down to tweaking the individual settings, like preemptive or not, what delay etc. And that is just down to trying different settings until you have it working well… Looking forward to trying your next version…

Initial tests on UI7/Edge show that this could work, however, the built in Vera code seems to be doing a better job than UI5 at setting TRVs - it’s difficult to tell until I load up the system with more TRVs and I’m a little loathed to do that until the weather is a few degrees warmer at risk of the WAF.

BUT there appears to be some bizarre logic in UI7 that automatically sets the mode of a TRV from HEAT to OFF if a lower temp is set, and then the new setpoint doesn’t get set by VERA. It’s like it assumes that it’s an aircon unit or something that is powered, and therefore by turning it off it will get cooler. Of course hot water rads don’t work like that.

So to really test this properly on UI7 can you have the code set the UserOperatingMode1 to be HeatOn when setting the TRV setpoints (either up or down) - UI5 never had this oddity so the code just needs to be adjusted to compensate.

Also, on UI5 the used setpoint is called TemperatureSetpoint1_Heat. On UI7 the same attribute is there, but the one that appears to be used is TemperatureSetpoint1 (ie. no _heat according to the hoverovers on the UI). The setpoint target whilst this is called SetpointTarget in the UI appears to ALSO be called TemperatureSetpoint1 when you hoverover it. Now this could be the hoverovers are all wrong - or it could also be how and why the inbuilt Vera code for setting the setpoints is now working properly - and why it never did on UI5. I’ll look at this a little more as testing allows, but wanted to stick it down somewhere so it’s not forgotten.

btw, what is your TRV_next_tgt_time variable for ? It never changes either for normal, or pre-emptive setting.