- 
                Notifications
    You must be signed in to change notification settings 
- Fork 526
DDF for Eurotronic spirit radiator thermostat (SPZB0001) #8361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
| The typo error is corrected ? | 
| I don't understand the error either, but it's actually about the DDF. | 
| Perhaps it's because the PR is on Draft status ? So no new check. | 
| I've even deleted everything and the error still exists. | 
| There are no  | 
| Ha yes, was the missing config_hostflags_item.json. On the code this flag is hidden, but IDK if it's usefull. 
 | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the PR. Way better to track changes :)
Please have a look at my comments. Apart from those, it seems that the config/offset item got lost from the issue discussion, so I'd suggest to add
        {
          "name": "config/offset",
          "refresh.interval": 3660,
          "write": {
            "at": "0x0010",
            "cl": "0x0201",
            "dt": "0x28",
            "ep": 1,
            "eval": "Item.val / 10;",
            "fn": "zcl:attr"
          },
          "parse": {
            "at": "0x0010",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val * 10;",
            "fn": "zcl:attr"
          },
          "default": 0
        },
| "name": "state/on", | ||
| "refresh.interval": 660, | ||
| "read": { | ||
| "at": "0x0000", | ||
| "cl": "0x0006", | ||
| "ep": 1, | ||
| "fn": "zcl:attr" | ||
| }, | ||
| "parse": { | ||
| "at": "0x0000", | ||
| "cl": "0x0006", | ||
| "ep": 1, | ||
| "eval": "Item.val = Attr.val", | ||
| "fn": "zcl:attr" | ||
| }, | ||
| "default": false | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the former content got lost. Here, it should be as follows (the attribute is read through state/valve):
          "name": "state/on",
          "parse": {
            "at": "0x0008",
            "cl": "0x0201",
            "ep": 1,
            "eval": "Item.val = Attr.val > 3;",
            "fn": "zcl:attr"
          },
          "read": {
            "fn": "none"
          }
| "read": { | ||
| "fn": "none" | ||
| }, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any particular reason not to read the attribute? I would've left the default read function here.
| "read": { | ||
| "at": "0x4008", | ||
| "cl": "0x0201", | ||
| "ep": 1, | ||
| "fn": "zcl:attr", | ||
| "mf": "0x1037" | ||
| }, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend to change the function here to
          "read": {
            "fn": "none"
          },
and let config/hostflags do the read for all other items relying on it. That would save lots of unnecessary reads.
| "read": { | ||
| "at": "0x4008", | ||
| "cl": "0x0201", | ||
| "ep": 1, | ||
| "fn": "zcl:attr", | ||
| "mf": "0x1037" | ||
| }, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend to change the function here to
          "read": {
            "fn": "none"
          },
and let config/hostflags do the read for all other items relying on it. That would save lots of unnecessary reads.
| "read": { | ||
| "at": "0x4008", | ||
| "cl": "0x0201", | ||
| "ep": 1, | ||
| "fn": "zcl:attr", | ||
| "mf": "0x1037" | ||
| }, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend to change the function here to
          "read": {
            "fn": "none"
          },
