[Solved] Add ID to MQTT Message

Hello everyone,
I’m completely new to this, so please be kind :smile: I have been stuck on this problem for 2 days now and I can’t find anything helpful about this online.

I am trying to control each pin of an Arduino individually via Openhab. To do so, I have set up my Arduino to recieve MQTT messages. The first 3 digits of the Message are used as an ID, that is supposed to tell the Arduino, which pin I am trying to access. The rest of the message is the command that I am sending. So the Message looks somewhat like this:

00250
Meaning:
002: I am controlling the pin with ID 002
50: Set dimmer value to 50 (on the pin corresponding to the ID 002)

Now here is where i ran into a problem:
This is the corresponding line in my Items file:

Dimmer Test_Dimmer1 “Dimmer” (All) {mqtt=">[localbroker:/openHAB/Test_Switch1:command:*:default]"}

this will of course only send values from 0-100. The problem here is, that I don’t know which pin I am trying to control, since there is no ID in the sent data.

I have also tried to transform the value with a Javascript. So I added a transformation in my Items file:

Dimmer Test_Dimmer1 “Dimmer”(All) {mqtt=">[localbroker:/openHAB/Test_Switch1:command:*:JS(getValue.js)]"}

The Javascript file getValue.js looked as follows:

(function(i){ //the variable i is the value openhab sends (I think) so for a dimmer that would be 0-100
var
message=“002”+i; //002 is the ID of the Pin I am controlling - so I’m adding this to the beginning
return message;
})(input)

This sort of worked. I got the desired Message (002xxx) out of Openhab sent to the Arduino. However I was not able to pass any parameters (speaking the ID) to the Javascript from Openhab. So I’d have to hardcode the ID into the script for every pin I am trying to access. (So I would end up with a bunch of *.js-Files for each ID)
That just doesn’t seem like the right solution. There has got to be an easier way to do this! This has been driving me insane for 6 hours now.

Is there a way to add the ID to all the MQTT-Messages sent to a certain device?

Thank You so much for Your help!!!

I would do this through a rule and proxy items.

First of all, this assumes you have persistence set up.

  • Create a Dimmer Item for each of your dimmers but don’t bind them to anything. Name these so we can easily parse the name to grab the pin number.
  • Create a Group for all of the above dimmers and add them all to this Group. I’ll call it gDimmers
  • Create a single String Item bound to your MQTT topic using the binding from your first version of Test_Dimmer1. I’ll call it DimmerMQTT
  • Create a rule that triggers on updates to gDimmers. In this rule we can get the specific dimmer that triggered the update through a hack and based on which Dimmer Item was updated construct the command string that we send to the MQTT topic through DimmerMQTT.postUpdate()

Items:

Group gDimmers
Dimmer 001_Test_Dimmer "Dimmer 1" (All, gDimmers)
Dimmer 002_Test_Dimmer "Dimmer 2" (All, gDimmers)
...
String DimmerMQTT { mqtt=">[localbroker:/openHAB/Test_Switch1:command:*:default]" }

Rule:

rule "Control Dimmers"
when
    Item gDimmers received update
then
    Thread::sleep(250) // give persistence time to store the result so lastUpdate will work, experiment with the minimum sleep needed on your system
    val mostRecent = gDimmers.members.sortBy[lastUpdate].last as DimmerItem

    val pin = mostRecent.name.split("_").get(0)
    val cmd = mostRecent.state.toSting

    DimmerMQTT.postUpdate(pin+cmd)
end

Limitations:

Because we have to sleep a bit to give lastUpdate a chance to populate this rule will not work well if dimmers can be updated at the same time. But in my experience this rarely if ever happens with lights but it is something to be aware of, particularly if you have a rule that, for example, turns all the dimmers off. In that case you would want to do that in a rule and put in a sleep between each command that is at least as long as your sleep above.

Thank You for Your Response!

This hasn’t quite worked yet though.
Is it right, that wer’e basically controlling a variable that will get sent as soon as it gets updated?
I am getting multiple errors:
First of all in the items:

This doesn’t work. It seems like the Items must not start with a number - easy fix though:

Group gDimmers
Dimmer Test_Dimmer_002 “Dimmer 1” (All, gDimmers)
Dimmer Test_Dimmer_003 “Dimmer 2” (All, gDimmers)

So this is all good.
Now the Rule:

it seems like the DimmerItem type doesn’t exist for me. Here is the Error message:
Couldn’t resolve reference to jvm type ‘Dimmeritem’

And last but not least - when the variable DimmerMQTT does update, no message gets sent.

UPDATE:
I feel a little bit stupid now - of course I had to import the DimmerItem first:

import org.openhab.core.library.items.DimmerItem

I don’t get any errors in the code anymore. When I change the dimmer though, the openHab terminal window gives me a huge NullPointerException.

Sort of. When you bind a String Item to an outgoing MQTT topic anything that the Item gets set to ends up being published to that MQTT topic.

Clearly I wasn’t able to test this out myself, or even type it into Designer. I didn’t know about the starting with numbers though. I’ll have to file that away in the vault of my memory.

Make sure you are importing the right classes. At the top of your rules file put:

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

I can’t remember which one of those three have the Item classes in them but if you import all three you should be covered.

However, as I look at it you probably don’t need the "as DimmerItem"cast anyway. First try it without it.

Double check the binding config on the Item. Here is what a working similar Item looks like in my config.

