dresden-elektronik / deconz-rest-plugin

deCONZ REST-API plugin to control ZigBee devices
BSD 3-Clause "New" or "Revised" License
1.89k stars 490 forks source link

Aqara Smart Radiator Thermostat E1 #6351

Closed Luigi-01 closed 1 year ago

Luigi-01 commented 1 year ago

Presently I have 6 Eurotronic Radiator valves which work perfect. However, many thermostat radiator valve are presently not available any more for Zigbee. I needed a new valve and bought this Aqara thermostat E1 valve, Solid design and works presently manually.

Device is connected, however not show in the menu and Domoticz does not see the device as well. Piture Aqara Smart Thermostatic E1

Manufacturer Name LUMI Model Identifier lumi.airrtc.agl001

Looks almost identical as the Essentials 120112 Smart Home radiator thermostat.

0x9294-01 0X9294-02 Basic Cluster identify Cluster 02 Identify Cluster Lui specific Cluster-01 Lumi specific Clster 03 Lumi specific Cluster Lumi specific Cluster 02 Node Info Power Configuration Cluster Thermostat Cluster 01 Thermostat Cluster 02 Thermostat Cluster 03 Thermostat Cluster 04 Thermostat Cluster 05 Thermostat Cluster 06 Thermostat Cluster 07 Thermostat Cluster 08 Time Cluster Time Cluster 02

Device

Screenshots

Basic

Identify

Alarms

Device Temperature

Groups

Scenes

On/Off

Level Control

Color Control

Simple Metering

Diagnostics

Other clusters that are not mentioned above

ulbrich-media commented 1 year ago

I created a DDF file since I ordered a few of these myself. This is actually the first time I ever looked into deCONZ or DDF files, but I managed to make basic features available:

What works

What doesn't work

Also when I change the target temperature on the thermostat directly I don't get the new value in Home Assistant. However I see the updated value in deCONZ GUI, so that may be an issue somewhere else.

I will look into it again when I got some spare time. However tips would be appreciated, I already read that Aqara Devices tend to reimagine the Zigbee Standard 😄

aqara-thermostat-e1.json

{
  "schema": "devcap1.schema.json",
  "manufacturername": "$MF_LUMI",
  "modelid": "lumi.airrtc.agl001",
  "vendor": "Aqara",
  "product": "Thermostat E1",
  "sleeper": false,
  "status": "Draft",
  "path": "/devices/aqara-thermostat-e1.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/heatsetpoint",
          "default": 0
        },
        {
          "name": "config/mode",
          "parse": {
            "at": "0x001c",
            "cl": "0x0201",
            "ep": 0,
            "fn": "zcl"
          }
        },
        {
          "name": "config/offset",
          "default": 0
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/on",
          "refresh.interval": 5
        },
        {
          "name": "state/temperature",
          "default": 0
        },
      {
        "name": "state/valve",
        "read": {
          "at": "0x0012",
          "cl": "0x0201",
          "ep": 0,
          "fn": "zcl"
        },
        "parse": {
          "at": "0x0012",
          "cl": "0x0201",
          "ep": 0,
          "eval": "Item.val = Attr.val;",
          "fn": "zcl"
        },
        "default": 0
      }
    ]
  }
],
"bindings": [
  {
    "bind": "unicast",
    "src.ep": 1,
    "cl": "0x0000"
  },
  {
    "bind": "unicast",
    "src.ep": 1,
    "cl": "0x0201",
    "report": [
      {
        "at": "0x0000",
        "dt": "0x29",
        "min": 1,
        "max": 600,
        "change": "0x00000014"
      },
      {
        "at": "0x0012",
        "dt": "0x29",
        "min": 1,
        "max": 600
      }
    ]
  },
  {
    "bind": "unicast",
    "src.ep": 1,
    "cl": "0x000A"
  }
]
}
cameo77 commented 1 year ago

I have now this device, too. So I did some screenshots to complete the first post with the missing values.

Device

Screenshots

Basic

aqara_e1_cluster_basic aqara_e1_node_info aqara_e1_node

Power Configuration

aqara_e1_cluster_power

Identify

aqara_e1_cluster_identify

Lumi specific

aqara_e1_cluster_lumi_specific aqara_e1_cluster_lumi_specific_1 aqara_e1_cluster_lumi_specific_2

Time

aqara_e1_cluster_time

Thermostat

aqara_e1_cluster_thermostat_1 aqara_e1_cluster_thermostat_2 aqara_e1_cluster_thermostat_3 aqara_e1_cluster_thermostat_4 aqara_e1_cluster_thermostat_5 aqara_e1_cluster_thermostat_6 aqara_e1_cluster_thermostat_7 aqara_e1_cluster_thermostat_8 aqara_e1_cluster_thermostat_9

Identify (greyed out at the Node)

aqara_e1_cluster_greyed_identify

Lumi specific (greyed out)

aqara_e1_cluster_greyed_lumi_specific

Thermostat (greyed out)

aqara_e1_cluster_greyed_thermostat aqara_e1_cluster_greyed_thermostat_1

Time (greyed out)

aqara_e1_cluster_greyed_time

I hope this helps.

Luigi-01 commented 1 year ago

Today I recieved an Essential 120112 Smart Home Radiator Thermostat. They are identical and connected straight with deConz. I can operate the valve with Domoticz, no isseus. Tonight or tomorrow I will check deConz and add the screen shots for this device.

Luigi-01 commented 1 year ago

Hereby some screen shots from the Essential 120112 Smart Home Radiator Thermostat. Physical they are the Same, Firmware/Software ?

Essential 120112 CV Badkamer Node Info Clusterinfo Basic Cluster info Groups 01 Cluster info Groups 02 Cluster info OTAU Cluster Info Scenes 01 Cluster Info Scenes 02 Cluster info Tuya specific

Smanar commented 1 year ago

@ulbrich-media thx for the DDF

What doesn't work

battery status (zigbee specification of the device says the default cluster 0x0001, attribute 0x0021 is not supported)
external temperature sensor (with an aqara bridge you can connect the thermostat with an external sensor, I was hoping this is solved trough an attribute and not the bridge)
schedule (didn't look into that, but there are attributes for that)

Also when I change the target temperature on the thermostat directly I don't get the new value in Home Assistant. However I see the updated value in deCONZ GUI, so that may be an issue somewhere else.

For the battery, the attribute 0x0020 seem working ? You have 31 as value The status is "Draft" better to use "Gold", because users always forget to change it for tests. You are using the attribute 0x0012 for state/valve, and this one is the heatpoint, I think it's for that the return don't update config/heatpoint.

For some danfoss device there is a special attribute for external sensor, like the 0x4015

@Luigi-01 no it's a different device and your is already supported.

Luigi-01 commented 1 year ago

Sorry, I only wanted to help. Not my intention to disturb the discussion. There they are physical the same, I thought it would be help full.

Smanar commented 1 year ago

No problem, but take care your device is a tuya one, you can have so much clone of it, and you can have different device but with exactly the same look and buy at same seller.

cameo77 commented 1 year ago

I also added the DDF and had a look at the battery status. Therefore I looked at other zigbee devices with battery, so I tried to transfer the settings.

  "schema": "devcap1.schema.json",
  "manufacturername": "$MF_LUMI",
  "modelid": "lumi.airrtc.agl001",
  "vendor": "Aqara",
  "product": "E1 Thermostat",
  "sleeper": false,
  "status": "Gold",
  "path": "/devices/e1_thermostat.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/battery",
          "parse": {
            "at": "0x0020",
            "cl": "0x0001",
            "ep": 0,
            "eval": "Item.val = Attr.val",
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "config/heatsetpoint",
          "default": 0
        },
        {
          "name": "config/mode",
          "parse": {
            "at": "0x001c",
            "cl": "0x0201",
            "ep": 0,
            "fn": "zcl"
          }
        },
        {
          "name": "config/offset",
          "default": 0
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/on",
          "refresh.interval": 5
        },
        {
          "name": "state/temperature",
          "default": 0
        },
        {
          "name": "state/valve",
          "read": {
            "at": "0x0012",
            "cl": "0x0201",
            "ep": 0,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0012",
            "cl": "0x0201",
            "ep": 0,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          },
          "default": 0
        }
      ]
    }
  ],
  "bindings": [
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0000"
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 1,
          "max": 600
        },
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 1,
          "max": 600,
          "change": "0x00000014"
        }
      ]
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x000A"
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0001",
      "report": [
        {
          "at": "0x0020",
          "dt": "0x20",
          "min": 0,
          "max": 31,
          "change": "0x00000001"
        }
      ]
    }
  ]
}

I'm not sure if this is the correct way. I do not know very much about creating DDFs. The API tells about battery level 16:

    "config": {
        "battery": 0,
        "heatsetpoint": 500,
        "mode": "off",
        "offset": 0,
        "on": true,
        "reachable": true
    },
    "etag": "ce7edd88dc6e43d07826b6e5e7af082d",
    "lastannounced": null,
    "lastseen": "2022-09-30T09:31Z",
    "manufacturername": "LUMI",
    "modelid": "lumi.airrtc.agl001",
    "name": "Thermostat 11",
    "state": {
        "battery": 16,
        "lastupdated": "2022-09-30T09:31:28.696",
        "on": null,
        "temperature": 2500,
        "valve": 500
    },
    "swversion": "0.0.0_825",
    "type": "ZHAThermostat",
    "uniqueid": "54:ef:44:10:00:51:c3:5d-01-0201"
}

I definitely have no idea where this comes from. In Homeassistant the level is 0%.

Smanar commented 1 year ago

Ha ^^, ok, I have understand.

Try this DDF

{
"schema": "devcap1.schema.json",
  "manufacturername": "$MF_LUMI",
  "modelid": "lumi.airrtc.agl001",
  "vendor": "Aqara",
  "product": "E1 Thermostat",
  "sleeper": false,
  "status": "Gold",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/battery",
          "default": 0
        },
        {
          "name": "config/heatsetpoint",
          "default": 0
        },
        {
          "name": "config/mode",
          "parse": {
            "at": "0x001c",
            "cl": "0x0201",
            "ep": 0,
            "fn": "zcl"
          }
        },
        {
          "name": "config/offset",
          "default": 0
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/on",
          "parse": {
            "at": "0x0008",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val > 3;",
            "fn": "zcl"
          },
          "read": {
            "fn": "none"
          }
        },
        {
          "name": "state/temperature",
          "default": 0
        },
        {
          "name": "state/valve",
          "default": 0
        }
      ]
    }
  ],
  "bindings": [
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 1,
          "max": 600
        },
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 1,
          "max": 600,
          "change": "0x00000014"
        }
      ]
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x000A"
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0001",
      "report": [
        {
          "at": "0x0020",
          "dt": "0x20",
          "min": 300,
          "max": 43200,
          "change": "0x00000001"
        }
      ]
    }
  ]
}

I m still using the legacy code to get battery, but the good binding, I think heatpoint will work better too. Can need to wait a little for battery, I m using hudge values. Better to delete the device and re-include it (need to remake the binds)

cameo77 commented 1 year ago

I've used your DDF. After that I reincluded the device. The API is now:

"config": {
    "battery": 0,
    "heatsetpoint": 2000,
    "mode": "off",
    "offset": 0,
    "on": true,
    "reachable": true
},
"etag": "6b5f45c1803228268bb69b107b987af4",
"lastannounced": null,
"lastseen": "2022-10-02T07:00Z",
"manufacturername": "LUMI",
"modelid": "lumi.airrtc.agl001",
"name": "Thermostat 25",
"state": {
    "lastupdated": "none",
    "on": null,
    "temperature": 0,
    "valve": 0
},
"swversion": "0.0.0_0025",
"type": "ZHAThermostat",
"uniqueid": "54:ef:44:10:00:51:c3:5d-01-0201"                           

The Phoscon UI says, that the device is not reachable (but it is, so it isn't greyed out). And Home Assistant complains about the null state. Furthermore, in Home Assistant there are two temperature values. The first one is the target temperature, I think, this works well now. The second temperature, I think that's the measured value. Before the new DDF it was 25 degree (always constant at 25). With the new DDF, the value is still constant, but at 0 degree.

By the way, my thermostat isn't installed yet. It is on, but it's on my desk. I wanted to wait until it's working. I hope, that it doesn't make any difference.

Smanar commented 1 year ago

The Phoscon UI says, that the device is not reachable And Home Assistant complains about the null

"reachable": true

But the value is good in the API .... You have tried to "resynchronise" HA ?

The local temperature is the attribute 0x0000 in the cluster 0x0201, can you try to read it ? If the api is updated in same time, it's a bind problem, else it's from the DDF and need to make this change for state/temperature

        {
          "name": "state/temperature",
          "parse": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          }
        },
cameo77 commented 1 year ago

Okay, I did a restart of the deconz addon and a reload of the integration. HA isn't complaining anymore. But in Phoscon it's "not reachable": not_reachable Perhaps the null in the state block is the problem?

I read out the local temperature. The value is 2230. No changes in the api. So I added the part to the DDF (the cluster id was false before), did a reload of the DDF, a restart of the addon and a reload of the integration. Nothing changed. Then, I read it out manually again, and now the value is correct in the api and also in HA. So maybe there is still a bind problem? In Phoscon, the screen changed to: reachable

Battery percentage is still 0 in HA and also in the api as you can see above.

Smanar commented 1 year ago

Perhaps the null in the state block is the problem?

You mean the state/on ?

For me it's not a problem, we are missing the binding to update it, but you can force an update with reading the attribute 0x0008 on the thermostat cluster. I will set a defaut value in the DDF for it.

I have added a battery code full DDF too. Have removed the bind for the time cluster (other project don't use it)

BTW I m looking too all other attribute available on the manufacture cluster, so have added the child lock to test.

{
    "schema": "devcap1.schema.json",
    "manufacturername": "$MF_LUMI",
    "modelid": "lumi.airrtc.agl001",
    "vendor": "Aqara",
    "product": "E1 Thermostat",
    "sleeper": false,
    "status": "Gold",
    "subdevices": [{
        "type": "$TYPE_THERMOSTAT",
        "restapi": "/sensors",
        "uuid": [
            "$address.ext",
            "0x01",
            "0x0201"
        ],
        "items": [{
                "name": "attr/id"
            },
            {
                "name": "attr/lastannounced"
            },
            {
                "name": "attr/lastseen"
            },
            {
                "name": "attr/manufacturername"
            },
            {
                "name": "attr/modelid"
            },
            {
                "name": "attr/name"
            },
            {
                "name": "attr/swversion"
            },
            {
                "name": "attr/type"
            },
            {
                "name": "attr/uniqueid"
            },
            {
                "name": "config/battery",
                "parse": {
                    "at": "0x0020",
                    "cl": "0x0001",
                    "ep": 255,
                    "eval": "const vmin = 20; const vmax = 30; let bat = Attr.val; if (bat > vmax) { bat = vmax; } else if (bat < vmin) { bat = vmin; } bat = ((bat - vmin) / (vmax - vmin)) * 100; if (bat > 100) { bat = 100; } else if (bat <= 0)  { bat = 1; } Item.val = bat;"
                },
                "default": 0
            },
            {
                "name": "config/heatsetpoint",
                "default": 0
            },
            {
                "name": "config/mode",
                "parse": {
                    "at": "0x001c",
                    "cl": "0x0201",
                    "ep": 0,
                    "fn": "zcl"
                }
            },
            {
                "name": "config/offset",
                "default": 0
            },
            {
                "name": "config/on"
            },
            {
                "name": "config/reachable"
            },
            {
                "name": "state/lastupdated"
            },
            {
                "name": "state/on",
                "parse": {
                    "at": "0x0008",
                    "cl": "0x0201",
                    "ep": 1,
                    "eval": "Item.val = Attr.val > 3;",
                    "fn": "zcl"
                },
                "read": {
                    "fn": "none"
                },
                "default": false
            },
            {
                "name": "state/temperature",
                "parse": {
                    "at": "0x0000",
                    "cl": "0x0201",
                    "ep": 1,
                    "eval": "Item.val = Attr.val;",
                    "fn": "zcl"
                }
            },
            {
                "name": "state/valve",
                "default": 0
            },
            {
                "name": "config/locked",
                "awake": true,
                "parse": {
                    "at": "0x0277",
                    "cl": "0xfcc0",
                    "ep": 1,
                    "eval": "{ Item.val = Item.val }",
                    "fn": "zcl",
                    "mf": "0x115f"
                },
                "read": {
                    "at": "0x0277",
                    "cl": "0xfcc0",
                    "ep": 1,
                    "fn": "zcl",
                    "mf": "0x115f"
                },
                "write": {
                    "at": "0x0277",
                    "cl": "0xfcc0",
                    "dt": "0x10",
                    "ep": 1,
                    "eval": "Item.val",
                    "fn": "zcl",
                    "mf": "0x115f",
                    "state.timeout": 2
                },
                "default": false
            }
        ]
    }],
    "bindings": [{
            "bind": "unicast",
            "src.ep": 1,
            "cl": "0x0201",
            "report": [{
                    "at": "0x0012",
                    "dt": "0x29",
                    "min": 1,
                    "max": 600
                },
                {
                    "at": "0x0000",
                    "dt": "0x29",
                    "min": 300,
                    "max": 3600,
                    "change": "0x00000032"
                }
            ]
        },
        {
            "bind": "unicast",
            "src.ep": 1,
            "cl": "0x0001",
            "report": [{
                "at": "0x0020",
                "dt": "0x20",
                "min": 300,
                "max": 43200,
                "change": "0x00000001"
            }]
        }
    ]
}

Bind seem good for me, you have re-included the device, since the last time, for deconz remake all bind ? Have chnaged the reporting value to test

cameo77 commented 1 year ago

Okay, I took the new DDF, did a restart of the addon and reincluded the device. So now the battery percentage seems working, because the value is now 100% in Phoscon and also in HA. Thanks! The measured temperature was reported after pairing for about an hour (~ once every 20 minutes). After that, only if I read it manually. Then again for about an hour. Funny behaviour. So I did again a restart and reincluded the device. Same behaviour.

You mean the state/on ?

Yes, I meant. But state/on is false now and not null anymore.

After reincluding the device HA warns in the logs:

Logger: pydeconz.models.sensor.thermostat
Source: components/deconz/climate.py:154
First occurred: 09:33:34 (207 occurrences)
Last logged: 09:40:09

Unexpected thermostat mode None

If I change the thermostat mode in HA (and set it back to off), there are no more warnings.

At the config/lock: Unfortunately I don't know a simple way for copying/pasting the DDF into the HA deconz addon. So I have to reproduce the DDFs with the GUI. Didn't find a way to add the write block to the config/lock with the GUI. Therefore it's still missing in my DDF. Here the DDF I've used:

{
  "schema": "devcap1.schema.json",
  "manufacturername": "$MF_LUMI",
  "modelid": "lumi.airrtc.agl001",
  "vendor": "Aqara",
  "product": "E1 Thermostat",
  "sleeper": false,
  "status": "Gold",
  "path": "/devices/e1_thermostat.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/battery",
          "parse": {
            "at": "0x0020",
            "cl": "0x0001",
            "ep": 255,
            "eval": "const vmin = 20; const vmax = 30; let bat = Attr.val; if (bat > vmax) { bat = vmax; } else if (bat < vmin) { bat = vmin; } bat = ((bat - vmin) / (vmax - vmin)) * 100; if (bat > 100) { bat = 100; } else if (bat <= 0)  { bat = 1; } Item.val = bat;",
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "config/heatsetpoint",
          "default": 0
        },
        {
          "name": "config/locked",
          "awake": true,
          "read": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Item.val;",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "default": false
        },
        {
          "name": "config/mode",
          "parse": {
            "at": "0x001c",
            "cl": "0x0201",
            "ep": 0,
            "fn": "zcl"
          }
        },
        {
          "name": "config/offset",
          "default": 0
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/on",
          "refresh.interval": 5,
          "read": {
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0008",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val > 3;",
            "fn": "zcl"
          },
          "default": false
        },
        {
          "name": "state/temperature",
          "parse": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "state/valve",
          "default": 0
        }
      ]
    }
  ],
  "bindings": [
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 1,
          "max": 600
        },
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 300,
          "max": 3600,
          "change": "0x00000032"
        }
      ]
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0001",
      "report": [
        {
          "at": "0x0020",
          "dt": "0x20",
          "min": 300,
          "max": 43200,
          "change": "0x00000001"
        }
      ]
    }
  ]
}

API looks now:

 "27": {
        "config": {
            "battery": 100,
            "heatsetpoint": 2000,
            "locked": false,
            "mode": "off",
            "offset": 0,
            "on": true,
            "reachable": true
        },
        "etag": "d620752c5745eaa5895f0498f88f4ad3",
        "lastannounced": "2022-10-03T16:21:04Z",
        "lastseen": "2022-10-03T16:29Z",
        "manufacturername": "LUMI",
        "modelid": "lumi.airrtc.agl001",
        "name": "Thermostat 27",
        "state": {
            "lastupdated": "2022-10-03T16:21:10.584",
            "on": false,
            "temperature": 2170,
            "valve": 0
        },
        "swversion": "0.0.0_0025",
        "type": "ZHAThermostat",
        "uniqueid": "54:ef:44:10:00:51:c3:5d-01-0201"
    }

What would the child lock attribute do?

Smanar commented 1 year ago

The measured temperature was reported after pairing for about an hour (~ once every 20 minutes). After that, only if I read it manually. Then again for about an hour. Funny behaviour.

Ok, so I have no idea what happen, I need to search information on other forum.

Yes, I meant. But state/on is false now and not null anymore.

Yep, I have forced the false state, you can enable the bind of the attribute 0x0008 to test it, in fact the value become true when the value is > 3.

Unexpected thermostat mode None

Urf, this one NEED to be in binding, realy important, attribute 0x001c, if deconz don't update it fastly can set a defaut value, but for me "None" is a good defaut value, It mean "unknow yet" for me.

For config/locked (and not config/lock , this one is for door lock) it s the child protection, with your DDF you are not able to set it (need the write part) but if you change it manualy, you will have the result in the API.

I will make some search about the temperature that disable itself after 1 hour.

          "min": 300,
          "max": 3600,
          "change": "0x00000032"

with this setting you need to have a report minimum every hour, or with a 0.2 °C change, maximum every 300s.

Perhaps if decreasing the 3600 value ?

Luigi-01 commented 1 year ago

the child lock attribute, than the temperature cannot changed manually. You can turn the knob, but the temperature will not change. By pressing the knop 3 seconds, the knop will not accept any input. By pressing the knop again 3 seconds it will unlock.

cameo77 commented 1 year ago

Here some further informations, maybe it helps. I've reincluded the device again. This is how the API looks a few minutes after pairing:

"27": {
        "config": {
            "battery": 0,
            "heatsetpoint": 2050,
            "locked": false,
            "mode": null,
            "offset": 0,
            "on": true,
            "reachable": true
        },
        "etag": "5934d4add914de00ad0081a08723834f",
        "lastannounced": null,
        "lastseen": "2022-10-04T08:05Z",
        "manufacturername": "LUMI",
        "modelid": "lumi.airrtc.agl001",
        "name": "Thermostat 27",
        "state": {
            "lastupdated": "none",
            "on": false,
            "temperature": 0,
            "valve": 0
        },
        "swversion": "0.0.0_0025",
        "type": "ZHAThermostat",
        "uniqueid": "54:ef:44:10:00:51:c3:5d-01-0201"
    }

So I have to read the clusters manually (I always do this after pairing), then the battery value is correct again. For reading the clusters, it is necassary to play around with the device, like pressing or rotating the knob. Similiar behaviour as described here: https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/Xiaomi:-Lost-devices-or-functional-issues What I didn't know until now, that I have to do the reading (and playing around) more often. For the most attributes it seems necessary to read it individually (especially for the lumic specific cluster). That's very time consuming, but here are some screenshots of the clusters that have changed:

Basic

aqara_e1_cluster_basic_neu

Power configuration

aqara_e1_cluster_power_neu

Lumi specific

aqara_e1_cluster_lumi_specific_neu aqara_e1_cluster_lumi_specific_neu_2 aqara_e1_cluster_lumi_specific_neu_3 There are still some attributes (Unknown), for that the reading has failed.

Thermostat

aqara_e1_cluster_thermostat_neu aqara_e1_cluster_thermostat_neu_2 aqara_e1_cluster_thermostat_neu_3 aqara_e1_cluster_thermostat_neu_4 aqara_e1_cluster_thermostat_neu_5 aqara_e1_cluster_thermostat_neu_6

