OH 4.2.2 refuses to communicate with Heatit thermostats

Hi,
I moved from OH 3.4.2 to OH 4.2.2 on a RPi4B+, but lost contact with Heatit thermostats.

Here is what I did:
Ran RPi Imager and loaded openhabian (for OH 4.2.2) to SD Card and powered up.
Removed Astro and Z-Wave Bindings and installed the 4.2.2 version to be up to date.
Restored system using the latest OH 3.4.2 …-cli Backup file.
All devices worked fine based on log entries, but (my feet) discovered that Heatit refused to accept commands.

Returned to OH 3.2.4 for a system integrity test. All good and Heatit accepted commands again.

Is Heatit missing from the Z-Wave binding or … ???
Suggestion anyone?

It’s likely you need to adjust your procedures. When you restore upgrade procedures are not performed. OH 3.4 to 4.2 is a pretty big jump and IIRC there have been changes in Things.

You can try to run java -jar /usr/share/openhab/bin/upgradeTool.jar after restoring the 3.4 backup. That’s not always guaranteed to work but it’s worked for others in the past.

The most fullproof approach is to initially install the same version of OH to the new image as your backup (3.4.2 in this case) and then upgrade OH after restoring your backup. That ensures the full set of automated upgrade procedures are performed by apt and the upgradeTool.jar.

Thanks Rich, good as always!
I worried you were going to say that, as I’m running 3.4.2 off a 16G SD which of course is the one with the highest capacity of all my 16Gs.
Is openhabian for 3.4.x still available for a fresh setup on a smaller SD or is it discontinued? I would prefer to build a copy first so I have a fallback.

Every version of OH since 2.5.12 is available in the apt repo.I’m not sure how to shoose the verison of OH to install through openhabian-config but believe there is a way. If not you can do it from the command line with apt.

Did that, but Heatit still not friendly. Commands are visible in log but not reaching Heatit.
Suggestions anyone?

Could this be a Z-Wave Binding Heatit Firmware issue?

Is the Thing ONLINE?

OH yes, all Things are ON Line.
Made a new test with PROD 3.4.2 → 4.2.2 using config 03, but Heatit ignored again.
Back at 3.4.2 now, and all is good.
Must be an update issue of some kind (my guess)?

What is the type:ID pair in the properties dropdown on the UI page? I could check the DB history, but there are several Heatit models.

Also a zwave debug log of the working version might help.

Two models in use: Z-TRM2fx zwave_deviceid 514, and Z-TRM3 zwave_deviceid 515.
Debug logging is outside my comfort zone.

The good news is that I do not see any changes in the Zwave DB after OH2.5 for those devices. The bad news is that all the diagnostic information to possibly determine the issue is at the debug level. Event and info level logs are not helpful. Also since I don’t see any device changes, a comparison between working and non-working debug is now needed.

In OH4 ZW debug is easy, from the UI setting tab, on the right is addon settings, find zwave in the list, click and change to debug. Do your setpoint command, then change back to info. You can post the log here using code fences. Try that first.

IIRC on OH3.4 you have to change the log level in karaf. The instructions are here; near the bottom where it says,

If things do not go as planned

Thanks Bob :slightly_smiling_face:
I’ve spent way too much time on this stupid issue already, so I’ll see what I can do. karaf is also new to me.

I have decided to stay on OH 3.4.2 for now and not play with that PROD unit any more.
I suggest relevant people compares OH3 and OH4 Heatit related code.
Since everything looks OK in the events.log it seems like commands are simply not forwarded to the radio link.

Hi Bob,

I finally got a Test RPi4B going and here are the Heatit Z-W test results:

Entrance Thermostat Setpoint prior to test: 25.1 deg
Command sent to change Setpoint to 26.1 deg

Log results:
2024-11-29 11:58:19.201 [INFO ] [openhab.event.RuleUpdatedEvent      ] - Rule '5b57f4d89c' has been updated.
2024-11-29 11:58:33.507 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'FF_Entrance_Setpoint' received command 26.1
2024-11-29 11:58:33.509 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'FF_Entrance_Setpoint' predicted to become 26.1
2024-11-29 11:58:33.512 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'FF_Entrance_Setpoint' changed from 25.1 to 26.1
==> /var/log/openhab/openhab.log <==
2024-11-29 11:58:33.517 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 35: Command received zwave:device:d5fd2f9335:node35:thermostat_setpoint_heating1 --> 26.1 [DecimalType]
2024-11-29 11:58:33.518 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 35: Received commands datatype DecimalType couldn't be converted to channels datatype QuantityType
2024-11-29 11:58:33.519 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 35: Command for unknown channel zwave:device:d5fd2f9335:node35:thermostat_setpoint_heating1 with DecimalType
2024-11-29 11:58:55.045 [DEBUG] [WaveSerialHandler$ZWaveReceiveThread] - Receive Message = 01 12 00 04 00 0C 0A 32 02 A1 64 00 03 90 00 00 00 D0 00 59 
2024-11-29 11:58:55.047 [DEBUG] [nal.protocol.ZWaveTransactionManager] - processReceiveMessage input 0<>128 : Message: class=ApplicationCommandHandler[4], type=Request[0], dest=12, callback=0, payload=00 0C 0A 32 02 A1 64 00 03 90 00 00 00 D0 00 
2024-11-29 11:58:55.049 [DEBUG] [nal.protocol.ZWaveTransactionManager] - Received msg (0): Message: class=ApplicationCommandHandler[4], type=Request[0], dest=12, callback=0, payload=00 0C 0A 32 02 A1 64 00 03 90 00 00 00 D0 00 
2024-11-29 11:58:55.050 [DEBUG] [nal.protocol.ZWaveTransactionManager] - lastTransaction null

