[ST Edge] Issues with Temperature capabilities on Z-Wave devices

There’s a bug in the default zwave capability handlers for ThermostatCoolingSetpoint.setCoolingSetpoint and ThermostatHeatingSetpoint.setHeatingSetpoint. The code for both assumes that the setpoint passed to it is in Celsius, and then converts the setpoint to Fahrenheit if the device has indicated it uses F. My location is set to F, so the app is sending setpoint in F to the handler. The handler is then pretending that that F temperature is C and converting it to F. For example, in the logs below it’s treating 74F as if it’s 74C, then converting that to 165F.

2021-10-31T13:33:30.950709179+00:00 INFO Z-Wave Thermostat  <ZwaveDevice: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx [5B] (Trane Thermostat)> received command: {"command":"setCoolingSetpoint","args":{"setpoint":74},"positional_args":[74],"capability":"thermostatCoolingSetpoint","component":"main"}
2021-10-31T13:33:30.965758179+00:00 INFO Z-Wave Thermostat  <ZwaveDevice: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx [5B] (Trane Thermostat)> sending Z-Wave command: {args={scale="FAHRENHEIT", setpoint_type="COOLING_1", value=165}, cmd_class="THERMOSTAT_SETPOINT", cmd_id="SET", dst_channels={}, encap="AUTO", payload="\x02\x0A\x00\xA5", src_channel=0, version=1}

Thanks for bringing this up to our attention, @philh30! Allow me some time to review this issue and I’ll get back to you

1 Like

ok, I’ve been reviewing the default handler of the capabilities ThermostatCoolingSetpoint and ThermostatHeatingSetpoint and the temperature scale that is sent to the Z-Wave device (from SmartThings) depends on the scale received in the ThermostatSetpoint reports.

You should have a log similar to this one (this is from a device that uses TemperatureMeasurement so, maybe some IDs change):

driver-name <ZwaveDevice: xxxx-xxx-xxx [6E] (device-name)> received Z-Wave command: {args={precision=1, scale="FAHRENHEIT", sensor_type="TEMPERATURE", sensor_value=74.8, size=2}, cmd_class="SENSOR_MULTILEVEL", cmd_id="REPORT", dst_channels={}, encap="S2_AUTH", payload="\x01\x2A\x02\xEC", src_channel=0, version=1}

It can be easily identified from the other events with the cmd_id="REPORT", please check which scale is reported there.

The thermostat is reporting everything in Fahrenheit:

2021-11-03T00:59:19.277941455+00:00 INFO Z-Wave Thermostat  <ZwaveDevice: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx [5C] (Thermostat)> received Z-Wave command: {args={precision=0, scale="FAHRENHEIT", setpoint_type="HEATING_1", size=1, value=71}, cmd_class="THERMOSTAT_SETPOINT", cmd_id="REPORT", dst_channels={}, encap="NONE", payload="\x01\x09\x47", src_channel=0, version=1}
2021-11-03T00:59:19.394928789+00:00 INFO Z-Wave Thermostat  <ZwaveDevice: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx [5C] (Thermostat)> received Z-Wave command: {args={precision=0, scale="FAHRENHEIT", setpoint_type="COOLING_1", size=1, value=74}, cmd_class="THERMOSTAT_SETPOINT", cmd_id="REPORT", dst_channels={}, encap="NONE", payload="\x02\x09\x4A", src_channel=0, version=1}

The error is caused a little lower, below starts at line 51 of thermostatHeatingSetpoint.lua:

local function set_heating_setpoint(driver, device, command)
  local scale = device:get_field(constants.TEMPERATURE_SCALE)
  local value = command.args.setpoint
  if (scale == ThermostatSetpoint.scale.FAHRENHEIT) then
    value = utils.c_to_f(value) -- the device has reported using F, so set using F
  end

For my case, scale is Fahrenheit based on the prior ThermostatSetpoint reports, and command.args.setpoint is sent as 74F from the app since my location is set to Fahrenheit. The If statement is tripped, then line 55 treats my setpoint as 74C and converts to 165F. I think the solve is to check the location scale and only call a conversion if there’s a mismatch. I’d also note that the current code doesn’t handle a Celsius location communicating with a Fahrenheit device.

In the driver linked below, I edited the set_heating_setpoint and set_cooling_setpoint functions (lines 66 through 117) and it’s now working in my setup of F location / F device.

You’re right, I’ll report this behavior right away.

Actually, it is sent as Fahrenheit because of the unit in the capability. Currently, there’s an issue with these two capabilities because they don’t follow the unit set in the location, only the one received from the events. This means that you could send the events with the “C” unit and it wouldn’t be automatically converted according to your location. Here’s the related post as a reference: