State update to a Thing channel via MQTT - what to do if state update is triggered, but I miss the state information?

Hi,
I have physical device with two A/C relays which can be controlled through MQTT (the device runs Espurna firmware).
That device gives status updates with a JSON payload:

'{"relay/1":"1","relay/0":"0","vcc":"3145","time":"2020-05-04 23:38:31","id":444192}'

The relay/x part indicates if that relay is on (1) or off (0). Status updates may contain only relay/0, only relay/1 or both or none of them (depends when a relay had its last activity).

I have set up my switches as things this:

Type switch : switch05_0 "ESP Switch 05 Relay 0" [ stateTopic="wohnung/switch5/data", commandTopic="wohnung/switch5/relay/0/set", transformationPattern="JS:EspurnaRelay0.js", allowedStates="ON,OFF" ]
Type switch : switch05_1 "ESP Switch 05 Relay 1" [ stateTopic="wohnung/switch5/data", commandTopic="wohnung/switch5/relay/1/set", transformationPattern="JS:EspurnaRelay1.js", allowedStates="ON,OFF" ]

The JavaScript transform allows me to see if the JSON contains the relay/0 respectively relay/1 and to react on that.

(function(i) { 
  var jsonElementToFind = "relay/0";
  var returnIfNotFound = "UNDEF";
  var arrOffOn = ["OFF", "ON"];  

  var jsonData = JSON.parse(i);
  var hits = jsonData[jsonElementToFind];
  
  if (hits != null)
    return arrOffOn[hits[0]];
  //else
    //return returnIfNotFound;
})(input)

My problem: I do not know how to handle the case, that a JSON was received, but does not contain information which would allow me to update the switch state. With the JS above, I tried to return "UNDEF", "" (empty string), nothing - but all of that results in an error:

2020-05-05 10:03:32.894 [WARN ] [ab.binding.mqtt.generic.ChannelState] - Command 'null' not supported by type 'OnOffValue': No enum constant org.eclipse.smarthome.core.library.types.OnOffType.null

That would be the “right” thing to do, assuming you want to positively indicate “don’t know” or “broken” to your Item, and not let the last good value stand.

What’s that? There is no allowedStates= parameter for an MQTT Thing? Can’t just make syntax up.
I think it’ll just get ignored, though.

If it did work, it would of course filter out attempts to set UNDEF …

I think you have run into a binding limitation here.

For switch (and contact) type channels, this binding has a mini-transform capability for the binary states e.g. the parameters on=“1” etc.
This is happening behind the scenes as well as your custom transform.
By default, these will pass your ON/OFF strings and convert to OnOffType to pass to Item state.
I think there’s an oversight, and no way to allow an UNDEF through the mini-transform, Technically it needs to end up an UnDefType I reckon, so it blows up because UNDEF does not “fit” into an OnOffType.

I believe what you are trying to do is entirely sensible, and you should raise an enhancement request against the MQTT binding for the on= off= code to allow UNDEF to pass through.

That all assumes you want to set your Item UNDEF when the MQTT JSON info is missing.
If instead, you want to ignore the MQTT message (and keep last Item state) you should look into chaining REGEX to your JS transform.

What’s that? There is no allowedStates= parameter for an MQTT Thing? Can’t just make syntax up.

:blush: wishful thinking…

But more importantly:

That would be the “right” thing to do, assuming you want to positively indicate “don’t know” or “broken” to your Item, and not let the last good value stand.

Thanks for pointing me back into the right direction: what I do want to achieve was to not send an update and keep the current state.
Pointing me to the REGEX and the possibility of chaining transformations solved my problem.

I am using the following REGEX:

Type switch : switch01_0 "ESP Switch 01 Relay 0" [ stateTopic="wohnung/switch1/data", commandTopic="wohnung/switch1/relay/0/set", transformationPattern="REGEX:.*\"relay/0\":\"(.*?)\".*" ]

As it turns out, I don’t need to chain anything more to it:

  • the 1 and 0 which are coming back when "relay/0" is contained in the JSON set the switch as expected
  • if "relay/0" is not contained, I don’t get any error messages any more

A warning to anybody else who has to fiddle with this kind of change on an MQTT thing channel:
The binding is really reluctant to read changes from the file (I had to work the REGEX out char by char, so changes to that channel were really small).
What helped me a lot, was to rename the channel I was working on with every change (I just appended and incremented a number ending up with switch01_0_37 when I finished).

1 Like

Useful reminder !

Top tip; set up a temporary string Item for the whole MQTT payload; refine your transform(s) in a rule before applying to real channel.

1 Like

That sounds excellent! Will definitely use that the next time, all that renaming nearly drove me nuts!