Playing with openHAB binding for Danfoss Air unit

In summer 2019 we had heat recovery ventilation installed in our house: A Danfoss Air A2 unit with a CCM module connected to our existing Danfoss Link CC Controller. The integration here is pretty useless: The Danfoss Link app can’t do anything other than read outdoor temperature and set vacation mode. Even the Link CC is crippled, compared to the Air Dial – for example it’s not possible to read relative humidity, thus completely impossible to check if the system is running as it should.

A few days after installation I added a WeMo Insight integrated with openHAB, so at least I have logged power consumption data since then. Then in November I finally couldn’t resist installing a network cable to the CCM unit as I saw it having an Ethernet port.

I was able to run the Danfoss HRV PC-Tool and finally read some more data like relative humidity. Naturally, next thing on my mind was reverse engineering of the protocol used. I didn’t have to do much research until I found this openHAB Community thread. Reading through the thread ended with the good news that someone already did all the work and even created an openHAB binding.


Installing the alpha version of the binding couldn’t be any easier and it worked out of the box without any problems. I linked almost all channels and started seeing and logging useful information like operating mode, fan speeds, boost, humidity, temperatures and remaining filter life.

Next, I could start adding rules to actively monitor how the system was operating. I started getting notifications on my phone when boost was activated to get a feeling about when that usually happens. I could also start making humidity graphs, which got me suspicious about these measurements. Comparing with my Netatmo data from four different indoor stations in the house, the Air unit’s measurements are consistently 5-10 % higher. This of course impacts how the system operates, as humidity is likely the only parameter used for calculating fan speed in “demand” mode.

Energy savings

Next revelation came when I found that some of the channels were writable, like operating mode, manual fan speed and boost. Now this turned into something really useful!

The one thing even the Danfoss Link app can do is set vacation mode when away from the house. This will set the HPV to manual fan speed level 1 which consumes about 9 W. So I figured that this could be automated and also used on weekdays some time after everyone has left the house. I used existing presence logic for that (from Unifi access point), but also decided to add CO2 level as parameter for safety. During the night our phones will also go to sleep at some point, so some additional logic is needed.

Trying to perform humidity/demand calculations like the unit itself does would be cool, but also somewhat more complicated than what I had in mind to begin with. Also, it would require me to integrate some new humidity sensors as I don’t want to rely on Netatmo for this, since data is only refreshed every 10 minutes and also Internet-dependent and Netatmo service-dependent. In other words, untrustworthy. But as safety mechanism for presence-flaws and not needing fast reaction, CO2 measurements could be used.

Nest smoke alarm

I also have a couple of Nest smoke alarms which are integrated in openHAB as I haven’t migrated to Google. So why not use them and trigger boost if smoke is detected?


So here we go. First, I have a rule that will trigger an Android notification when boost is activated. This includes relative humidity from the Air unit as well as from four different rooms in the house, and includes previous values 20 minutes ago. The rule is too ugly to post, and probably too specific to share anyway, so let’s skip it and go directly to the power-saving rule:

rule "Danfoss control"
    Item Anyone_Home changed to ON or
    Item SkynetStationIndoor_Max_CO2 changed or
    Item HomeLeft30MinutesAgo received command OFF
    var hasChanged = Anyone_Home.changedSince(now.minusMinutes(29))
    if (Anyone_Home.state == OFF
        && !hasChanged
        &amp;&amp; (SkynetStationIndoor_Max_CO2.state as Number).intValue < 500
        &amp;&amp; DanfossHRV_Main_Mode.state == "DEMAND")
    else if ((Anyone_Home.state == ON || (SkynetStationIndoor_Max_CO2.state as Number).intValue >= 700)
        &amp;&amp; DanfossHRV_Main_Mode.state != "DEMAND")

SkynetStationIndoor_Max_CO2 is a group with function “MAX” being linked from my four different Netatmo CO2 items. HomeLeft30Minutes ago is a manually created item based on the Expire Binding:

Switch HomeLeft30MinutesAgo { expire="30m,command=OFF" }

Updated from presence.rules:

rule "Anyone home timer start"
    Item Anyone_Home changed to OFF

rule "Anyone home timer cancel"
    Item Anyone_Home changed to ON

So this first rule will, in a pretty simple way, just switch to lowest step 30 minutes after everyone left the home and CO2 levels are all below 500. This is a conservative way to take control only when assuming no humidity will be generated. Weakest point is that humidity is not considered at all, so for example when drying clothes indoor, rule might trigger anyway.

Next, the smoke alarm rule (still untested):

rule "Danfoss boost on smoke alarm"
    Item NestProtectFamilyRoom_SmokeAlarmState changed from "OK" or
    Item NestProtectHall_SmokeAlarmState changed from "OK"

And last, the filter notification:

rule "Danfoss filter monitoring"
    Item DanfossHRV_Service_RemainingFilterLife changed
    if (DanfossHRV_Service_RemainingFilterLife.state < 10)
        var body = String::format("Remaining filter life: %d %%", (DanfossHRV_Service_RemainingFilterLife.state as Number).intValue)
        // Use some service to push notification, I use Pushbullet.

Of course also added a sitemap section to have some app control, since Danfoss doesn’t provide this (in Danish, but you probably get the idea):

openHAB sitemap

Thanks to pravussum for the binding, which can be found here:

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.