Skip to content

DDF for Eurotronic Spirit radiator thermostat (SPZB0001) - #8361

Merged
manup merged 7 commits into
dresden-elektronik:masterfrom
mattreim:SPZB0001
Nov 5, 2025
Merged

DDF for Eurotronic Spirit radiator thermostat (SPZB0001)#8361
manup merged 7 commits into
dresden-elektronik:masterfrom
mattreim:SPZB0001

Conversation

@mattreim

@mattreim mattreim commented Oct 17, 2025

Copy link
Copy Markdown
Collaborator

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

Must be merged with #8377

@Smanar

Smanar commented Oct 18, 2025

Copy link
Copy Markdown
Collaborator

The typo error is corrected ?
I don't see why the validor is saying there is an error.

@mattreim

Copy link
Copy Markdown
Collaborator Author

I don't understand the error either, but it's actually about the DDF.

@Smanar

Smanar commented Oct 18, 2025

Copy link
Copy Markdown
Collaborator

Perhaps it's because the PR is on Draft status ? So no new check.

@mattreim
mattreim marked this pull request as ready for review October 18, 2025 17:15
@mattreim

Copy link
Copy Markdown
Collaborator Author

I've even deleted everything and the error still exists.

@github-actions

github-actions Bot commented Oct 18, 2025

Copy link
Copy Markdown
Contributor

Hey @mattreim, thanks for your pull request!

Tip

Modified bundles can be downloaded here.
Relative expire date

DDB changes

Modified

  • eurotronic/eurotronic_spzb0001_trv.json : Spirit radiator thermostat ✔️

Validation

Tip

Everything is fine !

🦆 Updated for commit 4f47c45

@mattreim
mattreim marked this pull request as draft October 18, 2025 20:13
@mattreim

Copy link
Copy Markdown
Collaborator Author

There are no config/hostflags yet, which I added. The information is from the PDF, but I don't think it's correct yet.

@Smanar

Smanar commented Oct 19, 2025

Copy link
Copy Markdown
Collaborator

Ha yes, was the missing config_hostflags_item.json.

On the code this flag is hidden, but IDK if it's usefull.

sensor.addItem(DataTypeUInt32, RConfigHostFlags)->setIsPublic(false);

@SwoopX SwoopX left a comment

Copy link
Copy Markdown
Collaborator

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
        },

Comment on lines +247 to +262
"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

Copy link
Copy Markdown
Collaborator

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"
          }

Comment on lines +285 to +287
"read": {
"fn": "none"
},

Copy link
Copy Markdown
Collaborator

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.

Comment on lines +162 to +168
"read": {
"at": "0x4008",
"cl": "0x0201",
"ep": 1,
"fn": "zcl:attr",
"mf": "0x1037"
},

Copy link
Copy Markdown
Collaborator

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.

Comment on lines +191 to +197
"read": {
"at": "0x4008",
"cl": "0x0201",
"ep": 1,
"fn": "zcl:attr",
"mf": "0x1037"
},

Copy link
Copy Markdown
Collaborator

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.

Comment on lines +86 to +92
"read": {
"at": "0x4008",
"cl": "0x0201",
"ep": 1,
"fn": "zcl:attr",
"mf": "0x1037"
},

Copy link
Copy Markdown
Collaborator

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.

Comment on lines +112 to +137
{
"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
},

Copy link
Copy Markdown
Collaborator

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,

Copy link
Copy Markdown
Collaborator

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

Copy link
Copy Markdown
Collaborator

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?

@mattreim

mattreim commented Oct 22, 2025

Copy link
Copy Markdown
Collaborator Author

@SwoopX Thank you for your help and I hope I understood the changes correctly but please take another look.

@mattreim
mattreim requested a review from SwoopX October 24, 2025 16:11

@SwoopX SwoopX left a comment

Copy link
Copy Markdown
Collaborator

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.

@mattreim

Copy link
Copy Markdown
Collaborator Author

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.

@mattreim
mattreim requested a review from SwoopX October 24, 2025 21:25
@mattreim

mattreim commented Oct 25, 2025

Copy link
Copy Markdown
Collaborator Author

@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"
    }
}

@SwoopX

SwoopX commented Oct 25, 2025

Copy link
Copy Markdown
Collaborator

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.

@mattreim

Copy link
Copy Markdown
Collaborator Author

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".

@mattreim
mattreim marked this pull request as ready for review October 25, 2025 22:11
@manup

manup commented Oct 29, 2025

Copy link
Copy Markdown
Member

Nice work guys, much appreciated when the legacy code can be removed too later on 👍

@manup manup added this to the v2.32.1-beta milestone Oct 29, 2025
@SwoopX

SwoopX commented Oct 29, 2025

Copy link
Copy Markdown
Collaborator

I fear it needs to go with the legacy code simultaneously. Will prepare the accompanying PR on the weekend at the latest.