Time

Reading the time attributes ends up in "failed 0xC3"


As you can see, the child lock attribute isn't available after all. I'm sorry for that.

Perhaps if decreasing the 3600 value ?

I've changed the binding to:

{
    "at": "0x0000",
      "dt": "0x29",
      "min": 300,
      "max": 3000,
      "change": "0x0000000A"
}

Same behaviour, maybe I have to decrease it more. I think this behaviour is funny, because I can read the 0x0000 attribute individually. And it works every time - without any movements at the device. So I think, that isn't the problem. But why deconz doesn't read the value by itself? If I have a look to the logs (info_l2), I can see every second the following lines:

16:00:30:850 Idle timer triggered
16:00:30:852 Force read attributes for ZHAThermostat SensorNode Thermostat 27
16:00:30:854 Force binding of attribute reporting for node Thermostat 27

Urf, this one NEED to be in binding, realy important, attribute 0x001c, if deconz don't update it fastly can set a defaut value, but for me "None" is a good defaut value, It mean "unknow yet" for me.

Oh, yes, you're right. But after pairing (and reading out) I can see, that 0x001c has the value "auto". I think this option is in HA, too. Why deconz doesn't set this value to the api?

@Luigi-01: Thanks. I thought way too complicated.

Smanar commented 1 year ago

As you can see, the child lock attribute isn't available after all. I'm sorry for that.

And if you use the @Luigi-01 procedure, pressing the knop 3 seconds, It will probably go ot "true" in the API.

I can see every second the following lines:

Interesting, you haven't an error message that can explain why the bind have failed ?

But why deconz doesn't read the value by itself?

It's possible, but better to use use reporting, if this one not working deconz will use poll, can force it using

        {
          "name": "state/temperature",
          "parse": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          },
          "read": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "refresh.interval": 3660,
          "default": 0
        },

Refresh 3660 s.

Why deconz doesn't set this value to the api?

This value is not in binding, so this value is not reported by the device, except ofc if you read it yourself using deconz, add it in the binding list (have used defaut value used by deconz for temperature in attribute 0x0000)


    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 1,
          "max": 600
        },
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 1,
          "max": 600,
          "change": "0x00000032"
        },
        {
          "at": "0x001c ",
          "dt": "0x30",
          "min": 1,
          "max": 600
        }
      ]
    },
cameo77 commented 1 year ago

And if you use the @Luigi-01 procedure, pressing the knop 3 seconds, It will probably go ot "true" in the API.

I can activate the child lock at the device with the knob, that's right. But I think that's not an zigbee attribute anymore. See the new screenshots, it's unsupported/greyed out. That's what I meant. Same thing with the PI Heating Demand (0x0008 of thermostat cluster). We have used it for state/on, but with the new screenshots it's not supported.

Interesting, you haven't an error message that can explain why the bind have failed ?

No, there isn't. But over night it was reporting about one value every hour. Actually I didn't changed anything. Had a look to the history of the last days (to be sure), there wasn't a reporting for longer than an hour, exactly as described in the last posts. During the day, it was reporting more values. Didn't read it in deconz and didn't any movements at the device. Exciting. I hope, this is reproducible after reincluding.

It's possible, but better to use use reporting, if this one not working deconz will use poll, can force it using

I will wait before I add this, because maybe it's working without polling. I will reinclude it again to find it out.

This value is not in binding, so this value is not reported by the device, except ofc if you read it yourself using deconz, add it in the binding list (have used defaut value used by deconz for temperature in attribute 0x0000)

Will add the system mode to binding. Will see the results, probably after reincluding.


I wondered about the small number of supported attributes. If I see videos from people, who are using the thermostat with the aqara bridge, there are quite more functionalities. For example, the child lock, external temperature sensor, window detection and so on. Therefore I searched a little bit and found that the zigbee2mqtt project supports most of this features. So I think it has to be possible to control them through zigbee.

So I looked in the device request issue of zigbee2mqtt: https://github.com/Koenkk/zigbee2mqtt/issues/13993

In addition to that, I searched in the code of their zigbee library. I definitly don't know much about zigbee, but what I can see is, that the most of this features are in the lumi specific cluster. But they use some attribute numbers, that don't show up in deconz, e.g. 0x0277 for the child lock. I wasn't sure if the cluster in deconz and the one in zigbee2mqtt are the same. But there is one attribute, that is listed in both and it has the same value. It's the 0x00f7 in lumi specific cluster. Here the line at zigbee2mqtt: https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/devices/xiaomi.js#L77 So I assume, they are the same clusters. Is this correct? And why are the other attributes, that are listed there in the lines above, not in deconz, too?

Smanar commented 1 year ago

I can activate the child lock at the device with the knob, that's right. But I think that's not an zigbee attribute anymore. See the new screenshots, it's unsupported/greyed out. That's what I meant.

Oups right, it s missing on the xml file, it s the attribute 0x0277. So not possible to see it using deconz, but can be see in the API with the DDF

          "parse": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Item.val;",
            "fn": "zcl",
            "mf": "0x115f"
          },

We have used it for state/on, but with the new screenshots it's not supported.

?? it was enabled here https://github.com/dresden-elektronik/deconz-rest-plugin/issues/6351#issue-1384701437 and disabled here https://github.com/dresden-elektronik/deconz-rest-plugin/issues/6351#issuecomment-1267300771

I wasn't sure if the cluster in deconz and the one in zigbee2mqtt are the same

Yeah they are ^^, and we can use them too, exaclty like the config/locked. This one was a test, if it work can add all others with the same way, but to write them, you need to edit the DDF manualy to add the "write" part.

We can add it in the xml file (general.xml) if you want to see them in deconz ?

cameo77 commented 1 year ago

?? it was enabled here #6351 (comment) and disabled here #6351 (comment)

Yes, I know. That's the problem I described. If you click the read button above the attribute tables, not all attributes are read with this devices. Didn't know that, so deconz shows them as available. But they aren't. It comes up, when you read them all individually. I realized this late. So only the newest screenshots show it correct. We have to change this part of the ddf.

Yeah they are ^^, and we can use them too, exaclty like the config/locked.

Really nice. I tried it with the config/locked. First it didn't work. But I changed your ddf part to:

{
    "name": "config/locked",
    "parse": {
        "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
    },
}

Now it works perfect, I can see it in the api. Let's add the other attributes!

We can add it in the xml file (general.xml) if you want to see them in deconz ?

Yes, I think it would be useful. I will find a way to edit the ddf on console within the ha addon.

Smanar commented 1 year ago

Yes, I know. That's the problem I described. If you click the read button above the attribute tables, not all attributes are read with this devices. Didn't know that, so deconz shows them as available. But they aren't. It comes up, when you read them all individually. I realized this late. So only the newest screenshots show it correct. We have to change this part of the ddf.

Ha yes, have same for doorlock, thoses device are not sleeper, but are not powered, so not so powerfull, we need to read attribute one by one, else the "read" button have same result, the device is not able to send all, adn deconz mark them as not available.

But I changed your ddf part to:

I don't see the change, just removed the "read" part ?

Yes, I think it would be useful

Try adding this part

                <attribute-set id="0x0271" description="Smart Radiator Thermostat E1">
                    <attribute id="0x0271" name="Enabled" type="u8" mfcode="0x115f" access="rw" required="m"> </attribute>
                    <attribute id="0x0272" name="Mode" type="u8" mfcode="0x115f" access="rw" required="m"> </attribute>
                    <attribute id="0x0273" name="Window detection" type="u8" mfcode="0x115f" access="rw" required="m"> </attribute>
                    <attribute id="0x0274" name="Valve detection" type="u8" mfcode="0x115f" access="rw" required="m"> </attribute>
            <attribute id="0x0277" name="Child lock off" type="u8" mfcode="0x115f" access="rw" required="m">
                <description>Child lock off: 0 - false, 1 - true</description>
                    </attribute>
                    <attribute id="0x0279" name="Away temperature" type="u32" mfcode="0x115f" access="rw" required="m"> </attribute>
                </attribute-set>

Around the line 4320 in the file description.xml

dlueth commented 1 year ago

I don't see the change, just removed the "read" part ?

