Skip to content

Conversation

@romasku
Copy link
Owner

@romasku romasku commented Aug 18, 2025

This PR introduces a single converter that uses the current device configuration as a source to generate expose definitions.
I also dropped support for Z2M v1, since v2 was released almost nine months ago, and maintaining a generic converter for the older version is difficult.

Also, I've renamed some device properties to make them more consistent, so we should write about this breaking change in the release notes. And now properties are ordered in a more meaningful way, so I hope the config page is at least a bit more manageable:

image

@clumsy-stefan
Copy link
Contributor

On one hand I think that's a really cool idea and I like the technical idea behind. On the other hand I believe that's again a brilliant idea from a technical and academic POV but not really useful from an operational/practical view.

The same points from me as in the levelCtrl discussion. You're trying to do a "catch-all" solution instead of simplifying the needed converters to a minimum. I fear that it's not really scalable in a bigger and "normal" environment where you have potentially dozens of switches where the converter needs to run. If I understand the code correctly it will try to "generate" a z2m converter for each device, even when they are exactly the same (at least it needs to run once, when it reads the config-string) and won't store it persistently, meaning it's run every time you start z2m for all devices?

Also there are practical implications, like if I want to change certain things locally (reporting timings, disable certain configs, or change other defaults from in the converter), I can't do that (easily) anymore, as it would get overridden by the defaults.

It's again kind of the view from the opposite side. Instead of having a handful easy converters that are usable and understandable that catches 90% of the cases in a big operational environment, we'll try the academic approach to cover 100% of all cases but makes it quite difficult for a "normal" IT-User/Operator in a production environment.

So basically what I'm saying is, that you're just too clever and a too good programmer for a "standard" production environment ;)

That's all MHO and not meant to offend anyone, just my thinking...

@romasku
Copy link
Owner Author

romasku commented Aug 19, 2025

My main goal here was to ensure that any configuration changes are automatically reflected in the exposes tab, since this is required for a single binary. Single binary means we need some dynamic parsing; otherwise, the user would have to manually select the "correct" model just to see the correct exposes, which feels worse to me. Also, I wouldn’t say I did anything too clever -- dynamic exposes already exist in z2m-converters, and the toZigbee/fromZigbee parts follow the standard Z2M approach.

If I understand the code correctly, it will try to "generate" a z2m converter for each device.

That’s a limitation of Z2M converters: the model field, used to display "image" can only be defined statically, so I have to generate separate converters for these images. But copying a JS object isn’t that slow, and Z2M itself loads far more converters by default, so I’d be surprised if this caused performance issues during startup.

That said, I understand your point about quick “hacks” advanced users may want to try. It would definitely be better if they could do so without spending hours figuring out how the code works. I’ll work on making it more readable.

@clumsy-stefan
Copy link
Contributor

Single binary means we need some dynamic parsing; otherwise, the user would have to manually select the "correct" model just to see the correct exposes, which feels worse to me.

Understood and agreed. That's why my idea was kind of 4 different model-configs (1-2-3-4 Gang switch) with the relevant converters, as I thought this catches 90% of all the devices. And obviously cover this in the config(string).

@romasku
Copy link
Owner Author

romasku commented Aug 19, 2025

That's why my idea was kind of 4 different model-configs (1-2-3-4 Gang switch) ...

If only it were that simple… :) Some switches have an indicator LED for each relay, others just a single LED, and the relay modules don’t have any indicator LEDs at all. There are also devices with or without a network LED. And in the future, we may support even more optional features (for example, power-monitoring relay modules could be the next step).

So, having a separate converter for every possible set of supported features would also lead to a huge list.

@clumsy-stefan
Copy link
Contributor

yeah, true also... so I guess the automatic generation is the better way.. Looking forward to test it...

@andrei-lazarov
Copy link
Contributor

Hi guys, sorry I didn't get to try the new features yet.
I'm writing the documentation page about updating and I need to know:

Are the new converters (old_style+levelCtrl / new_style) still backwards compatible?
I'm assuming they were until now.

So if you have a switch on v18 and another switch on the upcoming v19:
Does the device on old fw work with the latest converters (apart from levelCtrl)?

