MQTT switch help

I am trying to create a switch item that controls a relay using Mqtt but also displays if its on or off.
I can get the sitemap switch to control the relay.
I can receive the status that the relay has been changed back from the device.
What I would like to do is have the switch state default to the current state of the relay.

Currently I am bodging by having a switch item and then a number item giving the status.this works but is not neat. My code is:
Items file
Switch CORelay "Conservatory Switch" <switch> (Conservatory) { mqtt="<[broker:jpfy/house/relay/CO/Recieve:state:default],>[broker:jpfy/house/relay/CO/SEND/:command:ON:1],>[broker:jpfy/house/relay/CO/SEND/:command:OFF:0]" } Number CORelayStatus "Conservatory Relay Status [%d]" <terrace> (Conservatory) { mqtt="<[broker:jpfy/house/relay/CO/Recieve:state:default] " }

Sitemap
Switch item=CORelay Text item=CORelayStatus

Any advice would be greatly appreciated.

This sounds like a job for @bob_dickenson’s Proxy Design Pattern discussed here.

You create a Proxy Item that you put on your sitemap to represent the state of the switch. Then you create rules that trigger on the Proxy Item and relays state changes to your CORelay. You set up other rules to receive state changes from the relay and postUpdate changes back to the Proxy Item so it represents the current state.

Thank You
I am still struggling a bit.
I have tried the following code but am not having any success
With the proxy item should it be?
Switch proxyconrelay "COProxy" <switch>
Or do I need a binding to the rule.

My rule is
` /Christmas light control/
import org.joda.time.*
import org.openhab.core.library.types.*
import org.openhab.core.library.types.PercentType
import org.openhab.core.library.items.SwitchItem
import org.openhab.model.script.actions.*
import org.openhab.model.script.actions.Timer
import java.util.HashMap
import java.util.LinkedHashMap
import java.util.ArrayList
import java.util.Map
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock

rule “PXY_1: proxyconrelay changed to ON”
when
Item proxyconrelay changed to ON
then
if
(CORelayStatus.state == 0) {
sendCommand(CORelay,ON)
}
end

rule “PXY_2: proxyconrelay changed to Off”
when
Item proxyconrelay changed to OFF
then
if
(CORelayStatus.state == 1) {
sendCommand(CORelay,OFF)
}
end`

You need three switches, your original two plus a proxy. The proxy is not bound to anything, it gets updated and processed through rules.

Switch	CORelay	"Conservatory Switch"	<switch>	(Conservatory)	{ mqtt="<[broker:jpfy/house/relay/CO/Recieve:state:default],>[broker:jpfy/house/relay/CO/SEND/:command:ON:1],>[broker:jpfy/house/relay/CO/SEND/:command:OFF:0]" }
Number	CORelayStatus	"Conservatory Relay Status [%d]"	<terrace>	(Conservatory)	{ mqtt="<[broker:jpfy/house/relay/CO/Recieve:state:default] " }
Switch proxyconrelay "COProxy" <switch>

Then you need rules to send commands to CORelay when the proxy receives a command and to update the proxy when CORelayStatus receives and update.

rule "proxyconrelay changed"
when
    Item proxyconrelay received command
then
    CoRelay.sendCommand(proxyconrelay.state)
end

rule "CORelayStatus updated"
when
    Item CORelayStatus received update
then
    if(CORelayStatus.state == 0) proxyconrelay.postUpdate(OFF)
    else proxyconrelay.postUpdate(ON)
end

Then your sitemap would be

Switch item=proxyconrelay

You can add additional logic if you are worried about duplicate commands being sent or there is extra stuff you want to consider. For example, Bob’s proxy example uses this design pattern to check the status of a motion detector to determine whether or not to turn on the light.

Thank you that worked.

Hello, I’m a newbie here and jump to OH2 directly.
Recently I follow @rlkoshak code to setup one Switch by the code at the end of demo.items:

Switch LED02 				{mqtt=">[mosquibroker:/ESP_Easy_01/GPIO/2:COMMAND:ON:0],>[mosquibroker:/ESP_Easy_01/GPIO/2:COMMAND:OFF:1],<[mosquibroker:/ESP_Easy_01/GPIO/2:state:default]"}
Number LED02_Status			{mqtt="<[mosquibroker:/ESP_Easy_01/GPIO/2:state:default]"}
Switch proxyLED02 

and the code at the end of demo.rules:

rule "proxyLED02 changed"
    when
        Item proxyLED02 received command
    then
        LED02.sendCommand(proxyLED02.state)
    end

rule "LED02_Status updated"
    when
        Item LED02_Status received update
    then
        if(LED02_Status.state == 0) proxyLED02.postUpdate(ON)
        else proxyLED02.postUpdate(OFF)
    end

and the code at the end of demo.sitemaps:

Frame  label="MQTT Test"{
    Switch item=proxyLED02 label="LED 02"
}

and my addons.cfg is:

# The base installation package of this openHAB instance
# Valid options:
#   - minimal  : Installation only with dashboard, but no UIs or other addons
#   - standard : Typical installation with all standards UIs
#   - demo     : A demo setup which includes UIs, a few bindings, config files etc.
package = demo

# A comma-separated list of bindings to install (e.g. "sonos,knx,zwave")
binding = mqtt

# A comma-separated list of UIs to install (e.g. "basic,paper")
ui = basic

# A comma-separated list of persistence services to install (e.g. "rrd4j,jpa")
persistence = mqtt

# A comma-separated list of actions to install (e.g. "mail,pushover")
action = mqtt

# A comma-separated list of transformation services to install (e.g. "map,jsonpath")
transformation = 

# A comma-separated list of text-to-speech engines to install (e.g. "marytts,freetts")
tts = 

# A comma-separated list of miscellaneous services to install (e.g. "myopenhab")
misc = 

In the bigining, I got no responcse from ESP8266-12 LED when toggle the Switch, but got the logs in openhab.log:

2016-02-19 22:37:11.351 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'proxyLED02' received command OFF
2016-02-19 22:37:11.357 [ERROR] [.script.engine.ScriptExecutionThread] - Error during the execution of rule 'proxyLED02 changed': Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.sendCommand(org.eclipse.smarthome.core.items.Item,java.lang.Number) on instance: null
2016-02-19 22:37:11.377 [INFO ] [marthome.event.ItemStateChangedEvent] - proxyLED02 changed from ON to OFF

After reboot openHAB server (Raspberry Pi 2), it did work! And with the following log data:

2016-02-20 10:41:51.021 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'LED02' received command OFF
2016-02-20 10:41:51.023 [DEBUG] [inding.mqtt.internal.MqttItemBinding] - Publishing command OFF to /ESP_Easy_01/GPIO/2
2016-02-20 10:41:51.025 [INFO ] [marthome.event.ItemStateChangedEvent] - proxyLED02 changed from OFF to ON
2016-02-20 10:41:51.026 [DEBUG] [t.mqtt.internal.MqttBrokerConnection] - Publishing message 34 to topic '/ESP_Easy_01/GPIO/2'
2016-02-20 10:41:51.027 [ERROR] [.mqtt.internal.MqttMessageSubscriber] - Error processing MQTT message.
java.lang.NullPointerException
	at org.openhab.core.events.EventPublisherDelegate.postUpdate(EventPublisherDelegate.java:60)[163:org.openhab.core.compat1x:2.0.0.201602120202]
	at org.openhab.binding.mqtt.internal.MqttMessageSubscriber.processMessage(MqttMessageSubscriber.java:150)[11:org.openhab.binding.mqtt:1.9.0.201602140217]
	at org.openhab.io.transport.mqtt.internal.MqttBrokerConnection.messageArrived(MqttBrokerConnection.java:552)[13:org.openhab.io.transport.mqtt:1.9.0.201602140217]
	at org.eclipse.paho.client.mqttv3.internal.CommsCallback.handleMessage(CommsCallback.java:354)[15:org.eclipse.paho.client.mqttv3:1.0.2]
	at org.eclipse.paho.client.mqttv3.internal.CommsCallback.run(CommsCallback.java:162)[15:org.eclipse.paho.client.mqttv3:1.0.2]
	at java.lang.Thread.run(Thread.java:745)[:1.8.0_65]