If the snippet is correct yes - and "eval": "Item.val = Attr.val;",

Is there a "mostly working" version of the DDF atm?

~I tried to rebuild one from your comments but it either does not work at all or now does not show sensor-temperature which used to work 2-3 days ago, related log eventually:~

~No thermostat sensor found for 0x54EF44100051D3B8, endpoint: 0x01~

Smanar commented 1 year ago

If the snippet is correct yes - and "eval": "Item.val = Attr.val;",

But this par tis already in the DDF ? and removing the "read" part have impact only if the device is polled .... I realy don't see why the previous DDF was not working.

To have the last DDf, I think it will be better to wait for @cameo77 share the modified one ^^.

dlueth commented 1 year ago

To have the last DDf, I think it will be better to wait for @cameo77 share the modified one ^^.

exactly what I am waiting for ;)

cameo77 commented 1 year ago

I don't see the change, just removed the "read" part ?

There was no read part in my ddf, so no removal. I only changed the expression Item.val = Item.val; to Item.val = Attr.val;. I don't know if there is a difference theoretically, but it is only working with the second expression. Tested it twice.

Around the line 4320 in the file description.xml

I'm now able to edit the files on console within the ha addon. The only file with the name 'description.xml' that I can find is in /usr/share/deCONZ/webapp/description.xml and has 43 lines. I think it's the wrong file. Is there another file with the same name? Or do you mean the 'general.xml'?


@dlueth: Here my current version of ddf:

{
  "schema": "devcap1.schema.json",
  "manufacturername": "$MF_LUMI",
  "modelid": "lumi.airrtc.agl001",
  "vendor": "Aqara",
  "product": "E1 Thermostat",
  "sleeper": false,
  "status": "Gold",
  "path": "/devices/e1_thermostat.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/battery",
          "read": {
            "at": "0x0020",
            "cl": "0x0001",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x0020",
            "cl": "0x0001",
            "ep": 1,
            "eval": "const vmin = 20; const vmax = 30; let bat = Attr.val; if (bat > vmax) { bat = vmax; } else if (bat < vmin) { bat = vmin; } bat = ((bat - vmin) / (vmax - vmin)) * 100; if (bat > 100) { bat = 100; } else if (bat <= 0)  { bat = 1; } Item.val = bat;",
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "config/heatsetpoint",
          "default": 0
        },
        {
          "name": "config/locked",
          "parse": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "default": false
        },
        {
          "name": "config/mode",
          "parse": {
            "at": "0x001c",
            "cl": "0x0201",
            "ep": 0,
            "fn": "zcl"
          }
        },
        {
          "name": "config/offset",
          "default": 0
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/on",
          "refresh.interval": 5,
          "read": {
            "fn": "None"
          },
          "parse": {
            "at": "0x0271",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          },
          "default": false
        },
        {
          "name": "state/temperature",
          "read": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "state/valve",
          "default": 0
        }
      ]
    }
  ],
  "bindings": [
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 1,
          "max": 600
        },
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 20,
          "max": 300
        },
        {
          "at": "0x001C",
          "dt": "0x30",
          "min": 1,
          "max": 600
        }
      ]
    },
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0001",
      "report": [
        {
          "at": "0x0020",
          "dt": "0x20",
          "min": 300,
          "max": 43200
        }
      ]
    }
  ]
}

I think, it would be interesting to know which functions work for you and which do not. So please share it with us.

Smanar commented 1 year ago

There was no read part in my ddf, so no removal. I only changed the expression Item.val = Item.val; to Item.val = Attr.val;. I don't know if there is a difference theoretically, but it is only working with the second expression. Tested it twice.

Ha fuck right, my bad, good catch. So to be able to change it using the API, the code can be

        {
          "name": "config/locked",
          "read": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "write": {
              "at": "0x0277",
              "cl": "0xfcc0",
              "dt": "0x10",
              "ep": 1,
              "eval": "Item.val",
              "fn": "zcl",
              "mf": "0x115f"
          },
          "default": false
        },

Is there another file with the same name? Or do you mean the 'general.xml'?

Right again, this file contain all attributes that can be see in deconz.

dlueth commented 1 year ago

@cameo77 Your DDF works like the one I used before did. I added the changes from @Smanar's last comment here. Battery is, like it was before, always "0" , mode initially "unknown" and child/lock is nowhere to be seen. The rest, at least, seems to work.

dlueth commented 1 year ago

@cameo77 OK, just did another test with your (unmodified) last DDF from here and added propsed changes to general.xml (which is very easy to achieve when using docker btw). I did remove the Radiator via phoscon this time and re-added it with the new DDF in place.

When re-adding it to OpenHAB this time ~i completely lost the "battery" channel and~ "mode" took a while to switch from "null" (meanwhile being unsettable) to "unkown" (becoming settable) and the "battery" channel took a while to occur (and still staying at 0%) . Child-Lock still missing as well

Smanar commented 1 year ago

@dlueth can you take a look direcly in the API, idk if openHAb can display the whole json ? or in phoscon/help/API Information/sensor ?

Because we can't be sure if the problem is from the DDF with looking in third app.

This device is a lazy one, so can take time to be full working after a re-incusion. As long we don't change the binding, you can just make a "hot reaload" in the DDF editor or restart deconz