Apparently a datatype issue?
My Setpoint Item is declared as Number and works fine in OH3.4.2, so why QuantityType now, and how can I fix it?
Is QyantityType also a Number?
Thanks.

I can’t answer the why now question. The Zw DB hasn’t changed in this area, but there have been more rigorous checks introduced by the core on some things. Don’t know if this is a reason.

Anyway, solution is to modify the item to Number:Temperature (or create a new item with that), and yes QuantityType is a subset of number.

Thanks,
So my take from this then is:
When I define an Item as Number in OH4 I cannot always trust it to be a Number, meaning I’m not in charge here.
Odd!!

It’s really quite the opposite. You couldn’t really on that in OH 3. You could define an Item as a Number and end up with a Quantity type and when you had a QuantityType it was sometimes challenging to know what unit the Item was in.

In OH 4 if you define the Item as a Number, it will never be a QuantityType. If something updates it with a QuantityType that update will first be converted to a DecimalType (no units). If something updates a Number:Temperature (for example) with a DecimalType, that value will be converted to a QuantityType using the unit as the unit.

The unit for the Item can be set through the unit metadata. If an update is sent to an Item with a different unit, the value will be converted to unit before the Item is updated.

You have full control over whether QuantityTypes are used at all and what unit is used when you choose to use a QuantityType. More details can be found in the breaking changes section of the release notes for OH 4.0.

Given all of this, the Zwave binding is in error here and should have an issue filled. When it receives a DecimalType, it should convert it to a QuantityType assuming the system default unit.

This is probably what is causing the issue, but it is not obvious to me how to accomodate a Number when the device needs to know the units. I think the item-type needs to match the channel-type

tl;dr == The zwave thermostat_setpoint channel is defined as a Number:Temperature. The Zwave protocol for this command class includes the scale (F or C) with the value so the device is sending or receiving a QuantityType

<!-- Heating Setpoint Channel -->
<channel-type id="thermostat_setpoint">
<item-type>Number:Temperature</item-type>
<label>Heating Setpoint</label>
<description>Sets the thermostat setpoint</description>
<category>Heating</category>

Prior to OH4 (the Zwave code hasn’t changed here), the ThingHandler tried to accommodate users that linked a number item to a Number:Temperature channel by changing it to a Quantity, I believe with this section of code;

        Class<? extends State> targetStateClass = channelDataType.getTypeClass().asSubclass(State.class);

        State convertedState = ((State) command).as(targetStateClass);

        if (convertedState == null) {
            logger.debug("NODE {}: Received commands datatype {} couldn't be converted to channels datatype {}", nodeId,
                    dataType, channelDataType);
            return null;
        }

My guess is OH4 eliminated the subclass of Number under Number:Temperature and now the converted state returns null and triggers the log entry;

2024-11-29 11:58:33.518 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 35: Received commands datatype DecimalType couldn't be converted to channels datatype QuantityType

The overall code that includes the above subroutine is

        // first try to get a channel by the expected datatype
        ZWaveThingChannel cmdChannel = cmdChannels.get(dataType);

        if (cmdChannel == null && !cmdChannels.isEmpty()) {
            // nothing by expected datatype found, try to find one where the datatype can be converted to
            for (ZWaveThingChannel channel : cmdChannels.values()) {
                command = convertCommandToDataType(channelUID, channel.getDataType(), command, dataType);
                if (command != null) {
                    cmdChannel = channel;
                    logger.debug("NODE {}: Received command {} was converted --> {} [{}]", nodeId, channelUID, command,
                            command.getClass().getSimpleName());
                    break;
                }
            }
        }

        if (cmdChannel == null) {
            logger.debug("NODE {}: Command for unknown channel {} with {}", nodeId, channelUID, dataType);
            return;
        }

This checks for dataType (in this case Number:temperature), then tries the subroutine that used to accept Number, then logs that there is no channel for Number.

2024-11-29 11:58:33.519 [DEBUG] [ding.zwave.handler.ZWaveThingHandler] - NODE 35: Command for unknown channel zwave:device:d5fd2f9335:node35:thermostat_setpoint_heating1 with DecimalType

Thanks Rich,
Yes, I can agree to that. I prefer Number that can be used in subsequent arithmetic.

I guess I have to accept QuantityType for now, so
could I ask you guys to please lend me a minute and show me how to change the attached DSL code lines to make them work with QuantityType? Trigger is every hour.
Would be very much appreciated.
Bjorn

  var Number temp = MS6_Ga_temperature.state as Number
  var newCase = 0

// Temp windows             Vaca  <-10  -10-0 0-10  10-20 >+20
// newCase                  0     1     2     3     4     5
val arrayBa2 = newArrayList(20.1, 31.1, 30.1, 29.1, 28.1, 25.1)

  if( vacation ) { ... }

  else {
    if((temp <= -10.0) && (newCase != 1)) { newCase = 1 }
    else if((temp > -10.0) && (temp <= 0.0) && (newCase != 2)) { newCase = 2 }
    else if((temp > 0.0) && (temp <= 10.0) && (newCase != 3)) { newCase = 3 }
    else if((temp > 10.0) && (temp <= 20.0) && (newCase != 4)) { newCase = 4 }
    else if(temp > 20.0 && (newCase != 5))  { newCase = 5 }
  }

  var tempBa2 = arrayBa2.get(newCase)

  if(SF_Bath_Setpoint.state != tempBa2)      { SF_Bath_Setpoint.sendCommand(tempBa2) }

Here is a tutorial I have used and an example (It is in DSL);

rule "Bedtime_Main_Heat"
when
    Time cron "0 05 21 ? * * *"
then
    val mode = Downstairs_Mode.state
    var upstate = UpstairsThermostat21_ThermostatOperatingState.state as Number
    var mainmode = MainThermostat14_ThermostatMode.state as Number
    var maintempset = (MainThermostat14_SetpointHeating.state as QuantityType<Temperature>).toUnit("°F")
    if( mainmode == 1 && mode != 'Vacation' ) {
        if(upstate != 1 && maintempset != 65|°F) {
            MainThermostat14_SetpointHeating.sendCommand(65)
        }
        if(upstate == 1 && maintempset != 66|°F) {
            MainThermostat14_SetpointHeating.sendCommand(66)
        }
    }
end

The changes made to handleing uinits expilicitely were to give the end user the ability to choose whether to use units or not instead of having the requirement to use units forced upon them by the add-ons.

If a DecimalType is receivd by the the add-on and it needs to know the units, it should assume the system default unit which will depend on the regional settings.

And that ended up with the end user having a Number Item that is actually carrying a QuantityType instead of a DecimalType. If they tried to use the state of that Item in a Rule, they’d be forced to deal with units even though they explicitely indicated they do not want to use units by defining it as a Number Item in the first place.

That is no longer allowed to happen. If the user defines the Item as a Number, that Item will only carry a DecimalType. If a QuantyType is passed, the unit is stripped and the Item ends up with a DecimalType. No longer is it possible for a Nunber Item to suddenly become a Number:Temperature Item through an update.

It’s a little bit awkward in Rules DSL but as @apella12 shows, it’s usually easiest to stick to using units where units are involved.

  var temp = MS6_Ga_temperature.state as QuantyType
  var newCase = 0

// Temp windows             Vaca  <-10  -10-0 0-10  10-20 >+20
// newCase                  0     1     2     3     4     5
val arrayBa2 = newArrayList(20.1, 31.1, 30.1, 29.1, 28.1, 25.1)

  if( vacation ) { ... }

  else {
    if((temp <= -10.0|°C) && (newCase != 1)) { newCase = 1 }
    else if((temp > -10.0|°C) && (temp <= 0.0|°C) && (newCase != 2)) { newCase = 2 }
    else if((temp > 0.0|°C) && (temp <= 10.0|°C) && (newCase != 3)) { newCase = 3 }
    else if((temp > 10.0|°C) && (temp <= 20.0|°C) && (newCase != 4)) { newCase = 4 }
    else if(temp > 20.0|°C && (newCase != 5))  { newCase = 5 }
  }

  var tempBa2 = arrayBa2.get(newCase)

  if(SF_Bath_Setpoint.state != tempBa2)      { SF_Bath_Setpoint.sendCommand(tempBa2) }

In JS Scripting, jRuby, and Blockly, you can ask for the state of an Item as a String, number, or quantity depending on what you want to to use in the rule instead of needing to do any casting or conversions yourself.

Thanks a million for your time.

Wow, that sounds scary, and may potentially have huge code consequences. Does this mean that the freedom to define an Item Type basically disappeared completely with OH4? I’m not sure I fully understand the consequences here.

Now, back to my code. I have a hunch:
If Z-W thermostats now require QuantityType then the following statement in my code is questionable and should be tuned as follows.

if((SF_Bath_Setpoint.state|°C) != tempBa2)      { SF_Bath_Setpoint.sendCommand(tempBa2) }

I added |°C in the if-part, but how can I make tempBa2 a QuantityType in the Command-part?
The following quote says it works with just a Number, right?

In addition I would have to redefine my items to Number:Temperature.

Season greetings :slightly_smiling_face: