Z-Wave JS UI + Zooz ZEN34 - retained sensor values

I have an issue after some recent Z-Wave JS UI updates or Home Assistant updates. Here is how it worked before:

ZEN34 button has 2 sensors, for the lower and for the upper paddle. Upon pressing any of them, the sensor value briefly changes to a number, from 0 to 5 (0 = single press, 1 = button held, 2 = button released, 3 = double press, 4 = triple, etc). Between the presses the sensor was back in the Unknown state (or N/A, I don’t remember, but the fact is it wasn’t within the 0…5 digit range).

Now it works almost the same, except for one change: it retains the last number. So if I press it once, it changes to 0 and stays, and if I press it again, it doesn’t trigger the automation which is listening for a sensor state change. I have to either do another physical action with the switch, or listen for MQTT events and catch the value from the message. MQTT method is fine for a temporary workaround, but I will have to update all the automations for all the switches, which is some additional work I’m trying to avoid if this can be fixed :slight_smile:

I’d be glad to submit a bug report, but I’m not sure if it’s a Home Assistant or Z-Wave JS UI behavior issue.

You’ll need to provide more information about the entities you’re using and your automation.

Here is how it worked before:

alias: Master Bedroom - Bed Light Off
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.n_9
    to: "0"
action:
  - service: light.turn_off
    target:
      entity_id: light.master_bedroom_bed_light
    data: {}
mode: single

Here is the current workaround:

alias: Master Bedroom - Bed Light Off
description: ""
trigger:
  - platform: mqtt
    topic: zwave/master_bedroom/other/romans_switch/91/0/scene/002
    enabled: true
condition:
  - condition: template
    value_template: "{{trigger.payload_json.value == 0 }}"
action:
  - service: light.turn_off
    target:
      entity_id: light.master_bedroom_bed_light
    data: {}
mode: single

I’m not sure how I can provide info about the entities, here is the screenshot and config from Z-Wave JS UI

{
  "type": "sensor",
  "object_id": "scene_state_scene_002",
  "discovery_payload": {
    "state_topic": "zwave/master_bedroom/other/romans_switch/91/0/scene/002",
    "value_template": "{{ value_json.value | default('') }}",
    "state_class": "measurement",
    "availability": [
      {
        "payload_available": "true",
        "payload_not_available": "false",
        "topic": "zwave/master_bedroom/other/romans_switch/status",
        "value_template": "{{'true' if value_json.value else 'false'}}"
      },
      {
        "topic": "zwave/_CLIENTS/ZWAVE_GATEWAY-Mosquitto/status",
        "value_template": "{{'online' if value_json.value else 'offline'}}"
      },
      {
        "payload_available": "true",
        "payload_not_available": "false",
        "topic": "zwave/driver/status"
      }
    ],
    "availability_mode": "all",
    "json_attributes_topic": "zwave/master_bedroom/other/romans_switch/91/0/scene/002",
    "device": {
      "identifiers": [
        "zwavejs2mqtt_0xe95ecd56_node36"
      ],
      "manufacturer": "Zooz",
      "model": "Z-Wave Plus 700 Series Remote Switch (ZEN34)",
      "name": "master_bedroom/other/romans_switch",
      "sw_version": "1.40.2"
    },
    "name": "n",
    "unique_id": "zwavejs2mqtt_0xe95ecd56_36-91-0-scene-002"
  },
  "discoveryTopic": "sensor/master_bedroom-other-romans_switch/scene_state_scene_002/config",
  "values": [
    "91-0-scene-002"
  ],
  "persistent": false,
  "ignoreDiscovery": false,
  "id": "sensor_scene_state_scene_002"
}

My UltraPro’s behave as your ZEN34 did initially. The value is undefined in between presses. I’m on Z-Wave JS UI 9.6.2.6e369a1.

However, my automations use device triggers rather than state:

platform: device
device_id: ce54736050a32cedfbe5d4588c8c6637
domain: zwave_js
type: event.value_notification.central_scene
property: scene
property_key: "001"
endpoint: 0
command_class: 91
subtype: Endpoint 0 Scene 001
value: 0
id: Button 1

I’m on v9.8.2. In the Device trigger behavior is somewhat the same: it doesn’t trigger when 0 is changed to 0, and between actions it retains the previous value.

What integration are you using exactly? It looks like MQTT, not Z-Wave.

Z-Wave JS UI (aka zwavejs2mqtt), so ZEN34 is connected as an MQTT device, yes

Well, one solution is switch to the Z-Wave integration. :wink:

Otherwise, I don’t have much experience with the MQTT side of Z-Wave, maybe something broke in Z-Wave JS UI as there have been some recent changes in that area.

If you want to know whether it’s an HA or ZUI issue, downgrade to a previous version of ZUI and see if it works again. If so, I’d say it’s the fault of ZUI. Take note of the discovery payload and see if it’s any different than the non-working one.

1 Like

Thanks. Downgrade was a really good idea, now I know the versions before January 25th work as expected and change the value to null between the presses :slight_smile:

upd: so looks like the issue was introduced in Z-Wave JS UI 3.3.0 / 9.8.0

And it changes the config in the Z-Wave JS UI for the scenes, here is an old version and the sensor doesn’t have the “measurement” state_class:

{
  "type": "sensor",
  "object_id": "scene_state_scene_002",
  "discovery_payload": {
    "state_topic": "zwave/master_bedroom/other/romans_switch/91/0/scene/002",
    "value_template": "{{ value_json.value | default('') }}",
    "availability": [
      {
        "payload_available": "true",
        "payload_not_available": "false",
        "topic": "zwave/master_bedroom/other/romans_switch/status",
        "value_template": "{{'true' if value_json.value else 'false'}}"
      },
      {
        "topic": "zwave/_CLIENTS/ZWAVE_GATEWAY-Mosquitto/status",
        "value_template": "{{'online' if value_json.value else 'offline'}}"
      },
      {
        "payload_available": "true",
        "payload_not_available": "false",
        "topic": "zwave/driver/status"
      }
    ],
    "availability_mode": "all",
    "json_attributes_topic": "zwave/master_bedroom/other/romans_switch/91/0/scene/002",
    "device": {
      "identifiers": [
        "zwavejs2mqtt_0xe95ecd56_node36"
      ],
      "manufacturer": "Zooz",
      "model": "Z-Wave Plus 700 Series Remote Switch (ZEN34)",
      "name": "master_bedroom/other/romans_switch",
      "sw_version": "1.40.2"
    },
    "name": "n",
    "unique_id": "zwavejs2mqtt_0xe95ecd56_36-91-0-scene-002"
  },
  "discoveryTopic": "sensor/master_bedroom-other-romans_switch/scene_state_scene_002/config",
  "values": [
    "91-0-scene-002"
  ],
  "persistent": false,
  "ignoreDiscovery": false,
  "id": "sensor_scene_state_scene_002"
}

Which version is working?

That seems like a likely cause, because that was one of the only changes related to Central Scene.

change the value to null between the presses

What is the actual value of the MQTT payload when this happens?

Do you see any error messages in the HA logs? Anything about a numeric value?

zwavejs2mqtt_3.2.1 is working fine out of box.
Sorry, I got confused with the changelogs and version numbers, because I can see 3.2.1 in the backup and 9.7.1 in the changelog.

Release 9.8.2/3.3.1 only works if I manually remove the “state_class”: “measurement” key

3.2.1 is the add-on version. You identified the correct ZUI version.

Do you see any error messages in your logs though? https://github.com/home-assistant/core/blob/1f7bf7c2a9d42cc1a9b74420e601b5e0a76493c1/homeassistant/components/sensor/__init__.py#L646-L652

Nothing in logs specifically for ZEN34
MQTT without the measurement part is the following:

Message 0 received on zwave/master_bedroom/other/romans_switch/91/0/scene/002 at 12:37 AM:

{"time":1706855050908}
Message 1 received on zwave/master_bedroom/other/romans_switch/91/0/scene/002 at 12:37 AM:

{"time":1706855831943,"value":0}

Message 2 received on zwave/master_bedroom/other/romans_switch/91/0/scene/002 at 12:37 AM:

{"time":1706855832950}

So it doesn’t send the null value, just no value in the payload, only time. Sorry, it’s getting late so my next reply will be tomorrow, but I can confirm it matches with the default behavior on the new Z-Wave JS UI version too: when I was doing a workaround, I was listening to the topic and it was providing only time or time+value in the payload. So it’s definitely not a HA issue, but a Z-Wave JS UI issue.

MQTT without the measurement part is the following:

Well, I’m curious if you get the error log I linked to, which would show when the state_class was set. It would explain your problem. The state_class forces the sensor code to check for a numeric value, and it errors if it’s not.

So it doesn’t send the null value, just no value in the payload, only time.

Yeah, but this template converts the empty payload into an empty string. So an empty string would definitely trigger an error when trying to convert to a numeric value. Perhaps either the default should be removed, or the state_class. Either way, as you say it’s a ZUI issue.

Funny enough I noticed that all Zooz devices behave the same way, but not all of them have an error reported. But the ones that do, do it in the exact way you predicted:

Logger: homeassistant.components.mqtt.models
Source: components/mqtt/models.py:305
Integration: MQTT (documentation, issues)
First occurred: February 1, 2024 at 11:53:47 PM (109 occurrences)
Last logged: 8:02:59 AM

Exception raised when updating state of sensor.scene_001_2, topic: 'zwave/garage/other/garage_opener/91/0/scene/001' with payload: b'{"time":1706855052215}'
Exception raised when updating state of sensor.n_26, topic: 'zwave/fireplace_room/lights/annas_work_light/status' with payload: b'{"time":1706855251080,"value":true,"status":"Alive","nodeId":43}'
Exception raised when updating state of sensor.n_25, topic: 'zwave/fireplace_room/lights/annas_work_light/status' with payload: b'{"time":1706855251080,"value":true,"status":"Alive","nodeId":43}'
Exception raised when updating state of sensor.n_24, topic: 'zwave/fireplace_room/lights/annas_work_light/status' with payload: b'{"time":1706855251080,"value":true,"status":"Alive","nodeId":43}'
Exception raised when updating state of sensor.scene_001_2, topic: 'zwave/garage/other/garage_opener/status' with payload: b'{"time":1706882579550,"value":true,"status":"Alive","nodeId":46}'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 639, in state
    numerical_value = int(value)
                      ^^^^^^^^^^
ValueError: invalid literal for int() with base 10: ''

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 642, in state
    numerical_value = float(value)
                      ^^^^^^^^^^^^
ValueError: could not convert string to float: ''

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/mqtt/models.py", line 305, in process_write_state_requests
    entity.async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 945, in async_write_ha_state
    self._async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1066, in _async_write_ha_state
    state, attr, capabilities, shadowed_attr = self.__async_calculate_state()
                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1003, in __async_calculate_state
    state = self._stringify_state(available)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 951, in _stringify_state
    if (state := self.state) is None:
                 ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 646, in state
    raise ValueError(
ValueError: Sensor sensor.scene_001_2 has device class 'None', state class 'measurement' unit 'None' and suggested precision 'None' thus indicating it has a numeric value; however, it has the non-numeric value: '' (<class 'str'>)
1 Like

3.3.2 version has it fixed, in case anyone had the same issue