I m looking for "mode, it seem you can send request to the device but return are only enabled for some of them.

            case 0x001C: // System Mode
            {
                if (sensor->modelId().startsWith(QLatin1String("SLR2")) ||   // Hive
                    sensor->modelId().startsWith(QLatin1String("SLR1b")) ||  // Hive
                    sensor->modelId().startsWith(QLatin1String("TH112")) ||  // Sinope
                    sensor->modelId().startsWith(QLatin1String("Zen-01")) || // Zen
                    sensor->modelId().startsWith(QLatin1String("AC201")))    // OWON
                {
                    qint8 mode = attr.numericValue().s8;
                    QString modeSet;

                    if      (mode == 0x01) { modeSet = QLatin1String("auto"); }
                    else if (mode == 0x03) { modeSet = QLatin1String("cool"); }
                    else if (mode == 0x04) { modeSet = QLatin1String("heat"); }
                    else if (mode == 0x05) { modeSet = QLatin1String("emergency heating"); }
                    else if (mode == 0x06) { modeSet = QLatin1String("precooling"); }
                    else if (mode == 0x07) { modeSet = QLatin1String("fan only"); }
                    else if (mode == 0x08) { modeSet = QLatin1String("dry"); }
                    else if (mode == 0x09) { modeSet = QLatin1String("sleep"); }
                    else                   { modeSet = QLatin1String("off"); }

                    item = sensor->item(RConfigMode);
                    if (item && !item->toString().isEmpty() && item->toString() != modeSet)
                    {
                        item->setValue(modeSet);
                        enqueueEvent(Event(RSensors, RConfigMode, sensor->id(), item));
                        configUpdated = true;
                    }
                }

so strange it can work for this device ? We probably need to make something like and adding a "parse" part. If someone can confirm it relay don't work at all ?

        {
          "name": "config/mode",
          "default" : "off",
          "values": [
            ["\"off\"", "off mode"],
            ["\"auto\"", "Auto mode"],
            ["\"cool\"", "Cool mode"],
            ["\"heat\"", "Heat mode"],
          ]
        },

For the battery, probably need to wait a little.

cameo77 commented 1 year ago

I have read a lot of code (of zigbee2mqtt, their zigbee library, deconz and ha integration), so now I probably know more. First about the 'general.xml': Your code is working well @smanar. I renamed some of the attributes and added the last two attributes. I tried to add values for 'preset', but it has no effect. What's wrong? Or is it better in ddf? Here my current version:

                                <attribute-set id="0x0271" description="Smart Radiator Thermostat E1">
                                        <attribute id="0x0271" name="Enabled" type="u8" mfcode="0x115f" access="rw" required="m"> </attribute>
                                        <attribute id="0x0272" name="Preset" type="u8" mfcode="0x115f" access="rw" required="m" default="0"> 
                                                <value name="manual" value="0"></value>
                                                <value name="auto" value="1"></value>
                                                <value name="away" value="2"></value>
                                        </attribute>
                                        <attribute id="0x0273" name="Window detection" type="u8" mfcode="0x115f" access="rw" required="m"> </attribute>
                                        <attribute id="0x0274" name="Valve fault detection" type="u8" mfcode="0x115f" access="rw" required="m"> </attribute>
                                        <attribute id="0x0277" name="Child lock on" type="u8" mfcode="0x115f" access="rw" required="m">
                                                <description>Child lock on: 0 - false, 1 - true</description>
                                        </attribute>
                                        <attribute id="0x0279" name="Away temperature" type="u32" mfcode="0x115f" access="rw" required="m"> </attribute>
                                        <attribute id="0x027b" name="Calibration" type="u8" mfcode="0x115f" access="r" required="m"> </attribute>
                                        <attribute id="0x027e" name="External sensor" type="u8" mfcode="0x115f" access="r" required="m"> </attribute>
                                </attribute-set>

About the battery problem: According to the zigbee2mqtt project and my tests, I assume, that the battery value isn't reported by the device itself. So we have to use poll for reading it. See the config/battery part in my current ddf below. It is working for me (it lasts 5 minutes after pairing until correct value). I'm thinking about setting the default value to 100 percent, but I don't know if it's useful.

About the mode and on: Again, according to the zigbee2mqtt project and my tests, I assume, that you can set if the device is heating or not only with the 0x0271 in lumi specific cluster. Using this the engine rotates the valve (system mode from thermostat cluster doesn't have an effect btw). Furthermore with preset I can set heating "mode" like 'auto', 'manual' or 'away'. So now the question is, how to implement this in ddf. Tried it with state/on and config/preset (see in the ddf). I can see it's working in the api, but I don't know if it's correct for the softwares that are using the api? And do we need a read or write part?

My current ddf:

{
  "schema": "devcap1.schema.json",
  "manufacturername": "$MF_LUMI",
  "modelid": "lumi.airrtc.agl001",
  "vendor": "Aqara",
  "product": "E1 Thermostat",
  "sleeper": false,
  "status": "Gold",
  "path": "/devices/e1_thermostat.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/battery",
          "refresh.interval": 300,
          "read": {
            "at": "0x0020",
            "cl": "0x0001",
            "ep": 1,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0020",
            "cl": "0x0001",
            "ep": 1,
            "eval": "const vmin = 20; const vmax = 30; let bat = Attr.val; if (bat > vmax) { bat = vmax; } else if (bat < vmin) { bat = vmin; } bat = ((bat - vmin) / (vmax - vmin)) * 100; if (bat > 100) { bat = 100; } else if (bat <= 0)  { bat = 1; } Item.val = bat;",
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "config/heatsetpoint",
          "default": 0
        },
        {
          "name": "config/locked",
          "read": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "default": false
        },
        {
          "name": "config/offset",
          "default": 0
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/preset",
          "parse": {
            "at": "0x0272",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          }
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/on",
          "refresh.interval": 5,
          "read": {
            "fn": "None"
          },
          "parse": {
            "at": "0x0271",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          }
        },
        {
          "name": "state/temperature",
          "read": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "state/valve",
          "default": 0
        }
      ]
    }
  ],
  "bindings": [
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 1,
          "max": 600
        },
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 20,
          "max": 300
        }
      ]
    }
  ]
}

@dlueth: Interesting, thanks. Can you see the child lock attribute in the api as @smanar described? I can't use it in ha, but I can see it in the api. How the battery value behaves with the new ddf (maybe it will last 5 minutes after pairing)?

dlueth commented 1 year ago

@cameo77

can you take a look direcly in the API, idk if openHAb can display the whole json ? or in phoscon/help/API Information/sensor ?

{ "config": { "battery": 0, "heatsetpoint": 2000, "locked": false, "mode": "heat", "offset": 75, "on": true, "reachable": true }, "etag": "867dce4e693e6baa6b7a85d6c28fbbec", "lastannounced": "2022-10-09T05:49:08Z", "lastseen": "2022-10-09T10:46Z", "manufacturername": "LUMI", "modelid": "lumi.airrtc.agl001", "name": "Aqara: Thermostat", "state": { "lastupdated": "2022-10-09T10:46:22.436", "on": true, "temperature": 2200, "valve": 0 }, "swversion": "0.0.0_0025", "type": "ZHAThermostat", "uniqueid": "54:ef:44:10:00:51:d3:b8-01-0201" }

dlueth commented 1 year ago

@cameo77 And after applying your current DDF + XML changes and waiting for some minutes:

{ "config": { "battery": 100, "heatsetpoint": 2000, "locked": false, "offset": 75, "on": true, "preset": null, "reachable": true }, "etag": "5d401028b567e5a532d35f9378552fd6", "lastannounced": null, "lastseen": "2022-10-09T10:56Z", "manufacturername": "LUMI", "modelid": "lumi.airrtc.agl001", "name": "Aqara: Thermostat", "state": { "lastupdated": "2022-10-09T10:56:11.361", "on": true, "temperature": 2220, "valve": 0 }, "swversion": "0.0.0_0025", "type": "ZHAThermostat", "uniqueid": "54:ef:44:10:00:51:d3:b8-01-0201" }

Smanar commented 1 year ago

I tried to add values for 'preset', but it has no effect

It's because of the type, from the z2m link this value is a u8, so a number. <value name="manual" value="0"></value> is for enum8, a list of value

You can try to cheat using enum8, but deconz will use this type in the request, so if the device whant a u8 the request will not work, you can describe all possible value in the <description>

For the battery, I don't see the polling in your DDF, it a field like "refresh.interval": 3600, but after a time if the report is not working deconz use poll itself.

For the working mode, there is a debate about "mode" and "preset". We are using HA rule, so mode can be only "off", "auto" and "manu". All other can be possible with "preset"' Some device have only "mode" some other have only "preset" (it's a jungle, thx tuya)

If you have only thoses 3 mode I think it's better to use them in "mode" than "preset"

        {
          "name": "config/mode",
          "parse": {
            "at": "0x0272",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = ['manu', 'auto', 'off'][Attr.val]",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "read": {
            "at": "0x0272",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          "write": {
              "at": "0x0272",
              "cl": "0xfcc0",
              "dt": "0x20",
              "ep": 1,
              "eval": "if (Item.val == 'manu') { 0 } else if (Item.val == 'auto') { 1 } else {2}",
              "fn": "zcl",
              "mf": "0x115f"
          },
        },

Tried it with state/on and config/preset (see in the ddf)

State/on is read only for sensor, writable value are in config/x

I can see it's working in the api, but I don't know if it's correct for the softwares that are using the api?

cf my previous comment

And do we need a read or write part?

Yes you need the "write" part toi be able to write the value using the API.

But it mean too we can remove the bind for the attribute 0x001C ? if we use only the one in the Xiaomi cluster ? And we can remove too the config/preset ?

dlueth commented 1 year ago

Btw, any idea if the offset is really taken into consideration by the radiator?

cameo77 commented 1 year ago

Okay, there were a few changes in z2m today. So I added the new attributes to the 'general.xml' and changed it according to your description. aqara_e1_cluster_lumi_specific_neu_22-10-09 So here my current version of the 'general.xml':

                                <attribute-set id="0x0271" description="Smart Radiator Thermostat E1">
                                        <attribute id="0x0271" name="Heating state" type="u8" mfcode="0x115f" access="rw" required="m"> 
                                                <description>Heating state: 0 - off, 1 - on</description>
                                        </attribute>
                                        <attribute id="0x0272" name="Preset" type="u8" mfcode="0x115f" access="rw" required="m" default="0"> 
                                                <description>Preset: 0 - manual, 1 - auto, 2 - away</description>
                                        </attribute>
                                        <attribute id="0x0273" name="Window detection" type="u8" mfcode="0x115f" access="rw" required="m">
                                                <description>Window detection: 0 - off, 1 - on</description>
                                        </attribute>
                                        <attribute id="0x0274" name="Valve fault detection" type="u8" mfcode="0x115f" access="rw" required="m">
                                                <description>Valve fault detection: 0 - off, 1 - on</description>
                                        </attribute>
                                        <attribute id="0x0275" name="Valve fault alarm" type="u8" mfcode="0x115f" access="r" required="m">
                                                <description>Valve fault alarm: 0 - false, 1 - true</description>
                                        </attribute>
                                        <attribute id="0x0277" name="Child lock on" type="u8" mfcode="0x115f" access="rw" required="m">
                                                <description>Child lock on: 0 - false, 1 - true</description>
                                        </attribute>
                                        <attribute id="0x0279" name="Away preset temperature" type="u32" mfcode="0x115f" access="rw" required="m"> </attribute>
                                        <attribute id="0x027a" name="Window open" type="u8" mfcode="0x115f" access="r" required="m">
                                                <description>Window open: 0 - false, 1 - true</description>
                                        </attribute>
                                        <attribute id="0x027b" name="Calibrated" type="u8" mfcode="0x115f" access="r" required="m">
                                                <description>Calibrated: 0 - false, 1 - true</description>
                                        </attribute>
                                        <attribute id="0x027e" name="External sensor" type="u8" mfcode="0x115f" access="r" required="m">
                                                <description>Temperature sensor: 0 - internal, 1 - external</description>
                                        </attribute>
                                        <attribute id="0x040a" name="Battery" type="u8" mfcode="0x115f" access="r" required="m"> </attribute>
                                </attribute-set>

I don't see the polling in your DDF

There was a "refresh.interval": 300, at the beginning of config/battery. But, as you can see, there is now a battery value in lumi specific cluster (thx aqara...). So I changed the config/battery to the new attribute. Now the value appears instantly after pairing. I don't know if it's updated without bind/poll.

 {
          "name": "config/battery",
          "read": {
            "at": "0x040a",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x040a",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "default": 0
        },

We are using HA rule, so mode can be only "off", "auto" and "manu".

Okay, the thermostat has two attributes for control. With the 0x0271 I can set if it's heating or not (on/off). And with the 0x0272 I can set the preset (manual/auto/away). If I look to your ddf part, I'm not sure if it works correct, because the 0x0272 has no off functionality. I think, we need both attributes. Not sure, but according to ha documentation and deconz integration code, it could be possible to use both: What do you think about? I would try to use config/preset for 0x0272. But is there an config option that I can use for 0x0271 instead of config/mode (because 0x0271 has no auto value)?

State/on is read only for sensor, writable value are in config/x

Yes you need the "write" part toi be able to write the value using the API.

Thanks! I will change it.

But it mean too we can remove the bind for the attribute 0x001C ? if we use only the one in the Xiaomi cluster ?

Is removed. Binding now only for occupied heating point and local temp.


@dlueth: Okay, child lock is visible in the api. So I assume, that's not a problem of deconz.

Btw, any idea if the offset is really taken into consideration by the radiator?

unfortunately not. maybe @smanar? funny, that you have an offset in the api and I haven't.

dlueth commented 1 year ago

@Smanar when using your DDF it is visible in phoscon, not when using @cameo77 's

I do have an offset because my openhab calculates the delta of thermostat's sensor vs external sensor and sets it ;)

dlueth commented 1 year ago

Btw, I will receive some essential radiators tomorrow most likely, they are the same as Aqara but have been supported before by deconz

Smanar commented 1 year ago

Now the value appears instantly after pairing. I don't know if it's updated without bind/poll.

Good question, from my memory Xiaomi cluster don't need bind/report.

when using your DDF it is visible in phoscon, not when using @cameo77 's

Hu ? On my side I m using the last gived by him too, perhaps there is a typo in one of them ? Phoscon is not a "reference" too, better to check on HA or direclty in the API.

I think, we need both attributes.

So the attribute that make on/off in "mode", and the attribute that make manual/auto/away in "preset" ?

What do you think about? I would try to use config/preset for 0x0272. But is there an config option that I can use for 0x0271 instead of config/mode (because 0x0271 has no auto value)?

yes, config/mode is device dependent, there is some device with just on/off, like some wall mounted thermostat, they have all managed by "preset", "mode" is just to turn the device "on" or "off". "Auto" will just not working in HA

Btw, any idea if the offset is really taken into consideration by the radiator?

I m taking a look in the code, for ZHAThermostat device, this request use a zigbee request so send a "calibration" value to the device. It's the attribute 0x0010 in the thermostat cluster. And yes it seem this field can be used by legacy code for all ZHAThermostat.

cameo77 commented 1 year ago

Good question, from my memory Xiaomi cluster don't need bind/report.

Well, I would also not add bind/report.

So the attribute that make on/off in "mode", and the attribute that make manual/auto/away in "preset" ?

Exactly. Both are necessary, I think.

yes, config/mode is device dependent, there is some device with just on/off, like some wall mounted thermostat, they have all managed by "preset", "mode" is just to turn the device "on" or "off". "Auto" will just not working in HA

So I should use config/mode and config/preset for them, shouldn't I? I read some code of the deconz integration. It's interesting. Mode 'auto' is only added if there is config/mode in api (look here). Accordingly, if there isn't, only the modes 'off' and 'heat' exist. Actually that's what we would need. So the question is which item we could use instead. For that I looked into the function, that sets the mode. Accordingly it is the config/on, take a look at here. But config/on is managed internally, as the ddf editor tells. Or could we use it? I'm really not sure if that would work. So let me know your thoughts about. Otherwise we simply use config/mode and setting 'auto' has no effect.

Smanar commented 1 year ago

I read some code of the deconz integration. It's interesting. Mode 'auto' is only added if there is config/mode in api (look here). Accordingly, if there isn't, only the modes 'off' and 'heat' exist. Actually that's what we would need.

IDK how work this code, but if there is no "config/mode", you will have no mode at all, so no more "heat" and "off" no ? If I m right you have a widget in HA with auto/off/heat, and this one work only with "config/mode" so if you want to use this one you need the "config/mode" No ? even "auto is not working.

"config/on" is used for rules, can't use this one.

There is "config/setvalve" as bool, but I think the integration in HA will be better natively is using "config/mode"

cameo77 commented 1 year ago

The more I was reading, the more I was tending to use config/mode. So let's proceed with it. Here is my ddf part:

    {
          "name": "config/mode",
          "read": {
            "at": "0x0271",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x0271",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = ['off', 'heat'][Attr.val];",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "write": {
             "at": "0x0271",
             "cl": "0xfcc0",
             "dt": "0x20",
             "ep": 1,
             "eval": "if (Item.val == 'off') { 0 } else if (Item.val == 'heat') { 1 }",
             "fn": "zcl",
             "mf": "0x115f"
          }
        },

Reading works, but writing doesn't (through home assistant). Did a restart of the addon and reinclude of the device. Do you see the error?

Smanar commented 1 year ago

dt = 0x20, it's the correct type for u8 All the rest seem fine for me

I think you can take a look in same time in logs with flag

On some DDF there is too "state.timeout": 2 but I don't think it will be usefull on this one, a TRV is not a deep sleeping device.

cameo77 commented 1 year ago

Okay, thank you. With DDF I can't see a evaluation of the write part in the logs. With info and info_l2, I can see the following lines while changing config/mode through ha:

09:35:03:489 Websocket 172.30.32.1:54536 send message: {"config":{"battery":100,"heatsetpoint":2200,"locked":false,"mode":"off","offset":0,"on":true,"preset":"manual","reachable":true},"e":"changed","id":"27","r":"sensors","t":"event","uniqueid":"54:ef:44:10:00:51:c3:5d-01-0201"} (ret = 225)
09:35:03:927 No thermostat sensor found for 0x54EF44100051C35D, endpoint: 0x01
09:35:03:930 Websocket 172.30.32.1:54536 send message: {"e":"changed","id":"27","r":"sensors","state":{"lastupdated":"2022-10-11T07:35:03.927","on":true,"temperature":2260,"windowopen":"false"},"t":"event","uniqueid":"54:ef:44:10:00:51:c3:5d-01-0201"} (ret = 196)

No interesting logs with ZCL.

dlueth commented 1 year ago

Btw, received my _TYST11_jeaxp72v (Essentials Radiator Premium) yesterday which is essentially the same device. These connect fine but seem to share issues regarding mode/preset. Mode is shown as "unknown" and seems to be not settable. Child lock is also missing there. Might this issue fix that as well?

Smanar commented 1 year ago

There are realy not same device, one is using the tuya cluster, the other the Xiaomi one.

With DDF I can't see a evaluation of the write part in the logs.

Not normal ... Childlock is working (the write stuff) ? nothing in logs too ?

09:35:03:927 No thermostat sensor found for 0x54EF44100051C35D, endpoint: 0x01

Not normal too. It mean the code haven't found ZHAThermostat for endpoint 01 and MAC adresss 0x54EF44100051C35D and it's exacly that

"uniqueid":"54:ef:44:10:00:51:c3:5d-01-0201"

The device type is a ZHAThermostat ? But this part impact only return, not send request.

cameo77 commented 1 year ago

Childlock is working (the write stuff) ? nothing in logs too ?

Childlock doesn't appear in ha. I can only see it in the api. So I don't know if writing works.

The device type is a ZHAThermostat ?

Yes. Didn't change that. It's still the same as in the ddfs in my posts above. "uniqueid":"54:ef:44:10:00:51:c3:5d-01-0201" MAC address seems to be correct, Endpoint too. But why 0201? It's the thermostat cluster, not lumi specific, I think.

Is there a way to call the api through url/http request? Would be interesting if the error is by ha or by deconz

cameo77 commented 1 year ago

Found a way to control the api through command line and tried to write config/mode -> same behaviour as before Added 0xfcc0 to uuid (at the top of the ddf) -> can't see the 'not found' log anymore, but value isn't written Added binding for mode attribute -> 'not found' log appears periodically, value isn't written

So I think, it's a problem in deconz. Beyond that I do not know anymore than before.

Smanar commented 1 year ago

09:35:03:927 No thermostat sensor found for 0x54EF44100051C35D, endpoint: 0x01

Ok, so Swoops have found the problem, we miss the fingerprint

  "path": "/devices/e1_thermostat.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "fingerprint": {
         "profile": "0x0104",
         "device": "0x0301",
         "endpoint": "0x01",
         "in": [
           "0x0000",
           "0xFCC0",
           "0x0201"
         ]
       },
      "items": [
        {
          "name": "attr/id"

You can use a REST client to edit value yourself https://dresden-elektronik.github.io/deconz-rest-doc/getting_started/ Else just curl curl -H 'Content-Type: application/json' -X PUT -d '{"duration": 90}' http://192.168.1.1:80/api/12345678/sensors/16/config

But strange Childlock don't appear in HA, its not something new.

cameo77 commented 1 year ago

Okay, I have added the fingerprint to my ddf. There is no 'not found' log anymore, but writing doesn't work through the api. Here some logs while setting mode through ha (with info and info_l2):

11:10:27:072 add task 13644 type 37 to 0x54EF44100051C35D cluster 0x0201 req.id 146
11:10:27:154 Websocket 172.30.32.1:49136 send message: {"config":{"battery":100,"heatsetpoint":700,"locked":false,"mode":"heat","offset":0,"on":true,"preset":"manual","reachable":true},"e":"changed","id":"27","r":"sensors","t":"event","uniqueid":"54:ef:44:10:00:51:c3:5d-01-0201"} (ret = 225)

Still no evaluation to see in ddf log, no usefully data in zcl.


Edit: And here the error log from home assistant while setting preset:

[547364435328] {'address': '/sensors/27/config/preset', 'description': 'Could not set attribute', 'type': 608}
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 202, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1738, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1775, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 207, in handle_service
    await service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 678, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 931, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 715, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/deconz/climate.py", line 205, in async_set_preset_mode
    await self.gateway.api.sensors.thermostat.set_config(
  File "/usr/local/lib/python3.10/site-packages/pydeconz/interfaces/sensors.py", line 560, in set_config
    return await self.gateway.request_with_retry(
  File "/usr/local/lib/python3.10/site-packages/pydeconz/gateway.py", line 142, in request_with_retry
    return await self.request(method, path, json)
  File "/usr/local/lib/python3.10/site-packages/pydeconz/gateway.py", line 167, in request
    response: dict[str, Any] = await self._request(
  File "/usr/local/lib/python3.10/site-packages/pydeconz/gateway.py", line 194, in _request
    _raise_on_error(response)
  File "/usr/local/lib/python3.10/site-packages/pydeconz/gateway.py", line 225, in _raise_on_error
    raise_error(data["error"])
  File "/usr/local/lib/python3.10/site-packages/pydeconz/errors.py", line 80, in raise_error
    raise pydeconzException(error)
pydeconz.errors.pydeconzException: {'address': '/sensors/27/config/preset', 'description': 'Could not set attribute', 'type': 608}

Edit 2: I tried to set child lock through api (I used curl, because it still doesn't appear in ha). It works!!!


Here my current ddf:

{
  "schema": "devcap1.schema.json",
  "manufacturername": "$MF_LUMI",
  "modelid": "lumi.airrtc.agl001",
  "vendor": "Aqara",
  "product": "E1 Thermostat",
  "sleeper": false,
  "status": "Gold",
  "path": "/devices/e1_thermostat.json",
  "subdevices": [
    {
      "type": "$TYPE_THERMOSTAT",
      "restapi": "/sensors",
      "uuid": [
        "$address.ext",
        "0x01",
        "0x0201"
      ],
      "fingerprint": {
        "profile": "0x0104",
        "device": "0x0301",
        "endpoint": "0x01",
        "in": [
          "0x0000",
          "0xfcc0",
          "0x0201"
        ]
      },
      "items": [
        {
          "name": "attr/id"
        },
        {
          "name": "attr/lastannounced"
        },
        {
          "name": "attr/lastseen"
        },
        {
          "name": "attr/manufacturername"
        },
        {
          "name": "attr/modelid"
        },
        {
          "name": "attr/name"
        },
        {
          "name": "attr/swversion"
        },
        {
          "name": "attr/type"
        },
        {
          "name": "attr/uniqueid"
        },
        {
          "name": "config/battery",
          "read": {
            "at": "0x040a",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x040a",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "default": 0
        },
        {
          "name": "config/heatsetpoint",
          "read": {
            "at": "0x0012",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0012",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          },
          "default": 0
        },
        {
          "name": "config/locked",
          "read": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x0277",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "write": {
             "at": "0x0277",
             "cl": "0xfcc0",
             "dt": "0x20",
             "ep": 1,
             "eval": "if (Item.val == true) { 1 } else { 0 }",
             "fn": "zcl",
             "mf": "0x115f"
          },
          "default": false
        },
        {
          "name": "config/offset",
          "default": 0
        },
        {
          "name": "config/on"
        },
        {
          "name": "config/mode",
          "read": {
            "at": "0x0271",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x0271",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = ['off', 'heat'][Attr.val];",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "write": {
             "at": "0x0271",
             "cl": "0xfcc0",
             "dt": "0x20",
             "ep": 1,
             "eval": "if (Item.val == 'off') { 0 } else if (Item.val == 'heat') { 1 }",
             "fn": "zcl",
             "mf": "0x115f"
          }
        },
        {
          "name": "config/preset",
          "read": {
            "at": "0x0272",
            "cl": "0xfcc0",
            "ep": 1,
            "fn": "zcl",
            "mf": "0x115f"
          },
          "parse": {
            "at": "0x0272",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = ['manual', 'auto', 'holiday'][Attr.val];",
            "fn": "zcl",
            "mf": "0x115f"
          },
          "write": {
             "at": "0x0272",
             "cl": "0xfcc0",
             "dt": "0x20",
             "ep": 1,
             "eval": "if (Item.val == 'manual') { 0 } else if (Item.val == 'auto') { 1 } else if (Item.val == 'holiday') { 2 }",
             "fn": "zcl",
             "mf": "0x115f"
          }
        },
        {
          "name": "config/reachable"
        },
        {
          "name": "state/lastupdated"
        },
        {
          "name": "state/on",
          "refresh.interval": 5,
          "parse": {
            "at": "0x0271",
            "cl": "0xfcc0",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl",
            "mf": "0x115f"
          }
        },
        {
          "name": "state/temperature",
          "read": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "fn": "zcl"
          },
          "parse": {
            "at": "0x0000",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val;",
            "fn": "zcl"
          },
          "default": 0
        }
      ]
    }
  ],
  "bindings": [
    {
      "bind": "unicast",
      "src.ep": 1,
      "cl": "0x0201",
      "report": [
        {
          "at": "0x0012",
          "dt": "0x29",
          "min": 1,
          "max": 600
        },
        {
          "at": "0x0000",
          "dt": "0x29",
          "min": 20,
          "max": 300
        }
      ]
    }
  ]
}