2016-02-20 10:41:51.046 [INFO ] [marthome.event.ItemStateChangedEvent] - proxyLED02 changed from ON to OFF

Although sometimes Switch no response (can’t turn on or can’t turn off by first tap, but after 2nd or 3rd tap it will OK), after short period, finally the LED work properly. But the ERROR message still remain in log file.

Can anyone help me to resolve this issue?

And my question is : Should I need “Import” in OH2? Because from the topic OH2 Documentation, Kai seems say no need import anymore in OH2, am I right?

Other question is : I put all the related MQTT bindings to addons directory, including “binding, action, io.transport, persistence, eclipse.smarthome.io.transport, eclipse.paho.client.mqttv3”. Is it OK?

Thanks for the help in advance!

I’ve opened this issue regarding the NullPointerException you see in the OH2 log. The root cause, however, is that the message published to the MQTT topic is not in a format that is acceptable for that kind of item, and so an attempt to convert it into an acceptable state fails. This ought to result in a WARN message in the log, but under OH2, produces a NullPointerException instead.

Once you change what is published to the MQTT broker, or you change the item type so it can accept the message, you will get past this issue!

Thanks @watou, your reply ease my nervous about this error log.
So you mean I can modify item definition on the topic of published message or even item style, isn’t it? I’ll try!

If you openHAB were instead a String item, for example, then any message you publish from your device to the topic, which the item subscribes to, will successfully be delivered, because the message does not have to conform to a specific format. If, on the other hand, you have a Switch item, then the MQTT message either has to be “ON” or “OFF”, or you have to use a transform (instead of default) in the item’s binding string, so that the MQTT message is transformed into either ON or OFF. Only then can the update be posted successfully to the Switch item.