@clumsy-stefan
Copy link
Contributor

clumsy-stefan commented Aug 20, 2025

as far as I could tell yes, but I already upgraded all to the upcoming FW... so I'm not 100% sure..

EDIT: actually I'm coming from my own "unified" binary back to the standard main branch, so my tests are not really meaningfull... It worked between my old and the new FW though..

@romasku
Copy link
Owner Author

romasku commented Aug 20, 2025

Yes, the converter works with both old and new firmware versions.

@andrei-lazarov
Copy link
Contributor

andrei-lazarov commented Aug 22, 2025

I tried the converters a bit and they did not work on Z2M 2.5.1. Updating my instance to 2.6.0 fixed it.

Z2M 2.5.1 Log:

[2025-08-22 02:39:23] error: 	z2m: Invalid external converter 'romasku_switch_custom.mjs' was ignored and renamed to prevent interference with Zigbee2MQTT.
[2025-08-22 02:39:23] debug: 	z2m: file:///home/andy/Work/HomeAssistant/zigbee%20fw/zigbee2mqtt/data/external_converters/.tmp-ed42d4f2-romasku_switch_custom-23304e38-54ff-4d3f-873f-f0d5e99bb9b7.mjs:4
  isDummyDevice,
  ^^^^^^^^^^^^^
SyntaxError: Named export 'isDummyDevice' not found. The requested module 'zigbee-herdsman-converters/lib/utils' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'zigbee-herdsman-converters/lib/utils';

Also please fix the indentation in the Exposes tab - All options are still indented under Linkquality.
I would indent all options of relay N under Relay N State and all options of switch N under Switch N action.
But this would make the relay toggles very far apart so I'm not sure if you like the idea.

We can also add an Apply config string button. Or a button to show/hide advanced options would also work.
I'm not sure how much formatting Z2M allows, but I can try it myself if you want.

@ashb
Copy link

ashb commented Sep 25, 2025

If the only problem with z2m 2.5 is the isDummyDevice fn, it's appears to be an easy thing to pollyfil, as this is all the fn is

export function isDummyDevice(obj: Zh.Device | DummyDevice): obj is DummyDevice {
    return "isDummyDevice" in obj;
}

@romasku romasku force-pushed the rs/generic-converter branch from 12c6cd4 to 0e6e3de Compare November 15, 2025 16:03
@romasku romasku force-pushed the rs/generic-converter branch from 5b37c4b to d67e57c Compare November 15, 2025 20:16
@romasku
Copy link
Owner Author

romasku commented Nov 15, 2025

Hi @andrei-lazarov,

I've revived this PR and tried to apply your suggestions, but unfortunately, Z2M’s UI is very limited, or, more precisely, we don’t have any real control over it. We can only define a list of entities (properties) to expose. There is support for “composite” entities that allow grouping, but using them automatically adds an “Apply” button for the whole group; i.e., you can only update all properties together and only by pressing this button. To me, this looks rather ugly for a switch/relay.

However, I was able to:

  • Add a fix for Z2M 2.5.x (less important now, but still good to have).
  • Add an Apply button for config by using a composite. It now requires an additional click, which makes it easier to work with.

Also, the new WindFront UI dropped grouping under Linkquality; it looks better now.

Please check.

This is the apply button:
image

And here is the whole page:
localhost_8080_

@Nerivec
Copy link

Nerivec commented Nov 16, 2025

@romasku some lesser used "device configurations" could quite possibly use some love. There are so many feature combinations, it's pretty hard to test everything (at least in a reasonable amount of time 😅).
The exposes section is generated from the list of device exposes sent by Z2M. There are hundreds of variations though... have to find the right one for this I suppose 😉
We can easily add a test mock so we can have it in the dev UI though, just need the downloaded state.json portions of a device.
Feel free to create issues/PRs if you find anything worth refactoring: https://github.com/Nerivec/zigbee2mqtt-windfront

PS: You can also quickly test displays using the storybook (just change the data in the bottom Control panel). E.g. https://nerivec.github.io/zigbee2mqtt-windfront/?path=/story/components-features-list--composite

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants