Number 'out of range' when trying to adjust thermostat setpoint via MQTT -> Zwave

  • Platform information:

    • Hardware: Docker
    • OS: Docker
    • Java Runtime Environment: Not sure, hoping it’s not needed
    • openHAB version: 4.1.1
    • mosquito version 2.0.18
    • zwavejs2mqtt version 9.6.0
  • Device info

    • Thermostat model: GoControl GC-TBZ48

I decided to redo my openHab install. I had one before mostly working that used Z-wave to control lots of things, but as MQTT becomes more ubiquitous in the smart home ecosystem, I wanted to use MQTT as my primary bus to control all things via mosquito and zwavejs2mqtt. (I know that’s more of a Home Assistant thing, and it did work out of the box in HA, but I frankly like OH far more for various reasons.)

It’s taken months, but I think I’m 99% done. Most everything works: lights can be turned on and off, I’ve gotten my garage door communicating through MQTT (ditching the MyQ setup and moving to a ratgdo was actually the the impetuous for this change), and I can access my thermostats. Well, kinda.

Reading the various values and such works fine. I can see the temp, etc. I can even control Off / Heat / Cool modes from OH. But for some reason whenever I try to adjust the setpoint it fails to work. Nothing is sent to MQTT, and I get a fun error in OH:

0014:54:44.032 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'KitchenThermostat_Climate_Control_4x_Sensor_Zwavejs2mqtt_5F0xd8b47b39_5FNode5_5Fclimate_Temperature' received command 52
0014:54:44.033 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'KitchenThermostat_Climate_Control_4x_Sensor_Zwavejs2mqtt_5F0xd8b47b39_5FNode5_5Fclimate_Temperature' predicted to become 52
0014:54:44.036 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'KitchenThermostat_Climate_Control_4x_Sensor_Zwavejs2mqtt_5F0xd8b47b39_5FNode5_5Fclimate_Temperature' changed from 51 °F to 52 °F
0014:54:44.060 [ERROR] [nal.common.AbstractInvocationHandler] - An error occurred while calling method 'ThingHandler.handleCommand()' on 'org.openhab.binding.mqtt.homeassistant.internal.handler.HomeAssistantThingHandler@4352f228': 52 is out of range
00java.lang.IllegalArgumentException: 52 is out of range
00at org.openhab.binding.mqtt.generic.values.NumberValue.parseCommand(NumberValue.java:110) ~[?:?]
00at org.openhab.binding.mqtt.generic.ChannelState.publishValue(ChannelState.java:369) ~[?:?]
00at org.openhab.binding.mqtt.homeassistant.internal.HomeAssistantChannelState.publishValue(HomeAssistantChannelState.java:72) ~[?:?]
00at org.openhab.binding.mqtt.generic.AbstractMQTTThingHandler.handleCommand(AbstractMQTTThingHandler.java:153) ~[?:?]
00at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
00at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
00at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
00at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
00at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:147) [bundleFile:?]
00at org.openhab.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59) [bundleFile:?]
00at jdk.proxy90.$Proxy208.handleCommand(Unknown Source) [?:?]
00at org.openhab.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:95) [bundleFile:?]
00at org.openhab.core.thing.internal.profiles.SystemDefaultProfile.onCommandFromItem(SystemDefaultProfile.java:49) [bundleFile:?]
00at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
00at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
00at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
00at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
00at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:147) [bundleFile:?]
00at org.openhab.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]
00at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
00at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) [?:?]
00at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [?:?]

The most interesting part of that seems to be the 5th line, where it says “52 is out of range”. Thinking it was some sort of issue with OH trying to send a string instead of a number or vice versa, I experimented changing the item type from Number:Temperature to Number and String, but so far nothing seems to work. I’ve tried removing and re-adding the device. I’ve tried creating a custom rule and sending variations of “63”, 63, “63.0”, 63.0, etc.

Also, I think it should be a number anyway. As a test I spun up a Home Assistant container and added the thermostat. It successfully adjusted the setpoint no problem, and when I snoop the traffic sent over MQTT, I see the following:

Topic: homeassistant/Kitchen/Thermostat/thermostat_setpoint/endpoint_0/setpoint/1 QoS: 0
{
  "time": 1705337544491,
  "value": 54
}

That seems to be some good news at least. It looks like a number, and doesn’t seem to need any sort of horrible translation either. Now I just need to get OH to send it.

So, I’m currently at a loss. I’ve thrown everything I can think of at the wall but nothing has stuck. I don’t know what range OH seems to think the number should be in, or how I would adjust that setting since according to the MQTT event, normal ranges are expected by the thermostat anyway.

For completeness’ sake, here is the item definition:

"KitchenThermostat_Climate_Control_4x_Sensor_Zwavejs2mqtt_5F0xd8b47b39_5FNode5_5Fclimate_Temperature": {
    "class": "org.openhab.core.items.ManagedItemProvider$PersistedItem",
    "value": {
      "groupNames": [
        "KitchenThermostat_Climate_Control_4x_Sensor"
      ],
      "itemType": "Number:Temperature",
      "tags": [
        "Point",
        "Temperature"
      ],
      "label": "Kitchen Thermostat Setpoint",
      "category": ""
    }
  },

I expect I made some kind of newbie mistake here when adding the device, or there’s some sort of esoteric metadata I have to add someplace that a wizard knows of. Thanks in advance for any help you can provide, and thanks for reading my boring book.

Have you properly set the units of measurement for you temperature item? Celsius, I think is the default temp unit so if there’s a unit confusion your channel may be trying to send 52°C to a thermostat which one could imagine (or hope!) is in fact out of range for what the thermostat will accept.

For your issue look closely at the “config” for the limits as @JustinG suggests.

As an alternate I did not use the preconfigured homeassistant channels as I encountered problems and just used generic Mqtt items linked directly to the appropriate topic. My thermostat items from the UI Code tab

UID: mqtt:topic:f06f8352c2:Thermostats
label: Thermostats
thingTypeUID: mqtt:topic
configuration: {}
bridgeUID: mqtt:broker:f06f8352c2
location: Thermostats
channels:
  - id: Main_Floor_Thermostat_Mode_n
    channelTypeUID: mqtt:number
    label: Main Floor Thermostat Mode
    description: null
    configuration:
      formatBeforePublish: "%.0f"
      commandTopic: zwave1/62/64/0/mode/set
      stateTopic: zwave1/62/64/0/mode
  - id: Upstairs_Thermostat_Mode_n
    channelTypeUID: mqtt:number
    label: Upstairs Thermostat Mode
    description: null
    configuration:
      formatBeforePublish: "%.0f"
      commandTopic: zwave1/63/64/0/mode/set
      stateTopic: zwave1/63/64/0/mode
  - id: Main_Floor_Thermostat_Status_n
    channelTypeUID: mqtt:number
    label: Main Floor Thermostat Status
    description: null
    configuration:
      stateTopic: zwave1/62/66/0/state
  - id: Upstairs_Thermostat_Status_n
    channelTypeUID: mqtt:number
    label: Upstairs Thermostat Status
    description: null
    configuration:
      stateTopic: zwave1/63/66/0/state
  - id: Main_Floor_Heating_Setpoint_n
    channelTypeUID: mqtt:number
    label: Main Floor Heating Setpoint
    description: null
    configuration:
      commandTopic: zwave1/62/67/0/setpoint/1/set
      unit: °F
      min: 60
      formatBeforePublish: "%.0f"
      stateTopic: zwave1/62/67/0/setpoint/1
      max: 70
  - id: Upstairs_Thermostat_Setpoint_Heat_n
    channelTypeUID: mqtt:number
    label: Upstairs Heating Setpoint
    description: Upstairs Heating Setpoint
    configuration:
      commandTopic: zwave1/63/67/0/setpoint/1/set
      unit: °F
      min: 60
      formatBeforePublish: "%.0f"
      stateTopic: zwave1/63/67/0/setpoint/1
      max: 70
  - id: Upstairs_Cooling_Setpoint_n
    channelTypeUID: mqtt:number
    label: Upstairs Cooling SetPoint
    description: null
    configuration:
      commandTopic: zwave1/63/67/0/setpoint/2/set
      unit: °F
      min: 69
      formatBeforePublish: "%.0f"
      stateTopic: zwave1/63/67/0/setpoint/2
      max: 80
  - id: Main_Floor_Cooling_SetPoint_n
    channelTypeUID: mqtt:number
    label: Main Floor Cooling Setpoint
    description: null
    configuration:
      commandTopic: zwave1/62/67/0/setpoint/2/set
      unit: °F
      min: 70
      formatBeforePublish: "%.0f"
      stateTopic: zwave1/62/67/0/setpoint/2
      max: 80

Have you properly set the units of measurement for you temperature item? Celsius, I think is the default temp unit so if there’s a unit confusion your channel may be trying to send 52°C to a thermostat which one could imagine (or hope!) is in fact out of range for what the thermostat will accept.

I don’t see it in the item config, but when I look at the UI, it does say the Dimension is Temperature (F) so I think it’s correctly set?

For your issue look closely at the “config” for the limits as @JustinG suggests.

I tried adding min and max values to my item code. Although it saved, when I went back in after testing I noticed they were removed. Regardless, it didn’t seem to do anything, so maybe I did it wrong. I don’t see anything in the docs that mentions this or what keys are valid.

I did try to add the setpointRange metadata as suggested by the Alexa documentation, which I found after searching for “range”. It didn’t seem to do anything either though. Same error, anyway.

It will be in the channel, not the item. I pulled this out (default)-yours could be different of zwavejs2mqtt.

	// Thermostat/HVAC https://www.home-assistant.io/components/climate.mqtt
	thermostat: {
		type: 'climate',
		object_id: 'climate',
		discovery_payload: {
			min_temp: 5,
			max_temp: 40,
			temp_step: 0.5,
			modes: [],
			mode_state_template: '{{ value_json.value }}',
			current_temperature_topic: true,
			current_temperature_template: '{{ value_json.value }}',
			temperature_state_topic: true,
			temperature_state_template: '{{ value_json.value }}',
			temperature_command_topic: true,
		},
	},

As noted above I’m not using them but IIRC this is how you can get a look.
Channel details 2024-01-16 094752

The default temp is based on your regional settings. If SI units is selected default is °C. If Imperial units is selected default is °F.

Settings → Items → TemperatureItem → Add Metadata → Unit

Item metadata is stored separately from the Item. You need to pull it separately from the REST API if that’s how you are looking.

Are your Items managed or defined in .items files?

I suspect that @apella12 is on the right track. For grins, try commanding the Item to something reasonable in the Celsius range (like 20). If that works that will confirm that there is a bug in the HomeAssistant discovery on that Channel. It’s treating it as Celsius and has some built in range checking.

To work around it you’ll need to create a Generic MQTT Channel where you can fix these problems. Also file an issue.

I’d also add that the docs note that the HA climate is not supported.

If by managed you mean I set them up via the UI, then yes. I feel like this is going to be biting me in the bum later on in this reply…

Oh hey, that worked! Thank you for that, it’s the first real bit of progress I’ve had on this. I was a bit surprised by this as it even says in the logs that it’s using °F but I guess some other part isn’t getting the message.

I guess that’s why setting the unit in the metadata isn’t working either. It’s already using the right unit, just not everywhere.

Huh, I was expecting something like one of those transformations. But now that I read more up on it, I guess those are only for making things human readable, not for changing the value of something being output. If that even made any sense.

…And this feels like the point where not using .items files is going to haunt me forever.

I see you mentioned a generic MQTT Channel, and not item. Is this where using text files is easier? I don’t see the ability to make a custom channel if the Thing is the MQTT broker, and picking the thermostat Thing just gives me the already created channels to link to. I presume I’ll have delete this and create a brand new generic MQTT thing like @apella12 suggested. As somebody who’s limped along in OH so far only creating stuff using the UI, this is scary to me for some reason. Well, actually, I’m guessing it’s because firing up vim or some other text editor and just hoping I get all those keys right is going to be impossible. Intellisense has ruined me I guess.

Oh crap. My apologies everyone. I do remember reading that page and I think I only saw dimmers and such, which I have none of, and then happily stopped reading? Well, now I feel like an ass.

@rlkoshak do you think it still makes sense to open an issue on this when it’s already documented as not being supported?

The file I posted above was created in the UI, no vim editing. The only helpful tool is MQTT explorer. An outline

  1. From things, hit plus (+), choose generic MQTT thing, fill in labels “thermostat” and link to your MQTT broker, save
  2. Go channels tab of thing, add channel (say number value)
  3. Go to MQTT explorer, expand, find topic and copy, then paste into state topic
  4. Repeat (add /set for the command topic -if applicable- Air Temp is not settable)
  5. If you have multiple thermostats, after doing one, I found it easier to cut and paste from the UI thing code tab

Check out the file above for reference (unfortunately for a reference I used the ZUI “just value” to avoid using the JSON transform, so yours will look a different (49 = SENSOR_MULTILEVEL)

I’m guessing it’s the binding.

Not at all. In a lot of ways creating a managed Thing is easier because you don’t need to research the names of the properties nor do you need to fight with syntax errors.

Yes.

Stay using the UI. The Advanced Things page shows the creation of a Generic MQTT Thing step-by-step through the UI.

Probably not. If it’s documented then the developers already know it’s a limitation.

This is a helpful tool. Using this, the documentation available in OH, and your very helpful post, I managed to recreate the Thing using the generic MQTT binding. You all were right; it wasn’t as bad as I feared. =)

And would you be surprised to learn that everything works pretty easily except for adjusting the setpoint, leaving me back to where I started?

Before I get into this, I wanted to say thinks to everyone. You, and @rlkoshak especially for going above and beyond in your thoughtful responses, images, and hand holding. I appreciate it immensely. I marked the post above as a solution that seemed to most hit the nail on the head at the beginning.

I don’t know if what I’m currently tackling is an OH problem or not. It might just be a config issue on my broker, or maybe in zwavejs2mqtt, although I kinda doubt that one. Or even more likely, I don’t understand MQTT as much as I thought I did. Given that, I totally understand if this is no longer the place for this discussion. If so, I’ll close this topic.

Log story short, MQTT Explorer gave me more questions than answers. I think I need to reconfigure something, possibly start from scratch. But before I do, I want to learn what I did wrong so I can do it right next time.
image

Why the heck do I have both a zwave prefix and a homeassistant prefix? I can understand the HA prefix, as that is what is currently configured in zwavejs2mqtt. But zwave? I truly have no idea where that is coming from. Even more confusing, is the topics in the zwave prefix seem to be getting some, but not all, messages. Weird, but I guess this isn’t my primary concern as I can just ignore it and use the HA prefix still. I only put that here in the spirit of supplying all info when asking a question.

More concerning is that the setpoint still isn’t working. After doing a day’s worth of debugging on it, I think the issue is that OH isn’t sending ‘lastActive’ messages. For example:

This is me setting the setpoint through HA, which works:

Here is me manually pushing the up/down arrows on the device itself:
Screenshot_20240118_144229

And here is me trying to set it in OH, which doesn’t update the thermostat:
Screenshot_20240118_143441

The topic is the exact same. The value is the same format. Everything seems to be the same, except for the ‘lastActive’ timestamp that bracket every request. I don’t know if this is actually the problem, but it’s the only difference I see (aside from the fact HA sends the command twice for some reason. I tried doing that in OH too but it made no difference). Looking at commands sent to other devices such as lightswitches, they all get bracketed by lastActive messages too, in both HA and OH, although that’s when using the HomeAssistant MQTT Component Thing Type, so I guess it might just be a HA thing.

Digging through the docs and advanced options, I see no mention of timestamps or lastActiv, required or no. Heck, I don’t even see it when searching in these forums or generally online… which makes me think I’m barking up the wrong tree here. But it’s the last noodle in the box.

I did try sending commands to the device via the zwave prefix, but so far nothing seems to work when I try that.

If anybody has a clue what is going on here, I would greatly appreciate the insight!

Well you are not in Kansas anymore. Forget HA regarding the Thermostat, you are in OH land. You have a hybrid situation. Some items are using the HA configs as channels but the thermostat is not.

To get right to the issue.
First you need to use the zwave section for your generic OH thing states (and set). Note my topics (I have zwave1, not zwave).

Copy the code tab for your generic Mqtt thing

, so we can see what you did. I’m just using numbers not named topics, so it could be a little hard to follow, but try to find this (with names that make sense) in the Zwave (Basement?) portion of your explorer.
thermo 2024-01-18 181353

Edit: Look at this post for reference Test: Zwave-JS-UI in place of Zwave binding - Tutorials & Examples / openHAB Stories - openHAB Community

What does zwave2mqtt publish when it’s not configured to use the HA standard? Given the number of messages, maybe it publishes to both its own standard and the HA standard?

I don’t think that’s relevant at all and furthermore I think that’s something that zwave2mqtt needs to publish, not something OH publishes. The Zwave binding keeps track of last active on the Thing.

The one thing that MqttExplorer isn’t going to tell you is who published a message, unfortunately.

I know nothing of the HA standard for MQTT but I know when I’ve set up stuff like this with my own topics and in the Homie standard, the topic that you publish to to command a device is separate from the topic that zwave2mqtt will publish to report a change in status.

Are you sure you are not seeing the command and then the device reporting its new state?

1 Like

This is true. In fact the HA “config” uses the topic in the zwave section to get the value. The Zwave section has the ring that rules them all :wink:.

Here is part of a Motion HA config: Note the embeded state topic is from the Zwave section.

{
  "payload_on": true,
  "payload_off": false,
  "value_template": "{{ value_json.value }}",
  "state_topic": "zwave/3/48/0/Motion",
  "json_attributes_topic": "zwave/3/48/0/Motion",
  "device": {
    "identifiers": [
      "zwavejs2mqtt_0xd2818a75_node3"
    ],
2 Likes

Lol. I appreciated the humor. Thankfully, it didn’t turn out nearly that bad as I feared after reading your reply. Of course, I only discovered that after basically deleting everything and starting from scratch. :smiley:

So, just for those who maybe find this thread for later, or for those that followed this saga and want a conclusion:

  1. The HomeAssistant stuff was showing up in MQTT explorer I think because there were some old Retained messages stored in the broker. After wiping the mosquito container and starting fresh, they all mostly went away. Mostly.
  2. I think my main issues with sending commands to devices via MQTT from OH was zwavejs2zwave wants you to send things to $topic\set if you want to actually change something. This is rather buried in the documentation for it considering how insanely important this is. Stupid me thought I could simply look at the MQTT messages that get sent when things change, and send new values to that same topic. What a silly goose I am. As soon as I started using the suffix /set everywhere, stuff started working.

Time to redo everything in OH now that I have something that works! Thank you all for your help and patience. You not only helped educate, but convinced me it was something doable. That was huge, and I appreciate it.

1 Like

As a general rule, when dealing with MQTT, the there will be a separate topic to command a device and for the device to report it’s current state. This is for a lot of reasons but primarily:

  1. it’s easy to get into an infinite loop
  2. who is publishing the message is not part of the message, there’s no way to distinguish between something asking a light to turn on and the device reporting that it has turned on, if there are not separate tropics

I just wanted to make it clear why there are are two topics. Sometimes understanding why is important to working with a technology.

1 Like

That… makes a metric ton of sense. It truly was I that was the silly goose.

And you’re right- knowing the why is important. For me in this scenario, it will likely ensure I’ll never forget the lesson as now it wouldn’t make sense any other way. Thanks!