Danfoss Ally Cloud Binding

This binding integrates Danfoss Ally™ smart thermostats into openHAB. It allows you to monitor and control your heating system through the Danfoss cloud API.

Changelog

Version 0.4.0

  • Improved bridge flow.
  • Improved docs

Version 0.3.1

  • A solution that doubles the possible number of pull updates before the API request limit is reached. This update is relevant if you have more than 5 devices and an update interval of 60 seconds or less.

Version 0.3.0

  • This release adds dynamic channels to all supported devices, with channel sets depending on device type. Things must be recreated after the binding update.

Version 0.2.1

  • Fix output state

Version 0.2

  • Added polling for individual devices, added new devices, and additional logging.

Danfoss Ally™ Radiator Thermostat (not tested well)
Danfoss Ally™ Gateway
Danfoss Icon2 Controller

Version 0.1

  • initial release

Resources

org.openhab.binding.danfossally-5.1.0-SNAPSHOT.jar

openhab-addons/bundles/org.openhab.binding.danfossally at danfossally · stas-dovgodko/openhab-addons

2 Likes

Good morning

I use Danfoss living connect (zwave) since many years ( no connection to OH). For testing I installed three Ally thermostats (zigbee, eTRV0100) a year ago. They are linked to OH via zigbee2mqtt, having no trouble at all. The new devices from last month (zigbee, eTRV0103), are allways unmounting after inclusion.

So I installed your binding and could establish the ally bridge, which is online now ( using the ally gateway).

The thermostat device ( linked to the gateway ) stays allways ‘unknown’. Maybe the device ID is wrong. I used the ‘virtuelle ID’ of the device out of the ally app. Maybe that’s not ok.

If I scan for new devices, nothing comes in.

update: there was a blank in the client ID, although the bridge was online. Now bridge is ok and I get the response

2025-12-12 14:22:09.749 [DEBUG] [iscovery.DanfossAllyDiscoveryService] - Starting Danfoss Ally device scan
2025-12-12 14:22:09.821 [DEBUG] [iscovery.DanfossAllyDiscoveryService] - Discovered unsupported Ally device: id=bf677c519a96b, name=Danfoss Ally™ Gateway, type=Danfoss Ally™ Gateway
2025-12-12 14:22:09.822 [DEBUG] [iscovery.DanfossAllyDiscoveryService] - Discovered unsupported Ally device: id=bff3dc58a08be, name=Schreibtisch, type=Danfoss Ally™ Radiator Thermostat

Thank you for the information provided. I have created a new version of the binding, which includes the gateway and your thermostat.
Unfortunately, I cannot test your thermostat as I do not have one.
Please reinstall the binding and try again.

Thanks, it works perfectly now.

The disadvantage is that you don’t get all data from the api compared to direct zigbee2mqtt connection, even they are avalable in the api like

        "code": "pi_heating_demand",
        "value": 76
      },
{
  "result": {
    "id": "bff3dc58a08",
    "name": "Schreibtisch",
    "time_zone": "+01:00",
    "sub": true,
    "device_type": "Danfoss Ally™ Radiator Thermostat",
    "create_time": 1765525161,
    "update_time": 1765548464,
    "active_time": 1765525161,
    "status": [
      {
        "code": "switch",
        "value": false
      },
      {
        "code": "mode",
        "value": "manual"
      },
      {
        "code": "work_state",
        "value": "Heat"
      },
      {
        "code": "temp_set",
        "value": 210
      },
      {
        "code": "upper_temp",
        "value": 350
      },
      {
        "code": "temp_current",
        "value": 223
      },
      {
        "code": "window_state",
        "value": "close"
      },
      {
        "code": "lower_temp",
        "value": 50
      },
      {
        "code": "child_lock",
        "value": false
      },
      {
        "code": "battery_percentage",
        "value": 100
      },
      {
        "code": "fault",
        "value": 0
      },
      {
        "code": "SetpointChangeSource",
        "value": "Externally"
      },
      {
        "code": "manual_mode_fast",
        "value": 265
      },
      {
        "code": "window_toggle",
        "value": false
      },
      {
        "code": "window_state_info",
        "value": "close"
      },
      {
        "code": "at_home_setting",
        "value": 210
      },
      {
        "code": "leaving_home_setting",
        "value": 170
      },
      {
        "code": "pause_setting",
        "value": 50
      },
      {
        "code": "holiday_setting",
        "value": 150
      },
      {
        "code": "switch_state",
        "value": false
      },
      {
        "code": "mounting_mode_active",
        "value": false
      },
      {
        "code": "ext_measured_rs",
        "value": -8000
      },
      {
        "code": "radiator_covered",
        "value": false
      },
      {
        "code": "heat_available",
        "value": true
      },
      {
        "code": "load_balance_enable",
        "value": true
      },
      {
        "code": "pi_heating_demand",
        "value": 76
      },
      {
        "code": "OccupiedSetpoint",
        "value": 2650
      }
    ],
    "online": true
  },
  "t": 1765549634999
}

That’s what comes in ( a lot of times but the interesting part got lost )

1 Like

Yes, the current version is more tailored to my own use cases and hardware. I think the next version will be more adapted for public use. Most likely, there will be some kind of raw channel that exposes API data in JSON format. I am still thinking about it.

Unfortunately, there is no stable dataset, and for each device type the set of keys in the status differs. While I had only one type of thermostat (for floor heating), this was not a problem.

Built a new version with dynamic channels added. Now all items have all channels that the API returns. When updating, existing Things need to be recreated.

Still trying to figure out the API request limits - for 8 devices, 60s polling hits the API limits

New Binding works quit ok, with lots of channels. The temperatures come in as integer values, like 254 means 25.4°C. Is there a chance to make the division in the binding?

No, because this is how the API returns the data. I cannot reliably distinguish, across different devices, whether a value represents temperature or some other metric (for example, humidity).

The channels that belong to the status group will be exposed from API without any transformations.

For thermostats, I calculate separate channels for temperature and setpoint, but I am not fully sure that this logic works correctly for all thermostat models.

I frequently get these messages. I have already reduce the number of channels to what’s really needed, but can’t avoid the message.

lag 07:37:09.597	WARN	
org.openhab.binding.danfossally.internal.DanfossAllyDeviceHandler
No status array found in device info
flag 07:42:09.822	WARN	
org.openhab.binding.danfossally.internal.DanfossAllyDeviceHandler
No status array found in device info

The Binding also gets disabled sometimes twice a day. So I have this rule to enable it again

configuration: {}
triggers:
  - id: "1"
    configuration:
      thingUID: danfossally:account:DanfossAllyBinding
      previousStatus: ONLINE
    type: core.ThingStatusChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: |-
        var {OH_function} = require ('./kroenert/index.js');
        var volume         = 20;
        var sound          = 4;  
        var message      = ['2Danfoss Ally Binding Offline'];

        OH_function.sendMessage(message);

        things.getThing('danfossally:account:DanfossAllyBinding').setEnabled(false);
        setTimeout(function() {things.getThing('danfossally:account:DanfossAllyBinding').setEnabled(true)},5000 );   
    type: script.ScriptAction

Honestly, this is strange behavior — I haven’t encountered anything like this before. It definitely doesn’t depend on the number of channels; it looks like at some point the API returns an error that I’m not handling correctly. I’ll investigate it further.