core: OZW: Set points incorrectly being converted to fahrenheit (HA now)

The problem

My previous issue was caused by OpenZWave and was fixed in https://github.com/OpenZWave/open-zwave/issues/2324 and for the past 24 hours or so everything has been working correctly in HA. However I just noticed that HA is now showing the Set Points incorrectly even though they’re being sent over MQTT correctly.

Environment

  • Home Assistant Core release with the issue: 0.113.3
  • Last working Home Assistant Core release (if known): At least since 0.109.3
  • Operating environment (OS/Container/Supervised/Core): Supervised
  • Integration causing this issue: OpenZWave (beta)
  • Link to integration documentation on our website: https://www.home-assistant.io/integrations/ozw/

Problem-relevant configuration.yaml

N/A

Traceback/Error logs

Additional information

Message 3 received on OpenZWave/1/node/12/instance/1/commandclass/67/value/562950160039954/ at 7:27 PM:
{
    "Label": "Cooling 1",
    "Value": 76,
    "Units": "F",
    "ValueSet": true,
    "ValuePolled": false,
    "ChangeVerified": false,
    "Min": 0,
    "Max": 0,
    "Type": "Decimal",
    "Instance": 1,
    "CommandClass": "COMMAND_CLASS_THERMOSTAT_SETPOINT",
    "Index": 2,
    "Node": 12,
    "Genre": "User",
    "Help": "Set the Thermostat Setpoint Cooling 1",
    "ValueIDKey": 562950160039954,
    "ReadOnly": false,
    "WriteOnly": false,
    "Event": "valueChanged",
    "TimeStamp": 1596663592
}
QoS: 0 - Retain: true
Message 2 received on OpenZWave/1/node/12/instance/1/commandclass/67/value/281475183329298/ at 7:27 PM:
{
    "Label": "Heating 1",
    "Value": 65,
    "Units": "F",
    "ValueSet": true,
    "ValuePolled": false,
    "ChangeVerified": false,
    "Min": 0,
    "Max": 0,
    "Type": "Decimal",
    "Instance": 1,
    "CommandClass": "COMMAND_CLASS_THERMOSTAT_SETPOINT",
    "Index": 1,
    "Node": 12,
    "Genre": "User",
    "Help": "Set the Thermostat Setpoint Heating 1",
    "ValueIDKey": 281475183329298,
    "ReadOnly": false,
    "WriteOnly": false,
    "Event": "valueChanged",
    "TimeStamp": 1596663592
}
QoS: 0 - Retain: true

image

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 38 (19 by maintainers)

Most upvoted comments

FWIW, I’ve been running with my change to always convert the values to the expected units (https://github.com/tboyce021/home-assistant/commit/52d842e200a52bcb67294457fb2822f996fd48e5) for the last two months and haven’t had any issues yet. Is there a better solution though?

Edit: Just updated the link with the rebase I did the other day. This should work with 0.118.

I had independently analyzed this before finding this issue. Below is my writeup of the cause, and my suggestions for how to approach addressing this. Hope this is useful.

Summary of Cause

Z-Wave thermostats that support multilevel sensor command class version 5 or newer let the device requesting the value to choose which temperature scale to receive in response. Unfortunately, the v5+ design of the multilevel sensor does not have any way of requesting that the devices default scale be used. This is arguably a bug/deficiency in the Z-wave specification.

When the device provides unsolicited temperature sensor reports, it gets to choose what scale to use. Decent thermostats will probably use whatever scale is used on the devices UI for these. (a.k.a. The same scale as it is using for the set-points).

OpenZWave allows you to specify the default unit to use when requesting the multilevel sensor value by setting the value at 255+index_of_temperature_sensor. However, if the node info is refreshed (such as with the refresh node info command), it will end up resetting the default back to Celsius. Furthermore, the current value of this 255+index value is not reliably saved to to the cache xml file, so the value is usually reset back to Celsius whenever the ozwdaemon container is restarted.

So basically, there is nothing that can be done by the ozw integration to ensure that the air temperature reported is always in Fahrenheit. Setting the default unit helps, but upon a node info refresh or daemon restart, a value in °C will get reported to MQTT.

The set points on the other hand, do reliably report in the thermostats current units. [0] Technically, when setting a set-point, Z-Wave allows picking which scale you are setting, and the thermostat is responsible for converting if necessary. However, ozwdaemon does not really support this via the setvalue api, which assumes the value given is in the same units as the set-point currently uses.

Right now it is actively dangerous to try to automate set point temperatures for thermostats that support Z-Wave multi-level sensor v5 or newer if the thermostat uses °F. This is because if the most recent air temperature reading happens to be in °C, the following occurs if you try to set the set-point to say 75°F: the units of the climate sensor are reported as °C, so the set-point value get converted to 24°C, sent to ozwdaemon without units, where ozwdaemon interprets it as 24°F, sends it to the thermostat, which recognizes that 24°F is below the minimum and sets it to the minimum instead.

Conclusions

Therefore, the bottom line is that under the current design, HA will sometimes get air temperatures in °C and sometimes in °F for thermostats that should be using °F. Unless and until improvements to OpenZWave and/or ozwdaemon are made to allow us to avoid this, we will simply need to cope with this fact.

Therefore, since the units reported by MQTT for the temperature sensor cannot be relied upon to indicate the units that should be used for the entity as a whole, but the set-points can, it would seem wise to base temperature_unit on the set-point units. This is especially true, since technically it is optional for a Z-Wave HVAC thermostat to report air temperature at all [1]. That alone would avoid the changing set-points to minimum value accidentally problem.

However to avoid merely inverting the overall problem, two additional changes are desirable. The first is noticing when the reported air temperature has different units from the set-point, and having that trigger us to update the default default air temperature unit for querying. The second is to either convert the air temperature to the other units in the mismatch case, or alternatively to treat the value as unavailable in the units mismatch case.

Footnotes

[0] There is one caveat here. Set-points that correspond to modes that are not currently available might have the wrong units. (E.g. my settings don’t Enable any modes that use the “Dry” set-point, and thus its “Dry” set-point units are not correct. But the heat and cool set-points are used by available modes, so they have the correct units.

[1] If you are wondering how this can be, I suspect the intention here is that a thermostat can be made that uses the temperature sensor of another node via an association group, and thus does not need to have one of its own. I am not aware of any thermostats that actually take advantage of this option.

I think so. To confirm it should be “Celsius” and “Fahrenheit”.

So we should set the CommandClass": "COMMAND_CLASS_SENSOR_MULTILEVEL", "Index": 256 to the unit, F or C, that we want the air temperature to be reported in?

@marcelveldt should we change and use the unit of the thermostat command class instead of the sensor command class, as the unit of the climate entity?

Side note: A device that reports different temperature features in different units seems like an anomaly.

Sounds to me like a good workaround. Somehow the unit is sometimes wrong in the payload from OZW.