Skip to content

Comments

Add MQTT support#2

Draft
wbyoung wants to merge 1 commit intomainfrom
zigbee2mqtt
Draft

Add MQTT support#2
wbyoung wants to merge 1 commit intomainfrom
zigbee2mqtt

Conversation

@wbyoung
Copy link
Owner

@wbyoung wbyoung commented Jul 17, 2025

There's still some work to do on this:

  • Determine if it's possible to get more parameter values (see below).
  • Better understand device names and identifiers in Z2M (see below).
  • Ensure the list of entities is properly filtering to just Inovelli switches in the config entry.
  • Verify that updating for a solid notification works.
  • Verify that updating for single LEDs works.
  • Ensure that double press on the config button ends up dismissing the notification (that the event handler is working properly).

Device Names and Identifiers

I got some great explanations on naming, topics, and identifiers.

Before this, in c2e9c1f, switches could be looked up by MQTT device ID or name (in case that's ever a useful idea to apply again).

Original problem description:

The examples I had to work off of used device.name as well as pulling details out of Home Assistant's DeviceInfo.identifiers.

From the docs as well as the source code, it appears that naming of MQTT entities can be configured. I'm not sure if there's a concept of a canonical name or ID. In particular, when receiving events, I'm not sure what the value in the topic will be which is important to map to the particular switch being acted upon. The solution I came up with for now is to simply add both the name and the device ID in to a mapping so that either one can be used to try to determine the proper switch.

It'd be nice to better understand this and know whether one or the other is the one that's used. Or perhaps they're actually the same value. Regardless, the code may be overly complicated & able to be simplified if only one type of ID is used when actions are received.

Obtaining Parameter Values

In c2e9c1f, I used the same strategy of locating related entities from the device. It turns out, though, that the 2x tap to dismiss notifications entity is disabled by default in the entity registry. The approach being implemented now is to request an update from MQTT when switches are added and process state updates for them.

Original problem description:

We need to determine if it's possible to get the state of various parameters.

ZHA stores these values in sensors (with well known translation keys and unique IDs ending in -disable_clear_notifications_double_tap and -local_protection) so it doesn't incur extra network overhead to get the values. I know we could get them with Z2M via a get. That would cause some problems if such a request incurs a round-trip to the switch. But if MQTT caches it, it may be okay. Ideally, Z2M would create a sensor for it like ZHA does, but I'm not familiar enough with the setup to know if that occurs.

Why it matters: obviously, without the 2x tap to dismiss enabled, the switch doesn't disable the notification. We shouldn't clear it in this case—it should just be left alone. However, with local protection enabled, the switch will send the 2x tap message, but it doesn't disable the notification in this case either. In this case, we should send a message to clear it.

Prior Art & Documentation Resources

The following were suggested as reference points for implementation:

Notes

ZHA has some events that it can receive from the switches, namely 0x24 which is for led_effect_complete. When this PR was first openened, that wasn't present in the Z2M docs nor the herdsman converters, but @rohankapoorcom added support for this in Koenkk/zigbee-herdsman-converters#9735.

@wbyoung wbyoung force-pushed the zigbee2mqtt branch 3 times, most recently from bddfb48 to 7171b26 Compare July 17, 2025 19:14
@wbyoung wbyoung force-pushed the zigbee2mqtt branch 7 times, most recently from 2a2f3af to 3f9bd9f Compare July 18, 2025 15:25
@wbyoung wbyoung force-pushed the zigbee2mqtt branch 5 times, most recently from 533bd75 to 41c3994 Compare July 18, 2025 23:10
@wbyoung
Copy link
Owner Author

wbyoung commented Jul 18, 2025

@rohankapoorcom @jncasey this is as far as I can take this without being able to test it against a system that's using Zigbee2MQTT.

If/when either of you have time to review it and/or take it to the point of being usable, I think it would be much appreciated by anyone using Zigbee2MQTT. 🥂

@wbyoung wbyoung force-pushed the zigbee2mqtt branch 5 times, most recently from bd4f127 to a0cc274 Compare July 22, 2025 17:57
@wbyoung wbyoung force-pushed the zigbee2mqtt branch 3 times, most recently from 0ce1d5c to 2a81862 Compare July 23, 2025 22:04
This is currently untested.
@github-actions
Copy link

github-actions bot commented Dec 4, 2025

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
If you are the author of this PR, please leave a comment if you want to keep it open. Also, please rebase your PR onto the latest dev branch to ensure that it's up to date with the latest changes.
Thank you for your contribution!

@github-actions github-actions bot added the stale label Dec 4, 2025
@wbyoung wbyoung removed the stale label Dec 4, 2025
@github-actions
Copy link

github-actions bot commented Jan 4, 2026

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
If you are the author of this PR, please leave a comment if you want to keep it open. Also, please rebase your PR onto the latest dev branch to ensure that it's up to date with the latest changes.
Thank you for your contribution!

@github-actions github-actions bot added the stale label Jan 4, 2026
@wbyoung wbyoung removed the stale label Jan 4, 2026
@github-actions
Copy link

github-actions bot commented Feb 4, 2026

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
If you are the author of this PR, please leave a comment if you want to keep it open. Also, please rebase your PR onto the latest dev branch to ensure that it's up to date with the latest changes.
Thank you for your contribution!

@github-actions github-actions bot added the stale label Feb 4, 2026
@wbyoung wbyoung removed the stale label Feb 4, 2026
@MrDaGree
Copy link

Quick testing, getting the following error in MQTT for a mmwave blue switch.

[2026-02-10 21:15:13] error: 	z2m: Publish 'set' 'led_effect' to 'Office Switch' failed: 'Error: ZCL command 0x0c2a6ffffeaa0fcf/1 manuSpecificInovelli.ledEffect({"color":null,"level":null,"duration":null}, {"timeout":10000,"disableResponse":true,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"reservedBits":0,"manufacturerCode":4655,"writeUndiv":false}) failed (Parameter 'effect' is missing)'

There were a few issues I noticed right away:

  1. The params dict builds with the keys having leds_ prefixed to the action, which when reading the docs doesnt appear correct.
  2. Comparing against a popular Home Assistant blueprint that does work, I was able to verify that the effects need to be a string type (also like on the docs).

Quick POC that worked for me, happy to make another PR to the z2m branch for it, is below:


# types.py
class Effect(IntEnum):
    _ignore_ = ("_Z2M_BY_EFFECT",)

    OFF = 0
    SOLID = 1
    FAST_BLINK = 2
    SLOW_BLINK = 3
    PULSE = 4
    CHASE = 5
    OPEN_CLOSE = 6
    SMALL_TO_BIG = 7
    AURORA = 8
    SLOW_FALLING = 9
    MEDIUM_FALLING = 10
    FAST_FALLING = 11
    SLOW_RISING = 12
    MEDIUM_RISING = 13
    FAST_RISING = 14
    MEDIUM_BLINK = 15
    SLOW_CHASE = 16
    FAST_CHASE = 17
    FAST_SIREN = 18
    SLOW_SIREN = 19
    CLEAR = 255

    _Z2M_BY_EFFECT: ClassVar[dict["Effect", str]]

    @property
    def zha(self) -> int:
        return int(self)

    @property
    def z2m(self) -> str:
        return type(self)._Z2M_BY_EFFECT[self]


Effect._Z2M_BY_EFFECT = {
    Effect.OFF: "off",
    Effect.SOLID: "solid",
    Effect.FAST_BLINK: "fast_blink",
    Effect.SLOW_BLINK: "slow_blink",
    Effect.PULSE: "pulse",
    Effect.CHASE: "chase",
    Effect.OPEN_CLOSE: "open_close",
    Effect.SMALL_TO_BIG: "small_to_big",
    Effect.AURORA: "aurora",
    Effect.SLOW_FALLING: "slow_falling",
    Effect.MEDIUM_FALLING: "medium_falling",
    Effect.FAST_FALLING: "fast_falling",
    Effect.SLOW_RISING: "slow_rising",
    Effect.MEDIUM_RISING: "medium_rising",
    Effect.FAST_RISING: "fast_rising",
    Effect.MEDIUM_BLINK: "medium_blink",
    Effect.SLOW_CHASE: "slow_chase",
    Effect.FAST_CHASE: "fast_chase",
    Effect.FAST_SIREN: "fast_siren",
    Effect.SLOW_SIREN: "slow_siren",
    Effect.CLEAR: "clear_effect",
}
# orchestration.py

    def _switch_command_led_params(self, led: LEDConfig, switch_id: SwitchId) -> dict[str, Any]:
        firmware_duration = (
            self._firmware_duration(led.duration)
            if self._any_has_expiration_messaging([switch_id])
            else None
        )
        duration = (
            255
            if led.duration is None
            or led.duration == ALREADY_EXPIRED
            or firmware_duration is None
            else firmware_duration
        )

        switch_info = self.switch_info(switch_id)
        is_z2m = switch_info.integration == Integration.Z2M

        base = {
            ("color" if is_z2m else "led_color"): int(led.color),
            ("effect" if is_z2m else "led_effect"): (led.effect.z2m if is_z2m else led.effect.zha),
            ("level" if is_z2m else "led_level"): int(led.brightness),
        }

        return base | {("duration" if is_z2m else "led_duration"): duration}

@wbyoung
Copy link
Owner Author

wbyoung commented Feb 11, 2026

Wow, thanks for getting and the great info.

If you're up for putting in the work to open a PR against my branch, that would be most welcome!

There's good test coverage in there, so if you get it working with tests covering the changes, we should be able to refactor/change things as needed to fit with how this will work for Z-Wave and Matter which I've already started on as well.

If you're just up for testing, I'd welcome that as well. Let me know what your interest/availability is.

@MrDaGree
Copy link

I have some time tonight and this weekend where I can get it refactored into a PR and updating tests!

@wbyoung
Copy link
Owner Author

wbyoung commented Feb 11, 2026

@MrDaGree wonderful! Let me know if I can answer any questions. I'm really helpful excited to get this merge and allow more people to use it.

@MrDaGree
Copy link

@wbyoung - Im running into a weird issue I've noticed with the _handle_z2m_message function, specifically with the section below.

        if (
            (notification_complete := payload.get("notificationComplete"))
            and (command := f"led_effect_complete_{notification_complete}")
            and command in DISMISSAL_COMMANDS
        ):
            await self._handle_generic_event(
                command=command,
                switch_id=switch_id,
                integration=Integration.Z2M,
            )

Once notificationComplete is set in the payload, it never clears/changes, so after toggling on a notification in HA it immediate turns off the toggle in HA as _all_clear is True. With ZHA, is the value of the complete notification constant?

notificationComplete will change between ALL_LEDS and a different value when double clicking the config button, but other than that it never changes.

2026-02-12 19:32:10.817 DEBUG (MainThread) [custom_components.lampie.orchestrator] start time recorded (test=2026-02-12 19:32:10.817571-06:00)
2026-02-12 19:32:10.817 DEBUG (MainThread) [custom_components.lampie.orchestrator] notification updated (test=on)
2026-02-12 19:32:10.818 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:test:on)
2026-02-12 19:32:10.819 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:10.876 WARNING (MainThread) [custom_components.lampie.orchestrator] {'0': 29, '1': 47, '10': 205, '11': 255, '12': 0, '13': 0, '14': 1, '2': 18, '3': 126, '4': 1, '5': 1, '6': 136, '7': 0, '8': 171, '9': 0, 'activeEnergyReports': 10, 'activePowerReports': 10, 'autoTimerOff': 0, 'auxSwitchUniqueScenes': 'Disabled', 'bindingOffToOnSyncLevel': 'Disabled', 'brightness': 70, 'brightnessLevelForDoubleTapDown': 2, 'brightnessLevelForDoubleTapUp': 254, 'buttonDelay': '500ms', 'current': 0, 'defaultLed1ColorWhenOff': 255, 'defaultLed1ColorWhenOn': 255, 'defaultLed1IntensityWhenOff': 101, 'defaultLed1IntensityWhenOn': 101, 'defaultLed2ColorWhenOff': 255, 'defaultLed2ColorWhenOn': 255, 'defaultLed2IntensityWhenOff': 101, 'defaultLed2IntensityWhenOn': 101, 'defaultLed3ColorWhenOff': 255, 'defaultLed3ColorWhenOn': 255, 'defaultLed3IntensityWhenOff': 101, 'defaultLed3IntensityWhenOn': 101, 'defaultLed4ColorWhenOff': 255, 'defaultLed4ColorWhenOn': 255, 'defaultLed4IntensityWhenOff': 101, 'defaultLed4IntensityWhenOn': 101, 'defaultLed5ColorWhenOff': 255, 'defaultLed5ColorWhenOn': 255, 'defaultLed5IntensityWhenOff': 101, 'defaultLed5IntensityWhenOn': 101, 'defaultLed6ColorWhenOff': 255, 'defaultLed6ColorWhenOn': 255, 'defaultLed6IntensityWhenOff': 101, 'defaultLed6IntensityWhenOn': 101, 'defaultLed7ColorWhenOff': 255, 'defaultLed7ColorWhenOn': 255, 'defaultLed7IntensityWhenOff': 101, 'defaultLed7IntensityWhenOn': 101, 'defaultLevelLocal': 101.6, 'defaultLevelRemote': 101.6, 'deviceBindNumber': 0, 'dimmingMode': 'Leading edge', 'dimmingSpeedDownLocal': 127, 'dimmingSpeedDownRemote': 127, 'dimmingSpeedUpLocal': 127, 'dimmingSpeedUpRemote': 15, 'doubleTapClearNotifications': 'Enabled (Default)', 'doubleTapDownToParam56': 'Disabled', 'doubleTapUpToParam55': 'Disabled', 'energy': 0.03, 'energy_reset': None, 'fanControlMode': 'Disabled', 'fanLedLevelType': 0, 'fanTimerMode': 'Disabled', 'firmwareUpdateInProgressIndicator': 'Enabled', 'highLevelForFanControlMode': 254, 'higherOutputInNonNeutral': 'Disabled (default)', 'identify': None, 'illuminance': 1, 'individual_led_effect': None, 'internalTemperature': 49, 'invertSwitch': 'No', 'ledBarScaling': 'Gen3 method (VZM-style)', 'ledColorForFanControlMode': 255, 'ledColorWhenOff': 170, 'ledColorWhenOn': 170, 'ledIntensityWhenOff': 1, 'ledIntensityWhenOn': 33, 'led_effect': {'color': 0, 'duration': 30, 'effect': 'open_close', 'level': 100}, 'linkquality': 140, 'loadLevelIndicatorTimeout': 'Stay On', 'localProtection': 'Disabled', 'lowLevelForFanControlMode': 63, 'maximumLevel': 255, 'mediumLevelForFanControlMode': 128, 'minimumLevel': 1, 'mmWaveDepthMax': 200, 'mmWaveDepthMin': 0, 'mmWaveDetectSensitivity': 'High (default)', 'mmWaveDetectTrigger': 'Fast (0.2s, default)', 'mmWaveHeightMax': 75, 'mmWaveHeightMin': -75, 'mmWaveHoldTime': 30, 'mmWaveRoomSizePreset': 'Small', 'mmWaveStayLife': 300, 'mmWaveTargetInfoReport': 'Disable (default)', 'mmWaveVersion': 100863491, 'mmWaveWidthMax': 100, 'mmWaveWidthMin': -100, 'mmwaveControlWiredDevice': 'Disabled', 'mmwave_area1_occupancy': True, 'mmwave_area2_occupancy': False, 'mmwave_area3_occupancy': False, 'mmwave_area4_occupancy': False, 'mmwave_control_commands': {'controlID': 'query_areas'}, 'mmwave_detection_areas': {'area1': {'depth_max': 200, 'depth_min': 0, 'height_max': 75, 'height_min': -75, 'width_max': 100, 'width_min': -100}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'mmwave_interference_areas': {'area1': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'mmwave_stay_areas': {'area1': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'notificationComplete': 'ALL_LEDS', 'occupancy': True, 'onOffLedMode': 'All', 'otaImageType': 'Zigbee (259)', 'outputMode': 'Dimmer', 'overheat': 'No Alert', 'periodicPowerAndEnergyReports': 3600, 'power': 1.2, 'powerType': 'Neutral', 'quickStartLevel': 254, 'quickStartTime': 0, 'rampRateOffToOnLocal': 127, 'rampRateOffToOnRemote': 127, 'rampRateOnToOffLocal': 127, 'rampRateOnToOffRemote': 127, 'remoteProtection': 'Disabled', 'singleTapBehavior': 'Old Behavior', 'smartBulbMode': 'Disabled', 'state': 'ON', 'stateAfterPowerRestored': 255, 'switchType': 'Aux Switch', 'update': {'installed_version': 16974080, 'latest_release_notes': None, 'latest_source': 'https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/images/Inovelli/VZM32-SN_0.10.ota', 'latest_version': 16973834, 'state': 'idle'}, 'voltage': 81.8}
2026-02-12 19:32:10.876 WARNING (MainThread) [custom_components.lampie.orchestrator] handling event led_effect_complete_ALL_LEDS for Z2M on light.office_switch
2026-02-12 19:32:10.876 WARNING (MainThread) [custom_components.lampie.orchestrator] from state: LampieSwitchInfo(led_config=(LEDConfig(color=<Color.RED: 0>, effect=<Effect.OPEN_CLOSE: 6>, brightness=100.0, duration=30.0),), led_config_source=LEDConfigSource(value='test', type=<LEDConfigSourceType.NOTIFICATION: 'notification'>), integration_info=Z2MSwitchInfo(full_topic='zigbee2mqtt/Office Switch', local_protection_enabled=False, double_tap_clear_notifications_disabled=False), integration=<Integration.Z2M: 'z2m'>, priorities=('test',), expiration=ExpirationInfo(started_at=None, expires_at=None, cancel_listener=None)),
led_confg_src: notification:test,
led_config: [LEDConfig(color=<Color.RED: 0>, effect=<Effect.OPEN_CLOSE: 6>, brightness=100.0, duration=30.0)],
all_clear: False,
first_on: <custom_components.lampie.coordinator.LampieUpdateCoordinator object at 0x7f91a4b12660>,
2026-02-12 19:32:10.876 DEBUG (MainThread) [custom_components.lampie.orchestrator] processing Z2M event led_effect_complete_ALL_LEDS on light.office_switch
2026-02-12 19:32:10.876 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:test:off)
2026-02-12 19:32:10.876 WARNING (MainThread) [custom_components.lampie.orchestrator] switch light.office_switch cleared a notification from the firmware; attempting to dismiss the notification; command=led_effect_complete_ALL_LEDS, led_config_source=notification:test, active_notification=test
2026-02-12 19:32:10.876 DEBUG (MainThread) [custom_components.lampie.orchestrator] start time cleared (test)
2026-02-12 19:32:10.877 DEBUG (MainThread) [custom_components.lampie.orchestrator] notification updated (test=off)
2026-02-12 19:32:10.877 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:off)
2026-02-12 19:32:10.877 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:10.877 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:20.125 DEBUG (MainThread) [custom_components.lampie.orchestrator] start time recorded (test=2026-02-12 19:32:20.125759-06:00)
2026-02-12 19:32:20.126 DEBUG (MainThread) [custom_components.lampie.orchestrator] notification updated (test=on)
2026-02-12 19:32:20.126 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:test:on)
2026-02-12 19:32:20.127 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:20.216 WARNING (MainThread) [custom_components.lampie.orchestrator] {'0': 29, '1': 47, '10': 205, '11': 255, '12': 0, '13': 0, '14': 1, '2': 18, '3': 126, '4': 1, '5': 1, '6': 136, '7': 0, '8': 171, '9': 0, 'activeEnergyReports': 10, 'activePowerReports': 10, 'autoTimerOff': 0, 'auxSwitchUniqueScenes': 'Disabled', 'bindingOffToOnSyncLevel': 'Disabled', 'brightness': 70, 'brightnessLevelForDoubleTapDown': 2, 'brightnessLevelForDoubleTapUp': 254, 'buttonDelay': '500ms', 'current': 0, 'defaultLed1ColorWhenOff': 255, 'defaultLed1ColorWhenOn': 255, 'defaultLed1IntensityWhenOff': 101, 'defaultLed1IntensityWhenOn': 101, 'defaultLed2ColorWhenOff': 255, 'defaultLed2ColorWhenOn': 255, 'defaultLed2IntensityWhenOff': 101, 'defaultLed2IntensityWhenOn': 101, 'defaultLed3ColorWhenOff': 255, 'defaultLed3ColorWhenOn': 255, 'defaultLed3IntensityWhenOff': 101, 'defaultLed3IntensityWhenOn': 101, 'defaultLed4ColorWhenOff': 255, 'defaultLed4ColorWhenOn': 255, 'defaultLed4IntensityWhenOff': 101, 'defaultLed4IntensityWhenOn': 101, 'defaultLed5ColorWhenOff': 255, 'defaultLed5ColorWhenOn': 255, 'defaultLed5IntensityWhenOff': 101, 'defaultLed5IntensityWhenOn': 101, 'defaultLed6ColorWhenOff': 255, 'defaultLed6ColorWhenOn': 255, 'defaultLed6IntensityWhenOff': 101, 'defaultLed6IntensityWhenOn': 101, 'defaultLed7ColorWhenOff': 255, 'defaultLed7ColorWhenOn': 255, 'defaultLed7IntensityWhenOff': 101, 'defaultLed7IntensityWhenOn': 101, 'defaultLevelLocal': 101.6, 'defaultLevelRemote': 101.6, 'deviceBindNumber': 0, 'dimmingMode': 'Leading edge', 'dimmingSpeedDownLocal': 127, 'dimmingSpeedDownRemote': 127, 'dimmingSpeedUpLocal': 127, 'dimmingSpeedUpRemote': 15, 'doubleTapClearNotifications': 'Enabled (Default)', 'doubleTapDownToParam56': 'Disabled', 'doubleTapUpToParam55': 'Disabled', 'energy': 0.03, 'energy_reset': None, 'fanControlMode': 'Disabled', 'fanLedLevelType': 0, 'fanTimerMode': 'Disabled', 'firmwareUpdateInProgressIndicator': 'Enabled', 'highLevelForFanControlMode': 254, 'higherOutputInNonNeutral': 'Disabled (default)', 'identify': None, 'illuminance': 1, 'individual_led_effect': None, 'internalTemperature': 49, 'invertSwitch': 'No', 'ledBarScaling': 'Gen3 method (VZM-style)', 'ledColorForFanControlMode': 255, 'ledColorWhenOff': 170, 'ledColorWhenOn': 170, 'ledIntensityWhenOff': 1, 'ledIntensityWhenOn': 33, 'led_effect': {'color': 0, 'duration': 30, 'effect': 'open_close', 'level': 100}, 'linkquality': 140, 'loadLevelIndicatorTimeout': 'Stay On', 'localProtection': 'Disabled', 'lowLevelForFanControlMode': 63, 'maximumLevel': 255, 'mediumLevelForFanControlMode': 128, 'minimumLevel': 1, 'mmWaveDepthMax': 200, 'mmWaveDepthMin': 0, 'mmWaveDetectSensitivity': 'High (default)', 'mmWaveDetectTrigger': 'Fast (0.2s, default)', 'mmWaveHeightMax': 75, 'mmWaveHeightMin': -75, 'mmWaveHoldTime': 30, 'mmWaveRoomSizePreset': 'Small', 'mmWaveStayLife': 300, 'mmWaveTargetInfoReport': 'Disable (default)', 'mmWaveVersion': 100863491, 'mmWaveWidthMax': 100, 'mmWaveWidthMin': -100, 'mmwaveControlWiredDevice': 'Disabled', 'mmwave_area1_occupancy': True, 'mmwave_area2_occupancy': False, 'mmwave_area3_occupancy': False, 'mmwave_area4_occupancy': False, 'mmwave_control_commands': {'controlID': 'query_areas'}, 'mmwave_detection_areas': {'area1': {'depth_max': 200, 'depth_min': 0, 'height_max': 75, 'height_min': -75, 'width_max': 100, 'width_min': -100}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'mmwave_interference_areas': {'area1': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'mmwave_stay_areas': {'area1': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'notificationComplete': 'ALL_LEDS', 'occupancy': True, 'onOffLedMode': 'All', 'otaImageType': 'Zigbee (259)', 'outputMode': 'Dimmer', 'overheat': 'No Alert', 'periodicPowerAndEnergyReports': 3600, 'power': 1.2, 'powerType': 'Neutral', 'quickStartLevel': 254, 'quickStartTime': 0, 'rampRateOffToOnLocal': 127, 'rampRateOffToOnRemote': 127, 'rampRateOnToOffLocal': 127, 'rampRateOnToOffRemote': 127, 'remoteProtection': 'Disabled', 'singleTapBehavior': 'Old Behavior', 'smartBulbMode': 'Disabled', 'state': 'ON', 'stateAfterPowerRestored': 255, 'switchType': 'Aux Switch', 'update': {'installed_version': 16974080, 'latest_release_notes': None, 'latest_source': 'https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/images/Inovelli/VZM32-SN_0.10.ota', 'latest_version': 16973834, 'state': 'idle'}, 'voltage': 81.8}
2026-02-12 19:32:20.217 WARNING (MainThread) [custom_components.lampie.orchestrator] handling event led_effect_complete_ALL_LEDS for Z2M on light.office_switch
2026-02-12 19:32:20.217 WARNING (MainThread) [custom_components.lampie.orchestrator] from state: LampieSwitchInfo(led_config=(LEDConfig(color=<Color.RED: 0>, effect=<Effect.OPEN_CLOSE: 6>, brightness=100.0, duration=30.0),), led_config_source=LEDConfigSource(value='test', type=<LEDConfigSourceType.NOTIFICATION: 'notification'>), integration_info=Z2MSwitchInfo(full_topic='zigbee2mqtt/Office Switch', local_protection_enabled=False, double_tap_clear_notifications_disabled=False), integration=<Integration.Z2M: 'z2m'>, priorities=('test',), expiration=ExpirationInfo(started_at=None, expires_at=None, cancel_listener=None)),
led_confg_src: notification:test,
led_config: [LEDConfig(color=<Color.RED: 0>, effect=<Effect.OPEN_CLOSE: 6>, brightness=100.0, duration=30.0)],
all_clear: False,
first_on: <custom_components.lampie.coordinator.LampieUpdateCoordinator object at 0x7f91a4b12660>,
2026-02-12 19:32:20.217 DEBUG (MainThread) [custom_components.lampie.orchestrator] processing Z2M event led_effect_complete_ALL_LEDS on light.office_switch
2026-02-12 19:32:20.217 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:test:off)
2026-02-12 19:32:20.217 WARNING (MainThread) [custom_components.lampie.orchestrator] switch light.office_switch cleared a notification from the firmware; attempting to dismiss the notification; command=led_effect_complete_ALL_LEDS, led_config_source=notification:test, active_notification=test
2026-02-12 19:32:20.217 DEBUG (MainThread) [custom_components.lampie.orchestrator] start time cleared (test)
2026-02-12 19:32:20.217 DEBUG (MainThread) [custom_components.lampie.orchestrator] notification updated (test=off)
2026-02-12 19:32:20.218 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:off)
2026-02-12 19:32:20.218 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:20.218 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:48.079 WARNING (MainThread) [custom_components.lampie.orchestrator] {'0': 29, '1': 47, '10': 205, '11': 255, '12': 0, '13': 0, '14': 1, '2': 18, '3': 126, '4': 1, '5': 1, '6': 136, '7': 0, '8': 171, '9': 0, 'activeEnergyReports': 10, 'activePowerReports': 10, 'autoTimerOff': 0, 'auxSwitchUniqueScenes': 'Disabled', 'bindingOffToOnSyncLevel': 'Disabled', 'brightness': 70, 'brightnessLevelForDoubleTapDown': 2, 'brightnessLevelForDoubleTapUp': 254, 'buttonDelay': '500ms', 'current': 0, 'defaultLed1ColorWhenOff': 255, 'defaultLed1ColorWhenOn': 255, 'defaultLed1IntensityWhenOff': 101, 'defaultLed1IntensityWhenOn': 101, 'defaultLed2ColorWhenOff': 255, 'defaultLed2ColorWhenOn': 255, 'defaultLed2IntensityWhenOff': 101, 'defaultLed2IntensityWhenOn': 101, 'defaultLed3ColorWhenOff': 255, 'defaultLed3ColorWhenOn': 255, 'defaultLed3IntensityWhenOff': 101, 'defaultLed3IntensityWhenOn': 101, 'defaultLed4ColorWhenOff': 255, 'defaultLed4ColorWhenOn': 255, 'defaultLed4IntensityWhenOff': 101, 'defaultLed4IntensityWhenOn': 101, 'defaultLed5ColorWhenOff': 255, 'defaultLed5ColorWhenOn': 255, 'defaultLed5IntensityWhenOff': 101, 'defaultLed5IntensityWhenOn': 101, 'defaultLed6ColorWhenOff': 255, 'defaultLed6ColorWhenOn': 255, 'defaultLed6IntensityWhenOff': 101, 'defaultLed6IntensityWhenOn': 101, 'defaultLed7ColorWhenOff': 255, 'defaultLed7ColorWhenOn': 255, 'defaultLed7IntensityWhenOff': 101, 'defaultLed7IntensityWhenOn': 101, 'defaultLevelLocal': 101.6, 'defaultLevelRemote': 101.6, 'deviceBindNumber': 0, 'dimmingMode': 'Leading edge', 'dimmingSpeedDownLocal': 127, 'dimmingSpeedDownRemote': 127, 'dimmingSpeedUpLocal': 127, 'dimmingSpeedUpRemote': 15, 'doubleTapClearNotifications': 'Enabled (Default)', 'doubleTapDownToParam56': 'Disabled', 'doubleTapUpToParam55': 'Disabled', 'energy': 0.03, 'energy_reset': None, 'fanControlMode': 'Disabled', 'fanLedLevelType': 0, 'fanTimerMode': 'Disabled', 'firmwareUpdateInProgressIndicator': 'Enabled', 'highLevelForFanControlMode': 254, 'higherOutputInNonNeutral': 'Disabled (default)', 'identify': None, 'illuminance': 1, 'individual_led_effect': None, 'internalTemperature': 49, 'invertSwitch': 'No', 'ledBarScaling': 'Gen3 method (VZM-style)', 'ledColorForFanControlMode': 255, 'ledColorWhenOff': 170, 'ledColorWhenOn': 170, 'ledIntensityWhenOff': 1, 'ledIntensityWhenOn': 33, 'led_effect': {'color': 0, 'duration': 30, 'effect': 'open_close', 'level': 100}, 'linkquality': 140, 'loadLevelIndicatorTimeout': 'Stay On', 'localProtection': 'Disabled', 'lowLevelForFanControlMode': 63, 'maximumLevel': 255, 'mediumLevelForFanControlMode': 128, 'minimumLevel': 1, 'mmWaveDepthMax': 200, 'mmWaveDepthMin': 0, 'mmWaveDetectSensitivity': 'High (default)', 'mmWaveDetectTrigger': 'Fast (0.2s, default)', 'mmWaveHeightMax': 75, 'mmWaveHeightMin': -75, 'mmWaveHoldTime': 30, 'mmWaveRoomSizePreset': 'Small', 'mmWaveStayLife': 300, 'mmWaveTargetInfoReport': 'Disable (default)', 'mmWaveVersion': 100863491, 'mmWaveWidthMax': 100, 'mmWaveWidthMin': -100, 'mmwaveControlWiredDevice': 'Disabled', 'mmwave_area1_occupancy': True, 'mmwave_area2_occupancy': False, 'mmwave_area3_occupancy': False, 'mmwave_area4_occupancy': False, 'mmwave_control_commands': {'controlID': 'query_areas'}, 'mmwave_detection_areas': {'area1': {'depth_max': 200, 'depth_min': 0, 'height_max': 75, 'height_min': -75, 'width_max': 100, 'width_min': -100}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'mmwave_interference_areas': {'area1': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'mmwave_stay_areas': {'area1': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'notificationComplete': 'ALL_LEDS', 'occupancy': True, 'onOffLedMode': 'All', 'otaImageType': 'Zigbee (259)', 'outputMode': 'Dimmer', 'overheat': 'No Alert', 'periodicPowerAndEnergyReports': 3600, 'power': 1.2, 'powerType': 'Neutral', 'quickStartLevel': 254, 'quickStartTime': 0, 'rampRateOffToOnLocal': 127, 'rampRateOffToOnRemote': 127, 'rampRateOnToOffLocal': 127, 'rampRateOnToOffRemote': 127, 'remoteProtection': 'Disabled', 'singleTapBehavior': 'Old Behavior', 'smartBulbMode': 'Disabled', 'state': 'ON', 'stateAfterPowerRestored': 255, 'switchType': 'Aux Switch', 'update': {'installed_version': 16974080, 'latest_release_notes': None, 'latest_source': 'https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/images/Inovelli/VZM32-SN_0.10.ota', 'latest_version': 16973834, 'state': 'idle'}, 'voltage': 81.8}
2026-02-12 19:32:48.079 WARNING (MainThread) [custom_components.lampie.orchestrator] handling event led_effect_complete_ALL_LEDS for Z2M on light.office_switch
2026-02-12 19:32:48.079 WARNING (MainThread) [custom_components.lampie.orchestrator] from state: LampieSwitchInfo(led_config=(), led_config_source=LEDConfigSource(value=None, type=<LEDConfigSourceType.NOTIFICATION: 'notification'>), integration_info=Z2MSwitchInfo(full_topic='zigbee2mqtt/Office Switch', local_protection_enabled=False, double_tap_clear_notifications_disabled=False), integration=<Integration.Z2M: 'z2m'>, priorities=('test',), expiration=ExpirationInfo(started_at=None, expires_at=None, cancel_listener=None)),
led_confg_src: notification,
led_config: [],
all_clear: True,
first_on: None,
2026-02-12 19:32:48.079 DEBUG (MainThread) [custom_components.lampie.orchestrator] processing Z2M event led_effect_complete_ALL_LEDS on light.office_switch
2026-02-12 19:32:48.079 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:off)
2026-02-12 19:32:48.080 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:off)
2026-02-12 19:32:48.080 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:48.080 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:48.774 WARNING (MainThread) [custom_components.lampie.orchestrator] {'0': 29, '1': 47, '10': 205, '11': 255, '12': 0, '13': 0, '14': 1, '2': 18, '3': 126, '4': 1, '5': 1, '6': 136, '7': 0, '8': 171, '9': 0, 'activeEnergyReports': 10, 'activePowerReports': 10, 'autoTimerOff': 0, 'auxSwitchUniqueScenes': 'Disabled', 'bindingOffToOnSyncLevel': 'Disabled', 'brightness': 70, 'brightnessLevelForDoubleTapDown': 2, 'brightnessLevelForDoubleTapUp': 254, 'buttonDelay': '500ms', 'current': 0, 'defaultLed1ColorWhenOff': 255, 'defaultLed1ColorWhenOn': 255, 'defaultLed1IntensityWhenOff': 101, 'defaultLed1IntensityWhenOn': 101, 'defaultLed2ColorWhenOff': 255, 'defaultLed2ColorWhenOn': 255, 'defaultLed2IntensityWhenOff': 101, 'defaultLed2IntensityWhenOn': 101, 'defaultLed3ColorWhenOff': 255, 'defaultLed3ColorWhenOn': 255, 'defaultLed3IntensityWhenOff': 101, 'defaultLed3IntensityWhenOn': 101, 'defaultLed4ColorWhenOff': 255, 'defaultLed4ColorWhenOn': 255, 'defaultLed4IntensityWhenOff': 101, 'defaultLed4IntensityWhenOn': 101, 'defaultLed5ColorWhenOff': 255, 'defaultLed5ColorWhenOn': 255, 'defaultLed5IntensityWhenOff': 101, 'defaultLed5IntensityWhenOn': 101, 'defaultLed6ColorWhenOff': 255, 'defaultLed6ColorWhenOn': 255, 'defaultLed6IntensityWhenOff': 101, 'defaultLed6IntensityWhenOn': 101, 'defaultLed7ColorWhenOff': 255, 'defaultLed7ColorWhenOn': 255, 'defaultLed7IntensityWhenOff': 101, 'defaultLed7IntensityWhenOn': 101, 'defaultLevelLocal': 101.6, 'defaultLevelRemote': 101.6, 'deviceBindNumber': 0, 'dimmingMode': 'Leading edge', 'dimmingSpeedDownLocal': 127, 'dimmingSpeedDownRemote': 127, 'dimmingSpeedUpLocal': 127, 'dimmingSpeedUpRemote': 15, 'doubleTapClearNotifications': 'Enabled (Default)', 'doubleTapDownToParam56': 'Disabled', 'doubleTapUpToParam55': 'Disabled', 'energy': 0.03, 'energy_reset': None, 'fanControlMode': 'Disabled', 'fanLedLevelType': 0, 'fanTimerMode': 'Disabled', 'firmwareUpdateInProgressIndicator': 'Enabled', 'highLevelForFanControlMode': 254, 'higherOutputInNonNeutral': 'Disabled (default)', 'identify': None, 'illuminance': 9, 'individual_led_effect': None, 'internalTemperature': 49, 'invertSwitch': 'No', 'ledBarScaling': 'Gen3 method (VZM-style)', 'ledColorForFanControlMode': 255, 'ledColorWhenOff': 170, 'ledColorWhenOn': 170, 'ledIntensityWhenOff': 1, 'ledIntensityWhenOn': 33, 'led_effect': {'color': 0, 'duration': 30, 'effect': 'open_close', 'level': 100}, 'linkquality': 136, 'loadLevelIndicatorTimeout': 'Stay On', 'localProtection': 'Disabled', 'lowLevelForFanControlMode': 63, 'maximumLevel': 255, 'mediumLevelForFanControlMode': 128, 'minimumLevel': 1, 'mmWaveDepthMax': 200, 'mmWaveDepthMin': 0, 'mmWaveDetectSensitivity': 'High (default)', 'mmWaveDetectTrigger': 'Fast (0.2s, default)', 'mmWaveHeightMax': 75, 'mmWaveHeightMin': -75, 'mmWaveHoldTime': 30, 'mmWaveRoomSizePreset': 'Small', 'mmWaveStayLife': 300, 'mmWaveTargetInfoReport': 'Disable (default)', 'mmWaveVersion': 100863491, 'mmWaveWidthMax': 100, 'mmWaveWidthMin': -100, 'mmwaveControlWiredDevice': 'Disabled', 'mmwave_area1_occupancy': True, 'mmwave_area2_occupancy': False, 'mmwave_area3_occupancy': False, 'mmwave_area4_occupancy': False, 'mmwave_control_commands': {'controlID': 'query_areas'}, 'mmwave_detection_areas': {'area1': {'depth_max': 200, 'depth_min': 0, 'height_max': 75, 'height_min': -75, 'width_max': 100, 'width_min': -100}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'mmwave_interference_areas': {'area1': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'mmwave_stay_areas': {'area1': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area2': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area3': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}, 'area4': {'depth_max': 0, 'depth_min': 0, 'height_max': 600, 'height_min': -600, 'width_max': 0, 'width_min': 0}}, 'notificationComplete': 'ALL_LEDS', 'occupancy': True, 'onOffLedMode': 'All', 'otaImageType': 'Zigbee (259)', 'outputMode': 'Dimmer', 'overheat': 'No Alert', 'periodicPowerAndEnergyReports': 3600, 'power': 1.2, 'powerType': 'Neutral', 'quickStartLevel': 254, 'quickStartTime': 0, 'rampRateOffToOnLocal': 127, 'rampRateOffToOnRemote': 127, 'rampRateOnToOffLocal': 127, 'rampRateOnToOffRemote': 127, 'remoteProtection': 'Disabled', 'singleTapBehavior': 'Old Behavior', 'smartBulbMode': 'Disabled', 'state': 'ON', 'stateAfterPowerRestored': 255, 'switchType': 'Aux Switch', 'update': {'installed_version': 16974080, 'latest_release_notes': None, 'latest_source': 'https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/images/Inovelli/VZM32-SN_0.10.ota', 'latest_version': 16973834, 'state': 'idle'}, 'voltage': 81.8}
2026-02-12 19:32:48.775 WARNING (MainThread) [custom_components.lampie.orchestrator] handling event led_effect_complete_ALL_LEDS for Z2M on light.office_switch
2026-02-12 19:32:48.775 WARNING (MainThread) [custom_components.lampie.orchestrator] from state: LampieSwitchInfo(led_config=(), led_config_source=LEDConfigSource(value=None, type=<LEDConfigSourceType.NOTIFICATION: 'notification'>), integration_info=Z2MSwitchInfo(full_topic='zigbee2mqtt/Office Switch', local_protection_enabled=False, double_tap_clear_notifications_disabled=False), integration=<Integration.Z2M: 'z2m'>, priorities=('test',), expiration=ExpirationInfo(started_at=None, expires_at=None, cancel_listener=None)),
led_confg_src: notification,
led_config: [],
all_clear: True,
first_on: None,
2026-02-12 19:32:48.775 DEBUG (MainThread) [custom_components.lampie.orchestrator] processing Z2M event led_effect_complete_ALL_LEDS on light.office_switch
2026-02-12 19:32:48.775 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:off)
2026-02-12 19:32:48.775 DEBUG (MainThread) [custom_components.lampie.orchestrator] switch updated (light.office_switch=notification:off)
2026-02-12 19:32:48.775 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all
2026-02-12 19:32:48.775 DEBUG (MainThread) [custom_components.lampie.orchestrator] issued commands to update light.office_switch leds: all

@wbyoung
Copy link
Owner Author

wbyoung commented Feb 13, 2026

Once notificationComplete is set in the payload, it never clears/changes, so after toggling on a notification in HA it immediate turns off the toggle in HA as _all_clear is True. With ZHA, is the value of the complete notification constant?

notificationComplete will change between ALL_LEDS and a different value when double clicking the config button, but other than that it never changes.

I'm guessing that ZHA works differently here, but there's really no payload to speak of—just the event being triggered. That event doesn't really come with the full state of things.

It sounds like what you're saying is that Z2M keeps track of the state of the switch and sends the whole state in the event/update that we're registered for. Does that sound right?

If so, we'll likely need to store the state of notificationComplete (in switch_info.integration_info, here referenced as zha_info) and only consider it being triggered when the value changes (to any value) when we process the payload.

@rohankapoorcom
Copy link

I can confirm that what you've described is how notificationComplete is processed in Z2M.

@MrDaGree
Copy link

I can confirm that what you've described is how notificationComplete is processed in Z2M.

This is helpful to know! I appreciate, though it seems a bit of an issue that it doesnt "clear" the next time you apply an LED effect

@wbyoung
Copy link
Owner Author

wbyoung commented Feb 14, 2026

This is helpful to know! I appreciate, though it seems a bit of an issue that it doesnt "clear" the next time you apply an LED effect

We can maintain our own state, though. As long as we only react to the changes we see, it should function about the same.

@MrDaGree
Copy link

MrDaGree commented Feb 14, 2026

The issue revolves around notifications with a specific duration. If I have a 30s duration notification, at the end of that "ALL_LEDS" is set in the payload. If I set another 30s duration notification, the payload already has "ALL_LEDS" set so it doesnt change to then be able to react on and immediately "clears" on the lampie side of things despite the notification still running.

This isnt an issue if I alternate between dismissing via the switch and then have a timed duration one.


Scenario to help ensure I'm explaining well:

  • Start 30s duration ALL_LED notification, if first start of Z2M notificationComplete is "unknown"
  • After 30s, notificationComplete is set to ALL_LEDS
  • Start another 30s duration ALL_LED notification, immediately clears as the next payload already has notificationComplete set to ALL_LEDS
  • Dismiss notification on switch, notificationComplete changes to button_3_double, then start 30s duration ALL_LED notification
  • After 30s, notificationComplete changes from button_3_double to ALL_LEDS

EDIT:

I guess we could store the "state" of the switch when we start a notification like you previously said in Lampie itself, but it'd be nice if the notificationComplete actually changed to a state not indicating complete once a new notification is sent

@rohankapoorcom
Copy link

I guess we could store the "state" of the switch when we start a notification like you previously said in Lampie itself, but it'd be nice if the notificationComplete actually changed to a state not indicating complete once a new notification is sent

I guess we could handle that in the Z2M converter, but it's a little bit weird since we'd basically be guessing at what point to reset the attribute since the device doesn't tell us that information.

@wbyoung
Copy link
Owner Author

wbyoung commented Feb 14, 2026

I guess we could handle that in the Z2M converter, but it's a little bit weird since we'd basically be guessing at what point to reset the attribute since the device doesn't tell us that information.

@rohankapoorcom would it be okay to clear it on any next change? It's a momentarily fired event, not something that's a persistent state. I'm guessing this just doesn't map well to the Z2M representation of things.

@MrDaGree are we also saying that (outside of Lampie) we have a notification that clears with notificationComplete=ALL_LEDS after 30 seconds and started another, that the notificationComplete=ALL_LEDS would have remained consistently the same value the entire time? This suggests it would need to be addressed in the Z2M converter.

@rohankapoorcom
Copy link

@rohankapoorcom would it be okay to clear it on any next change? It's a momentarily fired event, not something that's a persistent state. I'm guessing this just doesn't map well to the Z2M representation of things.

Do you know how the momentary clearing is handled on the ZHA side? We could try to implement it exactly the same way there. I assumed that the device would publish a "clearing" of it after some period of time but it does not.

@wbyoung
Copy link
Owner Author

wbyoung commented Feb 14, 2026

@rohankapoorcom would it be okay to clear it on any next change? It's a momentarily fired event, not something that's a persistent state. I'm guessing this just doesn't map well to the Z2M representation of things.

Do you know how the momentary clearing is handled on the ZHA side? We could try to implement it exactly the same way there. I assumed that the device would publish a "clearing" of it after some period of time but it does not.

I don't know that I've dug far enough into it to know the exact answer, but can look more if need be. I know that ZHA publishes certain events to the HASS event bus with key zha_event and that this is one of them. I assumed—possibly incorrectly—that the switch was doing the same thing, broadcasting an event. Is the switch actually changing state? Does Zigbee (or Z2M) not have an event concept?

@rohankapoorcom
Copy link

I assumed—possibly incorrectly—that the switch was doing the same thing, broadcasting an event. Is the switch actually changing state? Does Zigbee (or Z2M) not have an event concept?

The switch is effectively broadcasting an event. I don't think Z2M has the concept of arbitrary event, only Actions are treated like events. We use the Actions concept already to send the multi tap scenes so I wouldn't want to overload that to send this over as well. Let me look at how it's implemented and see if we can extend that logic to send this as an event instead.

@MrDaGree
Copy link

@MrDaGree are we also saying that (outside of Lampie) we have a notification that clears with notificationComplete=ALL_LEDS after 30 seconds and started another, that the notificationComplete=ALL_LEDS would have remained consistently the same value the entire time? This suggests it would need to be addressed in the Z2M converter.

Correct. I also wonder if it would make more sense for Lampie to send back clear, but clearing the LEDS also would run into the same as above as it wouldnt change the notificationComplete

@wbyoung
Copy link
Owner Author

wbyoung commented Feb 18, 2026

Correct. I also wonder if it would make more sense for Lampie to send back clear, but clearing the LEDS also would run into the same as above as it wouldnt change the notificationComplete

Another way—and this is what I was planning before @rohankapoorcom added support in the Z2M converters—is to just manage the notification durations entirely in the integration and not send them to the switch at all.

But hopefully @rohankapoorcom has a solution in mind and can turn something around quickly enough to allow you to continue to move this forward, @MrDaGree.

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