POPP TRV 701721 / Danfoss Ally (zigbee) Driver

I have put a version 3.0 on github. This implements a switch function.
'off' sets thermostatMode to off and heatingSetpoint to eTRVMinHeatSetpointLimit;
(it takes a few seconds for the temperature change to register)
setting a heatingSetpoint above this min automatically sets thermstatMode to heat;...
heat and on commands only change the thermostatMode to heat, they do not change the heatingSetpoint - use an app to set this to what you want or to set a scheduled temperature
I do not use Action TIles so let me know if this does the job for you.
On hubitat dashboard thermostat tiles , off thermostatMode seems to give a blank tile so I can't then see the heatingSetpoint or the arrows to change that setting :frowning:

3 Likes

I don't really know about advantages / disadvantages ... I think I have read somewhere that battery life may be affected but I am still on my first set of duracell AAs in each valve and they are still going for over a year (now 65%).

I have not mastered aggression factor setting - I understand the principle but not sure about the effect in practice with these valves. I have recently read that aggression factor has to be 1, 5 or 10, but I really don't know if that is right. I willtry to do some graphs over Christmas holidays and see how things change.

1 Like

You will need to use the Initialize command on each TRV device page - once version 3.0 is loaded.

Thanks for this. Looks like a possible issue, I've installed and then initialised.

I'm getting the following errors:

dev:1792023-12-04 08:19:54.087errororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'float'. Try 'java.lang.Float' instead on line 911 (method setHeatingSetpoint)
dev:1792023-12-04 08:19:53.270errororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'float'. Try 'java.lang.Float' instead on line 911 (method setHeatingSetpoint)
dev:1792023-12-04 08:19:49.242debugParsing read attr - Desc Map: [raw:78BA0100000A0100200D, dni:78BA, endpoint:01, cluster:0000, size:0A, attrId:0001, encoding:20, command:01, value:0D]
dev:1792023-12-04 08:19:49.239debugParse description read attr - raw: 78BA0100000A0100200D, dni: 78BA, endpoint: 01, cluster: 0000, size: 0A, attrId: 0001, encoding: 20, command: 01, value: 0D
dev:1792023-12-04 08:19:49.169debugParsing read attr - Desc Map: [raw:78BA0100000A00002003, dni:78BA, endpoint:01, cluster:0000, size:0A, attrId:0000, encoding:20, command:01, value:03]
dev:1792023-12-04 08:19:49.166debugParse description read attr - raw: 78BA0100000A00002003, dni: 78BA, endpoint: 01, cluster: 0000, size: 0A, attrId: 0000, encoding: 20, command: 01, value: 03
dev:1792023-12-04 08:19:46.570infoJellyGreen's driver for TRV Lounge initialized
dev:1792023-12-04 08:19:46.563debuginitializeCommands(): [he raw 0x78BA 1 0x01 0x0000 {10 00 00 00 00}, delay 2000, he raw 0x78BA 1 0x01 0x0000 {10 00 00 01 00}, delay 2000, he raw 0x78BA 1 0x01 0x0000 {10 00 00 02 00}, delay 2000, he raw 0x78BA 1 0x01 0x0000 {10 00 00 03 00}, delay 300, he raw 0x78BA 1 0x01 0x0000 {10 00 00 04 00}, delay 400, he raw 0x78BA 1 0x01 0x0000 {10 00 00 05 00}, delay 300, he raw 0x78BA 1 0x01 0x0000 {10 00 00 06 00}, delay 300, he raw 0x78BA 1 0x01 0x0000 {10 00 00 07 00}, delay 200, he raw 0x78BA 1 0x01 0x0000 {10 00 00 10 00}, delay 400, he raw 0x78BA 1 0x01 0x0000 {10 00 00 00 40}, delay 200]
dev:1792023-12-04 08:19:46.557debugcmds(): [he raw 0x78BA 1 0x01 0x0000 {10 00 00 00 00}, delay 2000, he raw 0x78BA 1 0x01 0x0000 {10 00 00 01 00}, delay 2000, he raw 0x78BA 1 0x01 0x0000 {10 00 00 02 00}, delay 2000, he raw 0x78BA 1 0x01 0x0000 {10 00 00 03 00}, delay 300, he raw 0x78BA 1 0x01 0x0000 {10 00 00 04 00}, delay 400, he raw 0x78BA 1 0x01 0x0000 {10 00 00 05 00}, delay 300, he raw 0x78BA 1 0x01 0x0000 {10 00 00 06 00}, delay 300, he raw 0x78BA 1 0x01 0x0000 {10 00 00 07 00}, delay 200, he raw 0x78BA 1 0x01 0x0000 {10 00 00 10 00}, delay 400, he raw 0x78BA 1 0x01 0x0000 {10 00 00 00 40}, delay 200]
dev:1792023-12-04 08:18:10.788errororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'float'. Try 'java.lang.Float' instead on line 1005 (method setTRVMinHeatSetpointLimit)
dev:1792023-12-04 08:18:07.075errororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'float'. Try 'java.lang.Float' instead on line 1019 (method setTRVMaxHeatSetpointLimit)
dev:1792023-12-04 08:17:22.590errororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'float'. Try 'java.lang.Float' instead on line 911 (method setHeatingSetpoint)
dev:1792023-12-04 08:16:50.189errororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'float'. Try 'java.lang.Float' instead on line 911 (method setHeatingSetpoint)

I explain ActionTiles and what I'm looking to do later today. Thanks again. Paul

When you look at Current States, can you see eTRVMinHeatSetpointLimit and eTRVMaxSetpointLimit? If not, press the Refresh command for the device and they might spring into life and you should see the default values (min 5 and max 35).
I think this can be fixed by adding one line of code "refresh()" at the top of the "initialized()" method - but if there are no defaults these could be set here instead with two lines:
"setTRVMinHeatSetpointLimit(5)"
"setTRVMaxHeatSetpointLimit(35)"
If you could try pressing refresh and let me know if that works then I will change the driver to make insert the first of these options.

Yes, that worked. Thanks for the pointer.

I'll give you guys a quick write-up of ActionTiles in a moment. In the meantime is there a way to store an on and off temperature? So the TRV jumps to those temps when the on and off actions are initiated? edit: I can see the off switch reverts to the minimum set value.

I have a use case where I have a less frequently used room that has a rad in it. That rad sits on the same heating zone as then rest of the house. So I'd like to be able to say turn the rad on for the weekend but leave off during the week. Doing that via an on/off switch would be amazing.

Thanks again, seriously appreciate the effort here :slight_smile:

One more ask.

Does it make sense to make the thermostatOperatingState state follow the eTRVCallingForHeat state.

If there is anyway to make:

eTRVCallingForHeat: yes = ThermostatOperatingState: heating
and
eTRVCallingForHeat: no = ThermostatOperatingState: idle

edit. I can see the ThermostatOperatingState changing so something is updating it, trying to figure that out.

In addition call you also store the last on/off setting in the state variables?

Then I would be a very happy man!

1 Like

That is good to hear.
You could use Hub variables and / or use the Hubitat Thermostat Scheduler app. Thats what I do. When you want to reassert the scheduled temperature you can just use the Set Scheduled Temperatures command to revert to the temperature you want for the time of day. You may need to take the scheduler on and off hold / scheduled too so that the schedule does not override any manual temperatures setting that you want to take priority.

Does it make sense to make the thermostatOperatingState state follow the eTRVCallingForHeat state? It would but the TRVs seems to get stuck calling for heat sometimes combining the two in some fashion has made things more reliable for me.

Can you you also store the last on/off setting in the state variables? Possibly but I would keep things simple and use a hub variable if you need to do this (or the Thermostat Scheduler)

I have tried different ways of combining Calling for Heat and PIHeatingHeatingDemand. If you want to play about in the driver rather than in an app you need lines 763 to about 775 of the driver code.

OK. All good. I can use something else to update the ThermostatOperatingState.

Thanks for the pointer will have a look.

Quick few notes on ActionTiles. Allows me to create a dashboard that I can then display on a tablet (cheap Amazon Fire Tablet). Gives me the ability to do this sort of stuff:

For a thermostat the tile changes status as the ThermostatOperatingState changes. So this:

image

Becomes this when the TRV is actually heating:

image

Nice and visual way of seeing what is going on. Useful in my use case anyway.

1 Like

Nice. Not much different to mine...
image
I don't show Off or Heat Mode. As I said before if I turn the TRV off the tiles goes blank

Excellent. The real bonus for here is the switch function. Let me have a play and I'll feedback. Thanks again. These are the nice to haves. The fact I have a responsive TRV is awesome, great work on the driver!

1 Like

@user3101 I've reverted the driver to the 2.8 version based on the following.

The ThermostatOperatingState does update currently. When you move the TRV set point above the current temp it takes approx 5 mins for the ThermostatOperatingState to change to 'heating'. When you drop the TRV below the current temp the ThermostatOperatingState changes to 'idle' after about a minute. So, all working as expected, just some delay on the status update.

Looks like this is the code in question that does that (line 755):

        if ((device.currentValue("eTRVCallingForHeat") == "yes") && (device.currentValue("eTRVPIHeatingDemand") > 0))
             {
               sendEvent(name: "thermostatMode", value: "heat", descriptionText: "for dashboard thermostat tile wording only ")     // ["auto", "off", "heat", "emergency heat", "cool"]
               sendEvent(name: "thermostatOperatingState", value: "heating", descriptionText: "for dashboard thermostat tile colour only ")  //  ["heating", "pending cool", "pending heat", "vent economizer", "idle", "cooling", "fan only"]
             }
        else {
               sendEvent(name: "thermostatMode", value: "heat", descriptionText: "for dashboard thermostat tile wording only")       // ["auto", "off", "heat", "emergency heat", "cool"]
               sendEvent(name: "thermostatOperatingState", value: "idle", descriptionText: "for dashboard thermostat tile colour only")      //  ["heating", "pending cool", "pending heat", "vent economizer", "idle", "cooling", "fan only"]
             }

With this in mind I can achieve my switch capability by simply creating a virtual switch and then putting a simple bit of logic behind it.

When switch changes to On then set change heating set point to x
When switch changes to Off then set change heating set point to y

So, all good.

That is how I have been operating for a while, but perhaps not as impatient as you, especially with one valve that sit calling for heat for a very long time before changing when it should, hence use PIDemand too. I am now using version 3.0
Anyway, hope all works for you now.
Jonathan

1 Like

If 3.0 is good enough for you and not just a trial change for me the I’ll go with that too. :joy:

Thanks jonathon. :+1:

Not wanting to raise matters again, but screenshot below shows a valve still calling for heat, despite PIHeating being 0. Can sit like this for a long time, hence a blending to define idle or heating.

Can I ask why you are use the eTRVPIHeatingDemand state (as well as eTRVCallingForHeat) to determine the thermostatOperatingState? My understanding is that this when the TRV is deployed using Hive this setting allows the TRV to turn on the boiler switch, so that the TRV can call for heat regardless of the Hive Thermostat state (boiler will produce heat even if the the room Thermostat is off). Are the TRV's not completely independent of the stat and boiler switch when deployed using Habitat (because the TRV won't know which Stat they might be paired with in a multi-zone set-up? Or am I missing something?

In my use case I simply want to know if the TRV has opened, which would be determined by the eTRVCallingForHeat state, would it not?

I think I might be missing something Jonathon? If not I might play with the code and change this:

   if ((device.currentValue("eTRVCallingForHeat") == "yes") && (device.currentValue("eTRVPIHeatingDemand") > 0))
         {
           sendEvent(name: "thermostatMode", value: "heat", descriptionText: "for dashboard thermostat tile wording only ")     // ["auto", "off", "heat", "emergency heat", "cool"]
           sendEvent(name: "thermostatOperatingState", value: "heating", descriptionText: "for dashboard thermostat tile colour only ")  //  ["heating", "pending cool", "pending heat", "vent economizer", "idle", "cooling", "fan only"]
         }
    else {
           sendEvent(name: "thermostatMode", value: "heat", descriptionText: "for dashboard thermostat tile wording only")       // ["auto", "off", "heat", "emergency heat", "cool"]
           sendEvent(name: "thermostatOperatingState", value: "idle", descriptionText: "for dashboard thermostat tile colour only")      //  ["heating", "pending cool", "pending heat", "vent economizer", "idle", "cooling", "fan only"]
         }

to this:

   if ((device.currentValue("eTRVCallingForHeat") == "yes"))
         {
           sendEvent(name: "thermostatMode", value: "heat", descriptionText: "for dashboard thermostat tile wording only ")     // ["auto", "off", "heat", "emergency heat", "cool"]
           sendEvent(name: "thermostatOperatingState", value: "heating", descriptionText: "for dashboard thermostat tile colour only ")  //  ["heating", "pending cool", "pending heat", "vent economizer", "idle", "cooling", "fan only"]
         }
    else {
           sendEvent(name: "thermostatMode", value: "heat", descriptionText: "for dashboard thermostat tile wording only")       // ["auto", "off", "heat", "emergency heat", "cool"]
           sendEvent(name: "thermostatOperatingState", value: "idle", descriptionText: "for dashboard thermostat tile colour only")      //  ["heating", "pending cool", "pending heat", "vent economizer", "idle", "cooling", "fan only"]
         }

Any thoughts?

edit: I think I see what you mean here. The eTRVCallingForHeat state seems a little unreliable as a why of determining if the eTRV is wanting to do something.

PIHeatingDemand is, I am prettry sure, an indication of how open the valve is on a scale of 0 to 100. I think you aree right that "calling for heat" was intended to switch your boiler.
BUT
When I started trying these valves and used "Calling for Heat" to control my boiler switch, I seemed to be getting quite a lot of time when the PIHeatingDemand was 0 and the "Calling for Heat" seems to get stick on 'yes'. For me that means that one radiator in the house was on (the bypass one, which is always on when central heating is on) and hot central heating water was flowing around the house). So I was getting many unnecessary and undesired hours of boiler being on.
So then I tried just using the PIHeatingDemand - so that that too could control when my boiler switched on / off. But that also had times when it would continue to have some demand when my rooms were well above their heatingsetpoint.
So, I tried combining the two. I do this in the driver, as you have seen, but I also do this in Apps and have tried different combinations.
None as simple as I would have liked - but, for me at least, I have got things to work well.
I agree your edit just uses calling for heat" to control idle / heating. If that works for you, then great.

Yes, interesting.

My intention here is to use the TRV as a dumb device. If I assume that it's working and reliable, then, if I set the heating set point at 22 and the temp is 10 is will open the valve producing heat, and vice in the opposite direction. So, therefore changing the code to this:

if (device.currentValue("thermostatMode") == "heat")
          {
            if (device.currentValue("heatingSetpoint") > device.currentValue("temperature"))
                //&& (device.currentValue("eTRVPIHeatingDemand") > 0))
             {
             sendEvent(name: "thermostatOperatingState", value: "heating", descriptionText: "for dashboard thermostat tile colour only ")  //  ["heating", "pending cool", "pending heat", "vent economizer", "idle", "cooling", "fan only"]
             }
           else 
             {
             sendEvent(name: "thermostatOperatingState", value: "idle", descriptionText: "for dashboard thermostat tile colour only")      //  ["heating", "pending cool", "pending heat", "vent economizer", "idle", "cooling", "fan only"]
             }
          }

Means that the thermostatOperatingState updates quickly and reliably.

It's a simple answer if you are willing to a) accept the TRV as a dumb device and b) that the TRV is reliable and does what it says on the tin.

The main point for me here is that I have a couple of rads on the primary heating zone, that are distant from the thermostat (which controls the hot water for the rads). And that I choose to heat a room based on other the rad is on/off. I'm not using them to call for heat. Selfish but should work I think.