String    N_D_Update      { mqtt=">[mosquitto:entry_sensors/getUpdate:state:*:default]" }

Oops, I messed up the binding config on your Item above. It should be “state” not “command”.

String DimmerMQTT { mqtt=">[localbroker:/openHAB/Test_Switch1:state:*:default]" }

Also, if that still doesn’t work, try removing the starting “/” on the topic name. I’ve had some problems with it and I think at least with Mosquitto they recommend not using a starting slash. I can’t find where I read that right now though.

Alright, here is the error message I get, when I change the dimmer:

2016-01-05 18:04:14.806 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule ‘ChangeDimmer’
java.lang.NullPointerException: null
at org.eclipse.xtext.xbase.lib.ListExtensions$1.compare(ListExtensions.java:84) ~[na:na]
at java.util.TimSort.countRunAndMakeAscending(Unknown Source) ~[na:1.8.0_66]
at java.util.TimSort.sort(Unknown Source) ~[na:1.8.0_66]
at java.util.Arrays.sort(Unknown Source) ~[na:1.8.0_66]
at java.util.ArrayList.sort(Unknown Source) ~[na:1.8.0_66]
at java.util.Collections.sort(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.xbase.lib.ListExtensions.sortInplaceBy(ListExtensions.java:87) ~[na:na]
at org.eclipse.xtext.xbase.lib.IterableExtensions.sortBy(IterableExtensions.java:786) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_66]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:729) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._featureCallOperation(XbaseInterpreter.java:713) ~[na:na]
at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke(PolymorphicDispatcher.java:291) ~[na:na]
at org.openhab.model.script.interpreter.ScriptInterpreter.internalFeatureCallDispatch(ScriptInterpreter.java:69) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._evaluateMemberFeatureCall(XbaseInterpreter.java:549) ~[na:na]
at sun.reflect.GeneratedMethodAccessor42.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke(PolymorphicDispatcher.java:291) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:218) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:751) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._featureCallOperation(XbaseInterpreter.java:712) ~[na:na]
at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke(PolymorphicDispatcher.java:291) ~[na:na]
at org.openhab.model.script.interpreter.ScriptInterpreter.internalFeatureCallDispatch(ScriptInterpreter.java:69) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._evaluateMemberFeatureCall(XbaseInterpreter.java:549) ~[na:na]
at sun.reflect.GeneratedMethodAccessor42.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke(PolymorphicDispatcher.java:291) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:218) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._evaluateCastedExpression(XbaseInterpreter.java:375) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_66]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke(PolymorphicDispatcher.java:291) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:218) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._evaluateVariableDeclaration(XbaseInterpreter.java:601) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_66]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke(PolymorphicDispatcher.java:291) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:218) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._evaluateBlockExpression(XbaseInterpreter.java:321) ~[na:na]
at sun.reflect.GeneratedMethodAccessor46.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_66]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_66]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke(PolymorphicDispatcher.java:291) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:218) ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:204) ~[na:na]
at org.openhab.model.script.internal.engine.ScriptImpl.execute(ScriptImpl.java:59) ~[na:na]
at org.openhab.core.scriptengine.ScriptExecutionThread.run(ScriptExecutionThread.java:44) ~[na:na]

As soon as I dont have this line commented out, the error message appears when I run the rule:

val mostRecent = gDimmers.members.sortBy[lastUpdate].last as DimmerItem

I’m guessing it doesn’t find the last updated item - but I honestly don’t know.

I could however get the String to send its content by changing “command” to “state” as you suggested! Thanks!

Interesting.

Let’s make sure that the Items are members of the group by adding some logging.

Before that line that causes the error add:

logInfo("Dimmers", "Number of members of gDimmers: " + gDimmers.members.size)
logInfo("Dimmers", "Number of members of sorted gDimmers: " +gDimmers.members.sortBy[lastUpdate].size)
logInfo("Dimmers", "Most recent dimmer is " + gDimmers.members.sortBy[lastUpdate].last.name)

This will tell us first that gDimmers has data members, then that when we sort them it has the same number of members, and finally the name of the Item that was most recently updated. If all three logs work I’m not sure what is going on.

Also, try dropping the “as DimmerItem” from that line and let’s see if that works. Maybe it is running into trouble with the cast.

Ok, dropping the “as DimmerItem” doesn’t make a difference.

When adding the logging though, it shows me:

Number of member of gDimmers: 2

followed by the same error message as I have posted before in the next line. So there appears to be a problem with the sorting.

When you said, that I needed to have persistence set up, you meant the addons, right?
Here’s what I have installed:

org.openhab.binding.mqtt-1.7.1
org.openhab.binding.mqttitude-1.7.1
org.openhab.persistence.mqtt-1.7.1
org.openhab.persistence.rrd4j-1.7.1

There’s your problem right there. :wink:

You need to do more than just have the binding jar in your addons. Please see the Persistence wiki page.

2 Likes

Oh my goodness! It works!!
That’s how little things can keep you busy for hours, if you don’t know what you’re doing! :smiley:

Thank You so much rlkoshak for taking all that time to explain everything to a greenhorn like me :+1:

For everyone that has the same problem as I did:
To set up the Persistence, you have to create a *.persistence file in you openhab/config/persistence/ folder.

In the file I set it up, so so every change on the Items is persistent:

Strategies {
}

Items {
       * : strategy = everyChange, restoreOnStartup
}

And tadaa - everything works, as rlkoshak said.

1 Like