Do you mean change “Switch LED02 {mqtt…” to “String LED02 {mqtt…”, or “Number LED02_Satus …” to “String LED02_Status …”? I try a bit but lost in fog ><
Can you give me much detail advice? Thanks!

It helps more to describe the path from your device -> MQTT broker -> MQTT binding -> transform -> item -> sitemap.

  1. Your device publishes the string “ON” to the topic “/switch” on the broker “broker” when it turns on, and “OFF” when it turns off.
  2. You have a Switch item defined in your items file like this: Switch mySwitch { mqtt="<[broker:/switch:state:default]" }.
  3. You have the item appear in your sitemap with Text item=mySwitch
  4. At this point, you can see the switch turn off and on in the openHAB Classic UI.

Problem is, your device publishes “1” for on and “0” for off. So instead of Switch mySwitch { mqtt="<[broker:/switch:state:default]" }, you have replace default with a transform to turn the MQTT message into the “ON” or “OFF” that openHAB needs for switches. So you would have your item be Switch mySwitch { mqtt="<[broker:/switch:state:MAP(onoff.map)]" } and you would have a file transform/onoff.map with

0=OFF
1=ON

in it. Does this make sense so far?

1 Like

FTR: This has been fixed in the latest build.

Thank you for the fix, Kai!

Hmm, I use ESP8266-12E NodeMCU on board LED (GPIO2) for test. This GPIO2 pin should be pull-down to turn on the LED, so I use “0” to turn “ON” and “1” to turn “OFF” in items file and rules file, then I can have the same state behavior between ESP8266 and openHAB UI. But I didn’t notice that this change maybe conflict with Switch mySwitch { mqtt="<[broker:/switch:state:default]" } statement.
I’ll try to use another pin with external LED to test normal map configuration. Thanks!

Recent build of 2.0.0-SNAPSHOT has remove the NullPointerException issue, thanks.
I test 2 LED in ESP8266-12E NodeMCU board, one is via GPIO2 to sent “0” to turn on the on board LED, other one is via GPIO12 to sent “1” to turn on external LED. I modified the item file:

Switch LED02 	        {mqtt=">[mosquibroker:/ESP_Easy_01/GPIO/2:COMMAND:ON:MAP(onoff_inverse.map)],>[mosquibroker:/ESP_Easy_01/GPIO/2:COMMAND:OFF:MAP(onoff_inverse.map)],<[mosquibroker:/ESP_Easy_01/GPIO/2:state:MAP(onoff_inverse.map)]", autoupdate="false"}
Number LED02_Status	{mqtt="<[mosquibroker:/ESP_Easy_01/GPIO/2:state:MAP(onoff_inverse.map)]"}

Switch LED12 		{mqtt=">[mosquibroker:/ESP_Easy_01/GPIO/12:COMMAND:ON:MAP(onoff.map)],>[mosquibroker:/ESP_Easy_01/GPIO/12:COMMAND:OFF:MAP(onoff.map)],<[mosquibroker:/ESP_Easy_01/GPIO/12:state:MAP(onoff.map)]", autoupdate="false"}
Number LED12_Status	{mqtt="<[mosquibroker:/ESP_Easy_01/GPIO/12:state:MAP(onoff.map)]"}

and the rule file (I use function to unify switch rule):

//Function 1: Switch State Update

val org.eclipse.xtext.xbase.lib.Functions$Function SwitchLogic = [
org.openhab.core.library.items.SwitchItem SwitchItem,
    org.openhab.core.library.items.SwitchItem SwitchState |

    if (SwitchState.state == ON) SwitchItem.postUpdate(ON)
    else SwitchItem.postUpdate(OFF)
]

//Function End

rule "LED02 State Update"

when
	Item LED02_State received update 
then
	SwitchLogic.apply(LED02, LED02_State)
end

rule "LED12 State Update"

when
	Item LED12_State received update 
then
	SwitchLogic.apply(LED12, LED12_State)
end

and the transform map:
onoff_inverse.map :

1=OFF
0=ON
1.00=OFF
0.00=ON
OFF=1
ON=0
OFF=1.00
ON=0.00

onoff.map :

0=OFF
1=ON
0.00=OFF
1.00=ON
OFF=0
ON=1
OFF=0.00
ON=1.00

and the sitemap:

Frame  label="MQTT Test"{
    Switch item=LED02 label="LED 02"
    Switch item=LED12 label="LED 12"
}

When I turn on/off LED 02, the log shows:

14:04:36.065 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'LED02' received command ON
14:04:36.080 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02_Status'
14:04:36.089 [INFO ] [marthome.event.ItemStateChangedEvent] - LED02 changed from OFF to ON
14:04:38.278 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'LED02' received command OFF
14:04:38.286 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02_Status'
14:04:38.289 [INFO ] [marthome.event.ItemStateChangedEvent] - LED02 changed from ON to OFF
14:04:38.380 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02_Status'

LED 02 works properly, even I manual change GPIO pin status from ESP8266, the LED status on my mobile openhab app change immediately and correctly.

But for example, if I change onoff_inverse.map to:

1=OFF
0=ON

the log is:

14:02:23.292 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'LED02' received command ON
14:02:23.300 [WARN ] [rm.AbstractFileTransformationService] - Could not transform 'ON' with the file 'onoff_inverse.map' : Target value not found in map for 'ON'
14:02:23.306 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '' with the file 'onoff_inverse.map' : Target value not found in map for ''
14:02:23.309 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02'
14:02:23.310 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '' with the file 'onoff_inverse.map' : Target value not found in map for ''
14:02:23.313 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02_Status'
14:02:23.443 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '0.00' with the file 'onoff_inverse.map' : Target value not found in map for '0.00'
14:02:23.445 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02'
14:02:23.447 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '0.00' with the file 'onoff_inverse.map' : Target value not found in map for '0.00'
14:02:23.450 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02_Status'

and if I change onoff_inverse.map to:

1=OFF
0=ON
1.00=OFF
0.00=ON

then the log is:

14:02:30.168 [INFO ] [smarthome.event.ItemCommandEvent    ] - Item 'LED02' received command OFF
14:02:30.174 [WARN ] [rm.AbstractFileTransformationService] - Could not transform 'OFF' with the file 'onoff_inverse.map' : Target value not found in map for 'OFF'
14:02:30.192 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '' with the file 'onoff_inverse.map' : Target value not found in map for ''
14:02:30.196 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02'
14:02:30.199 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '' with the file 'onoff_inverse.map' : Target value not found in map for ''
14:02:30.204 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'LED02_Status'

My question is: Dose the format of MAP file is OK? and, Can you give me some advice on ‘Function’? Like: How to fully qualify each and every reference with the complete package name?

Thank a lot!

No, the map files have duplicate ON and OFF keys. The keys to the left of the = must be unique.

With your MQTT out bindings, I recommend simply specifying the literal value you want to send, instead of using a map, like:

Switch LED02 {mqtt=">[mosquibroker:/ESP_Easy_01/GPIO/2:command:ON:0],>[mosquibroker:/ESP_Easy_01/GPIO/2:command:OFF:1],<[mosquibroker:/ESP_Easy_01/GPIO/2:state:MAP(onoff_inverse.map)]", autoupdate="false"}
Switch LED12 {mqtt=">[mosquibroker:/ESP_Easy_01/GPIO/12:command:ON:1],>[mosquibroker:/ESP_Easy_01/GPIO/12:command:OFF:0],<[mosquibroker:/ESP_Easy_01/GPIO/12:state:MAP(onoff.map)]", autoupdate="false"}

I also suggest using

import org.openhab.core.library.types.*

and other imports at the top of your rules file to simplify, and also writing the code directly in the body of the rule if the function is behaving strangely.

All the best!

Thank you @watou, it works! I use map for inbound message only and modify map file like:

0=OFF
1=ON
0.00=OFF
1.00=ON

There is only one warn log “[b.core.events.EventPublisherDelegate] - given new state is NULL, couldn’t post update for ‘LED02_Status’” remain, but I think this maybe issue from ESP8266 because switch state update correctly.

Other question is: Should I need the import section for rules in OH2?

Glad you got it working! The imports aren’t needed for the state types in openHAB 2.

Hi,

I am having a similar problem with the “given new state is NULL, couldn’t post update” message in my logs.

I am using OH2 beta (version from the shell tells me 4.0.4).

I have a switch that I build myself and it it publishes the following messages via MQTT. Topic “name/state” Message “ON” or Message “OFF”.

So I would expect it work find updating a switch without any transformation. I have tested it with a String and thats fine.

Switch TestSwitch {mqtt="<[mosquitto:name/state:state:default]"}
String TestString {mqtt="<[mosquitto:name/state:state:default]"}

This is the log output

16:25:49.462 [INFO ] [marthome.event.ItemStateChangedEvent] - TestString changed from ON to OFF
16:25:50.369 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn’t post update for 'TestSwitch’
16:25:50.371 [INFO ] [marthome.event.ItemStateChangedEvent] - TestString changed from OFF to ON
16:25:50.988 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn’t post update for ‘TestSwitch’

Based on what you have said it looks like it should work. Do you have any idea why the switch is always seeing the state change as NULL, when the string sees the update correctly and contains ON and OFF which is what the switch would expect?

Or have I missed something? Thats quiet possible as I have only been trying out OH2 for a day (and never tried OH1)

Regards

Ben

Hi Ben, I agree it ought to work. Try turning on debug logging for the binding in the console:

openhab> log:set DEBUG org.openhab.binding.mqtt