Skip to content

✏️ Fix duplicate endpoints in Z2M state names#156

Draft
andrei-lazarov wants to merge 2 commits intoromasku:mainfrom
andrei-lazarov:z2m/fix_state_names
Draft

✏️ Fix duplicate endpoints in Z2M state names#156
andrei-lazarov wants to merge 2 commits intoromasku:mainfrom
andrei-lazarov:z2m/fix_state_names

Conversation

@andrei-lazarov
Copy link
Copy Markdown
Collaborator

@ashb pointed out that the states look ugly in HA (or in Z2M ➡ Device ➡ State).
Notice how switch_left is duplicated:

 "switch_left_press_action_switch_left": "released",

I would prefer it at the front so the states would be grouped by switch if sorted alphabetically. It should be:

 "switch_left_press_action": "released",

But it looks like Z2M automatically appends the endpoint in exposes.ts (I guess?):

this.property = `${this.property}_${this.endpoint}`;
...
feature.property = `${feature.property}_${endpointName}`;

So this is the best I can do:

 "press_action_switch_left": "released",

I edited the converters template for the new format.

Unfortunately, after updating the converters, Z2M still shows the old (now unresponsive) states, along with the new ones.

Screenshot From 2025-09-21 16-27-49

You can get rid of the old entries by removing them from the state history (zigbee2mqtt/state.json), or by deleting the file altogether and letting Z2M rebuild it.
I don't know if Z2M ever clears history organically.

@romasku
Copy link
Copy Markdown
Owner

romasku commented Sep 24, 2025

I like this change, thank you! However, I think it could be a breaking change, since I’m not sure HA entities will migrate to the new names. I’m almost certain automations will break, and possibly even just exposing the entity on the dashboard. Could you please check this, and if that’s the case, can you please add the corresponding changelog entry?

@andrei-lazarov
Copy link
Copy Markdown
Collaborator Author

andrei-lazarov commented Sep 24, 2025

Right... not sure how to do it though. This is only a converter update so not related to the firmware changelog.
I guess we should wait for now, and release this change at the same time with the next firmware version. So we could bundle it with the release notes.

@andrei-lazarov
Copy link
Copy Markdown
Collaborator Author

andrei-lazarov commented Sep 24, 2025

Changed my mind: Let's have dedicated release notes for the converters.
I suspect we will do more breaking changes in the future, so it's better to document all of this.
I created the new changelog and added a version number for the converters (and the branch it came from, for good measure).

converters_version

Also tested and indeed automations break.

@ashb
Copy link
Copy Markdown

ashb commented Sep 25, 2025

If you want, it might be possible to define a new class

https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/src/lib/exposes.ts#L115 that overrides the withEndpoint function to be different.

Totally untested, but something like this might work:

class CustomSwitch extends exposes.Switch {
    withEndpoint(endpointName: string) {
        super.withEndpoint(endopintName);
        if (this.property) {
            this.property = `${this.endpoint}_${this.property}`;
        }
    }
}

buuuuut wiring that up might not be straight forward.

Chasing it down further. I think it's the calls to romasku.switchAction we need to change, which calls in to https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/src/lib/modernExtend.ts#L2496-L2503

We might be able to do something like this:

    switchAction: (name, endpointName) => {
        let e = enumLookup({
            name,
            endpointName,
            lookup: { on_off: 0, off_on: 1, toggle_simple: 2, toggle_smart_sync: 3, toggle_smart_opposite: 4 },
            cluster: "genOnOffSwitchCfg",
            attribute: "switchActions", // Enum8
            description: `Select how switch should work:
            - on_off: When switch physically moved to position 1 it always generates ON command, and when moved to position 2 it generates OFF command
            - off_on: Same as on_off, but positions are swapped
            - toggle_simple: Any press of physical switch will TOGGLE the relay and send TOGGLE command to binds
            - toggle_smart_sync: Any press of physical switch will TOGGLE the relay and send corresponding ON/OFF command to keep binds in sync with relay
            - toggle_smart_opposite: Any press of physical switch: TOGGLE the relay and send corresponding ON/OFF command to keep binds in the state opposite to the relay`,
        });

        e.exposes[0].withProperty(`something_custom_${endpointName}`);
        return e
    },

(And I've reached what I can reasonably to from just reading the code. I have no access to the z2m or zigbee network right now to try further)

@andrei-lazarov andrei-lazarov marked this pull request as draft September 27, 2025 00:12
@ashb
Copy link
Copy Markdown

ashb commented Feb 5, 2026

I came back to my idea, and I didn't do exactly like I said, but I noticed that some of the "stock" Zigbee converters use nesting (levelConfig in the C-ZB-RD1 device as inspiration), so I implemented that:

Screenshot 2026-02-05 at 10 37 56

(Currently Only the switch settings are nested, the switch state isn't, and neither are relay state nor the relay power on behaviour.

However the main draw back to this approach is what it does to the HA display. It's now even worse 🤮 :

Screenshot 2026-02-05 at 10 42 32

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.

3 participants