and let config/hostflags do the read for all other items relying on it. That would save lots of unnecessary reads.
| { | ||
| "name": "config/heatsetpoint", | ||
| "refresh.interval": 660, | ||
| "read": { | ||
| "at": "0x0012", | ||
| "cl": "0x0201", | ||
| "ep": 1, | ||
| "fn": "zcl:attr" | ||
| }, | ||
| "write": { | ||
| "at": "0x0012", | ||
| "cl": "0x0201", | ||
| "dt": "0x29", | ||
| "ep": 1, | ||
| "eval": "Item.val", | ||
| "fn": "zcl:attr" | ||
| }, | ||
| "parse": { | ||
| "at": "0x0012", | ||
| "cl": "0x0201", | ||
| "ep": 1, | ||
| "eval": "Item.val = Attr.val", | ||
| "fn": "zcl:attr" | ||
| }, | ||
| "default": 0 | ||
| }, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one here is very delicate, as the screwed firmware version does not allow for any differentiation which attribute must be written. For the Spirit, the legacy code uses mf attribute 0x4003, so I'd vouch for continuing using it in the read and parse functions.
As for the write function, I guess we can leave it as is, since it doesn't matter anyway. The legacy code has an ugly, but required workaround and sends a write request to any relevant attribute (so in total 2). As said, this must remain as you have no chance to know which attribute the hardware really accepts.
Please, this must be tested in strict mode!
| "id": "config/hostflags", | ||
| "datatype": "Int32", | ||
| "access": "RW", | ||
| "public": true, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the item should not be public.
| "dt": "0x29", | ||
| "mf": "0x1037", | ||
| "min": 1, | ||
| "max": 600 | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Legacy code has a reportable change of 50 (int value). Do we want to adapt that?
| @SwoopX Thank you for your help and I hope I understood the changes correctly but please take another look. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems as if the force push screwed the proper tracking of the changes...
From what I can see, quite some write functions have been deleted, presumably accidentally? Also, the question regarding the reportable change is still pending and if the DDF has been tested in strict mode.
| Now I'm completely confused, too. Probably something about ("read" => "fn": "none"), right? I haven't been able to test it yet because I'm using HA and am currently testing it on Windows. But I'd like to start with a somewhat finished DDF. | 
| @SwoopX I just tested everything in strict mode, and the device works exactly as expected. The valve shows values between 0 and 100, and the error code appears immediately, even if I remove the thermostat. The only thing I haven't been able to test is "windowopen", as it's apparently still too warm outside. So, for me, the DDF is now ready for use, but only in strict mode; otherwise, it doesn't work. {
    "capabilities": {
        "sleeper": false
    },
    "config": {
        "battery": 60,
        "displayflipped": false,
        "heatsetpoint": 2100,
        "locked": false,
        "mode": "auto",
        "offset": 0,
        "on": true,
        "reachable": true
    },
    "ep": 1,
    "etag": "6088eb7dd4abf9d3f826e8ed75b7bdfe",
    "lastannounced": "2025-10-25T13:47:57Z",
    "lastseen": "2025-10-25T13:56Z",
    "manufacturername": "Eurotronic",
    "modelid": "SPZB0001",
    "name": "Thermostat - Diele",
    "nwkaddress": "0x9EB5",
    "state": {
        "errorcode": "none",
        "lastupdated": "2025-10-25T13:57:03.876",
        "on": false,
        "temperature": 2158,
        "valve": 0,
        "windowopen": "0"
    },
    "swversion": "18181120",
    "type": "ZHAThermostat",
    "uniqueid": "00:15:8d:00:07:74:34:93-01-0201"
}Events:     "16:15:42:46": {
        "e": "changed",
        "id": "36",
        "r": "sensors",
        "state": {
            "errorcode": "none",
            "lastupdated": "2025-10-25T14:15:42.045",
            "on": false,
            "temperature": 2087,
            "valve": 0,
            "windowopen": "0"
        },
        "t": "event",
        "uniqueid": "00:15:8d:00:07:74:34:93-01-0201"
    }
} | 
| Awesome, I guess this one should be ready to go then. However, I'd need to prepare another PR to have the legacy code removed completely, otherwise the DDF is not used. One last remark though: the legacy code sets the bits for the hostflags a little different. No clue if that has any (noticable) impact or not. | 
| Thanks for taking over the follow-up PR, and this old device is a bit slower than the new ones anyway, but that's not a big deal. So the legacy code is getting smaller and smaller. I'll now make it "Ready for review". | 
| Nice work guys, much appreciated when the legacy code can be removed too later on 👍 | 
| I fear it needs to go with the legacy code simultaneously. Will prepare the accompanying PR on the weekend at the latest. | 
This PR is a follow-up to device request #8333 (Eurotronic SPZB0001), and I hope we can finish it. If @SwoopX, @Smanar, @manup helps, it could happen quickly ;)
Spirit_ZigBee_BAL_web_DE_Okt.-2019.pdf