@mattreim mattreim changed the title DDF for Eurotronic spirit radiator thermostat (SPZB0001) DDF for Eurotronic Spirit radiator thermostat (SPZB0001) Nov 2, 2025
@manup

manup commented Nov 4, 2025

Copy link
Copy Markdown
Member

@SwoopX thanks so this PR and #8377 are ready to be merged?

Unfortunantely my Eurotronic Spirit gave up years ago so I can't test it.

@SwoopX

SwoopX commented Nov 4, 2025

Copy link
Copy Markdown
Collaborator

@manup yes, should be ready to go. It was tested by @mattreim and another user earlier in strict mode, according to their feedback.

@manup
manup merged commit f1cbf84 into dresden-elektronik:master Nov 5, 2025
1 check passed
@mcormick

mcormick commented Dec 1, 2025

Copy link
Copy Markdown

Just to let you know I had to downgrade to stable last friday after updating to latest on thursday because the house was cold... I think I noticed something with the polling rate, but not entirely sure. TRVs are running firmware 18181120.

@mattreim

mattreim commented Jan 15, 2026

Copy link
Copy Markdown
Collaborator Author

Hi @SwoopX, unfortunately I've now noticed that the device is updating every second. Do you have any idea what could be causing this?

21:52:16:791 ZCL attribute report 0x00158D0007743493 for cluster: 0x0201, ep: 0x01, frame control: 0x1C, mfcode: 0x1037 
21:52:17:792 ZCL attribute report 0x00158D0007743493 for cluster: 0x0201, ep: 0x01, frame control: 0x1C, mfcode: 0x1037 
21:52:18:789 ZCL attribute report 0x00158D0007743493 for cluster: 0x0201, ep: 0x01, frame control: 0x1C, mfcode: 0x1037 
21:52:19:786 ZCL attribute report 0x00158D0007743493 for cluster: 0x0201, ep: 0x01, frame control: 0x1C, mfcode: 0x1037 
21:52:20:783 ZCL attribute report 0x00158D0007743493 for cluster: 0x0201, ep: 0x01, frame control: 0x1C, mfcode: 0x1037

@Smanar

Smanar commented Jan 16, 2026

Copy link
Copy Markdown
Collaborator

All request that use the mfcode have a "refresh.interval" > 1 s.

And it's a report attribute, so something normal, increase bind/report value to test.

Enable APS + aps_l2 you will have more information about the request (attribute for exemple)

@mattreim

Copy link
Copy Markdown
Collaborator Author

Thank you, I need to observe the behavior further and experiment with the values.

@SwoopX

SwoopX commented Jan 18, 2026

Copy link
Copy Markdown
Collaborator

@mattreim might be coincidence that data is coming that close. Or is that happening (way) more often? Anyway, as Smanar suggested, adding APS data should give more insights, as we currently do not see what attribute data is coming in and the respective values.

We've also forgotten to set the reportable change values for the attribute reporting back then, so the reporting is eventually based on legacy code.

@mattreim

mattreim commented Jan 18, 2026

Copy link
Copy Markdown
Collaborator Author

Most messages appear in the first few hours after a restart, and then they become less frequent.

22:29:00:253 APS-DATA.request id: 100, addrmode: 0x03, addr: 0x00158D0007743493, profile: 0x0104, cluster: 0x0201, ep: 0x01 -> 0x01 queue: 1 len: 5 tx.options 0x00
22:29:00:276 APS-DATA.confirm id: 100, status: 0x00 SUCCESS

22:29:02:144 aps request id: 27 prf: 0x0000 cl: 0x0000 timeout (confirmed: 1) to 0x00158D00032816FC (0xFFFD)
22:29:02:224 aps request id: 27 finished, erase from queue

22:29:08:253 APS-DATA.request id: 165, addrmode: 0x03, addr: 0x00158D0007743493, profile: 0x0104, cluster: 0x0201, ep: 0x01 -> 0x01 queue: 1 len: 5 tx.options 0x00
22:29:08:254 	asdu (length: 5): 1036000800

@Smanar

Smanar commented Jan 19, 2026

Copy link
Copy Markdown
Collaborator

APS-DATA.request

Mean it's deconz that make request to the device, so not good if it' something happening every seconds

asdu (length: 5): 1036 00 0800

It's a read attribute on attribute 0x0008

        {
          "name": "state/valve",
          "refresh.interval": 660,
          "parse": {
            "at": "0x0008",

The report is set to 1/600/1.

The device is not set as "sleeper", so if deconz haven't an anwser after 600s it start to spam the device to have the value, it need an answer or an error message.

@mattreim

Copy link
Copy Markdown
Collaborator Author

I hope this PR will fix it, but I will continue to monitor it.

@mattreim

Copy link
Copy Markdown
Collaborator Author

With the recent changes to the DDF and after several restarts, the number of messages has decreased significantly. Therefore, I think my problem is resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants