zha-device-handlers: [BUG] Danfoss Ally valve: Slow actuator response [solved already in other solutions]

Describe the bug The problem is well described here: https://community.home-assistant.io/t/danfoss-ally-valve-slow-actuator-response-solved/254939

So if you issue a new temperature target setpoint for the thermostat using HA+ZHA the thermostat uses the internal PID mechanism to control the valve which results in slow (and sometimes unexpected) valve control movements.

To Reproduce Steps to reproduce the behavior:

  1. Go to your Danfos Ally thermostat connected using ZHA
  2. Change the desired temperature
  3. Watch the pi_heating_demand changing over time (far to slow)

Expected behavior The pi_heating_demand should change much faster

Screenshots grafik

Additional context The issue is already fixed in deconz (https://github.com/dresden-elektronik/deconz-rest-plugin/pull/4408) as well as in the Koenkk/zigbee-herdsman-converters (https://github.com/Koenkk/zigbee-herdsman-converters/pull/2592)

So mainly the solution is well described in the official document (https://assets.danfoss.com/documents/176987/AM375549618098en-000101.pdf):

grafik

The zigbee coordinator needs to send a Setpoint Command including the HeatingSetpoint itself aswell as a bitmask (enum8 set to 1) to circumvent the thermostats PID mechism.

Based on that I started to read carefully all instructions of the zha quirks because I wanted to sort out if I can create a custom zhaquirk (based on https://github.com/zigpy/zha-device-handlers/tree/dev/zhaquirks/danfoss) fixing this issue.

While I already identified that I need to add a custom output cluster in the replacement (and I guess for that I also need to add the thermostat output cluster to the signature itself?) I didn’t find any good example (first I thought the tuya custom quirks were good to understand but I honestly gave up) on how to understand:

  1. how do I implement a custom command in the quirk?
  2. (in this specific case) how can I access the occupied_heating_setpoint sent by HA+ZHA to the thermostat (which is based on the solution above an int16)
  3. how can I create a custom command like “setpointType (enum8) + HeatingSetpoint (16bit)” where the HeatingSetpoint is occupied_heating_setpoint from 2) and the setPointType is set to 1 (the final command input needs to be masked in hex I guess)?

Also just to recap how it works: ZHA is using the climate.py integration in HA and calls the function

async def async_set_temperature(self, **kwargs):
        """Set new target temperature."""

which eventually calls (in the case of the Danfoss Ally):

            elif self.hvac_mode == HVAC_MODE_HEAT:
                success = await thrm.async_set_heating_setpoint(
                    temp, self.preset_mode == PRESET_AWAY
                )

which is implemented in core/homeassistant/components/zha/core/channels/hvac.py

so there in normal operation the following code should be executed:

        if not await self.write_attributes(data):
            self.debug("couldn't set heating setpoint")
            return False

That’s where I got lost to find the appropriate calls into zigpy and how the zha quirks overwrite the zigpy code to be executed (or is this assumption already wrong?).

Any help appreciated. Surely you also can fix this yourself if you think this is faster than to teach me 😉 (because I won’t have time within the next 3 weeks). If you fix it yourself I can learn from your implementation to be able to handle such requests myself in the future.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 47 (32 by maintainers)

Most upvoted comments

Normally it takes a couple of days before the Ally is properly learning the room response.

I have been using the Popp for quite some time and it works exactly the same as the Danfos. Danfos updated it to 1.08 by downloading the firmware from the support page and using ZHA. I had no problem

For feedback from Danfoss we need to ask @Stefano0042, I don’t have any connections with them.

I have one example from my daily used room:

grafik

Purple is the requested setpoint, dark blue is the temperature from the thermostat itself and light blue is the actual room temperature. Yes, with activated PID (for that you need to use a custom integration right now as the standard ZHA integration disables the PID by intention) it really needs time to reach the desired temperature. But you also can see that the temperature of the thermostat still rises as long as the external temperature is not reached (so in my experience the average fits really well).

I use scripts and an automation in HA that triggers as often as the external room temperature sensor changes. This happens more often than 30 minutes at daytime but only very view times at night. I can’t answer why the documentation suggests to only send the temperature at a minimum of 30 minutes. It works well with more often changes also.

@WolfRevo exactly, what really matter is the controlled parameter: air temperature. I’ve got further details from eTRV department head engineer about the valve movement in scheduling mode, thus is not a pure PID but builded-up on a proprietary algorithm, that has not obviously been unveiled, based on a mix of adaptive and statistical data quite complicated they say, one reason more to use the factory set I would say.

You could take advantage of it to include compatibility with the Popp Zigbee thermostat (POPZ701721) that has the same characteristics. Changing the line: MODELS_INFO: [(DANFOSS, "eTRV0100"),("D5X84YU", "eT093WRO")],

http://manuals-backend.z-wave.info/make.php?lang=en&sku=POPZ701721&cert=ZIG21051ZB330911-24&type=mini

As I don’t own this one I can’t test this change. Besides that my PR already has been approved and integrated into DEV.

One PM how some users is using there TRVs (at least tuya ones) in HA as manual or scheduling on / off from HA then thinking its more economic then letting the TRV doing the work and getting one stable and more economical heating in the room.

My goal is that the TRV shall doing the work and only changing the set point temperature if changing somthing but normally leaving it doing its work as good it can (if not getting the valve jammed and need little hands on).

As I already mentioned I see that both arguments are legit. I also understand the statement from @Adminiuga

But this is actually what i mean, by definition, commands originated from ZHA Climate entity count (or should count) as manual setpoint change, because it cannot come from Thermostat scheduling.

Checking the code at the moment there is no quirk using a parameter from the configuration.yaml of HA. The zha-device-handler on the other hand already checks for custom quirks path in the config file. So I guess it wouldn’t be hard to extend the setup() function in zhaquirks/__init__.py for additional optional parameters and make them available to the single quirks for further usage?

BTW I reverted back to the original code and disabled the setpoint command again. I have to admit it feels more natural and comfortable this way (knowing that the valve needs some time to react; the first on is the occupied heating setpoint, the second one the pi heating demand):

grafik

This is mostly based on the easy fact that it always needs some time to heat up the air in a room so “feeling” the warm air is never immediately after the valve has fully openend and the time the PID takes is close to normal warm up of our rooms so from a external perspective the effect is not really relevant but the thermostat is much more precise in getting and holding the desired temperature. Nevertheless the PR still makes sense from the ZHA point of view but integrating an parameter would be nice to have. Objections?

That is really a tricky part, my Allies in HA environment are normally driven all the time by a scheduled activity, as result the temperature control in the rooms is smooth and stable (Standard setpoint = Ss, Eco setpoint (night) = Ss -1 or maximum -2 °C). so let’s call it the basic functioning. Type 1 play his role if you manually rotate the actuator dial. Ideally it would be optimal if only the scheduled temperature changes would be followed by a type 0 setpoint command.

On the basis of a direct feedback from Danfoss R&D I would like to point out that is certainly good to have the possibility to use Setpoint type = 1 on request (normally, in consequence of a manual increase of temperature), to boost the PI value, but pay attention, this situation can lead to a temperature overshoot and economy losses. Setpoint type = 0 is the normal setup in scheduled mode (almost all the time). Massive Type 1 calls will disturb the self-learning activity of the actuator itself. Hopefully you will take care of this suggestions during deployment of the PR. Definitely this is not a bug but the result of a well engineered project.

seems like you already defined the command correctly. Do they tell you what behavior is going to be if you do both the “write_attributes” and “setpoint” command? In other words, do you need to filter out the setpoint attribute write?

Try the following instead, which would do both attr write and setpoint command:

    async def write_attributes(self, attributes, manufacturer=None):
    """Send SETPOINT_COMMAND after setpoint change"""

        write_res = await super().write_attributes(attributes, manufacturer=manufacturer)

        if "occupied_heating_setpoint" in attributes:
            await self.setpoint_command(0x01, attributes["occupied_heating_setpoint"], manufacturer=manufacturer)

        return write_res

it would do the write attributes and then the setpoint command, it the heating setpoint was in the attributes