Use IOTlink to send commands to PC via MQTT via rule results in erros

Hi all,

I try to send a command via MQTT to my PC running iotlink.

Goal of this exercise is to switch my Display from the internal (Display 1) to the external (Display 2) via Displayswitch.exe

Using the information from the official IOTlink Gitlab wiki for running an application: https://gitlab.com/iotlink/iotlink/-/wikis/Addons/Commands

My rule looks like this:

rule "R1_Virt_Konsole_On"

when
	Item R1_Virt_Konsole_switch received command ON
then
	R1_Computer_switch.sendCommand(ON)
	R1_Fernseher_switch.sendCommand(ON)
	R1_Computer_Boxen_switch.sendCommand(ON)
	val actions = getActions("mqtt","mqtt:broker:mosquitto")
actions.publishMQTT("desktop/workgroup/desktop/commands/run","{"command": 'C:\\Windows\\System32\\Displayswitch.exe', "args": '/external', "visible": false, "fallback": true}")
Thread::sleep(5000)
 R1_Virt_PC_switch.sendCommand(OFF)
 R1_Virt_Computer_switch.sendCommand(OFF)
end

rule "R1_Virt_Computer_TV_enable"

when
    Item Desktop_state changed from OFF to ON
then
    if (R1_Virt_Konsole_switch==ON)
    {
	val actions = getActions("mqtt","mqtt:broker:mosquitto")
	actions.publishMQTT("desktop/workgroup/desktop/commands/run","{"command": 'C:\\Windows\\System32\\Displayswitch.exe', "args": '/external', "visible": false, "fallback": true}")
    }
end
    
rule "R1_Virt_Konsole_Off"

when
	Item R1_Virt_Konsole_switch received command OFF
then
	if (R1_Virt_Computer_switch.state==OFF && R1_Virt_PC_switch.state==OFF)
		{
		logInfo("PC", "Konsole ausgeschaltet")
	val actions = getActions("mqtt","mqtt:broker:mosquitto")
	actions.publishMQTT("desktop/workgroup/desktop/commands/run","{"command": 'C:\\Windows\\System32\\Displayswitch.exe', "args": '/internal', "visible": false, "fallback": true}")
Thread::sleep(1000)
	actions.publishMQTT("desktop/workgroup/desktop/commands/shutdown"," ")
Thread::sleep(500)
		}
	if (R1_Virt_Computer_switch.state==OFF)
		{
		R1_Computer_Boxen_switch.sendCommand(OFF)
		}
	if (R1_Virt_Fernseher_switch.state==OFF)
		{
		R1_Fernseher_switch.sendCommand(OFF)
		}
end

Sneding the payload via mqttfx works perfectly and switches the display.

I get the following erros in openhab.log:

2020-12-14 18:09:15.116 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model 'R1_Virt_Konsole.rules'
2020-12-14 18:09:15.117 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'R1_Virt_Konsole.rules' is either empty or cannot be parsed correctly!
2020-12-14 18:09:16.138 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'R1_Virt_Konsole.rules' has errors, therefore ignoring it: [10,65]: missing ')' at 'command'
[10,176]: mismatched input ')' expecting 'end'
[24,66]: missing ')' at 'command'
[24,177]: extraneous input ')' expecting '}'
[37,66]: missing ')' at 'command'
[37,177]: mismatched input ')' expecting '}'
[41,3]: mismatched input '}' expecting 'end'

I tried adding ’ instead of " before and after the payload, which renders this section useless.

Is there anything I can try to just send the payload without openhab checking what is in there?

As you can see in your post, there are a few JSON attributes which are not red. That’s because they have a " in front, which has ‘stopped’ the previous ".

You need to add \ before each " which is part of your JSON string. Something like:

actions.publishMQTT("desktop/workgroup/desktop/commands/run","{\"command\": 'C:\\Windows\\System32\\Displayswitch.exe', \"args\": '/external', \"visible\": false, \"fallback\": true}")

For the future: you need to use the backslash to escape the quotes.

1 Like

Or add iotlink things as things/items.

I wrote an extention for iotlink to poll and action commands on my hyper-v system so I can save/resume VMS from openhab. It’s quite a good system.

Thank you very much for your suggestions.

Found a solution myself, but tested also hafniumzinc’s solution which also worked.

Here my solution:

rule "R1_Virt_Konsole_On"

when
	Item R1_Virt_Konsole_switch received command ON
then
	R1_Computer_switch.sendCommand(ON)
	R1_Fernseher_switch.sendCommand(ON)
	R1_Computer_Boxen_switch.sendCommand(ON)
	val actions = getActions("mqtt","mqtt:broker:mosquitto")
	actions.publishMQTT("desktop/workgroup/desktop/commands/run","{command: 'C:\\Windows\\System32\\Displayswitch.exe', args: '/external', visible: false, fallback: true}")
	Thread::sleep(5000)
 	R1_Virt_PC_switch.sendCommand(OFF)
	R1_Virt_Computer_switch.sendCommand(OFF)
end

rule "R1_Virt_Computer_TV_enable"

when
    Item Desktop_state changed from OFF to ON
then
    if (R1_Virt_Konsole_switch==ON)
    {
		val actions = getActions("mqtt","mqtt:broker:mosquitto")
		actions.publishMQTT("desktop/workgroup/desktop/commands/run","{command: 'C:\\Windows\\System32\\Displayswitch.exe', args: '/external', visible: false, fallback: true}")
    }
end
    
rule "R1_Virt_Konsole_Off"

when
	Item R1_Virt_Konsole_switch received command OFF
then
	if (R1_Virt_Computer_switch.state==OFF && R1_Virt_PC_switch.state==OFF)
		{
		logInfo("PC", "Konsole ausgeschaltet")
		val actions = getActions("mqtt","mqtt:broker:mosquitto")
		actions.publishMQTT("desktop/workgroup/desktop/commands/run","{command: 'C:\\Windows\\System32\\Displayswitch.exe', args: '/internal', visible: false, fallback: true}")
		Thread::sleep(1000)
		actions.publishMQTT("desktop/workgroup/desktop/commands/shutdown"," ")
		Thread::sleep(10000)
		}
	if (R1_Virt_Computer_switch.state==OFF)
		{
		R1_Computer_Boxen_switch.sendCommand(OFF)
		}
	if (R1_Virt_Fernseher_switch.state==OFF)
		{
		R1_Fernseher_switch.sendCommand(OFF)
		}
end

One question about IOTlink… How safe/secure is it? If you enable commands addon, are you able to control to not allow some commands? Or even better, can you whitelist only commands you allow? Because I don’t feel safe giving this kind of access to my computer just to run few predefined commands… Of course one could lock down MQTT strictly, but you never know what mqtt device could be compromised and used to send malicious commands to the computer…
I can’t find anything about security on git wikis.
Any input would be appreciated.
Thanks

Hi all,

I am trying the same without a lot of success. I managed to get IOTlink to work and commands such as “shutdown” or “lock” are working for me, however, for some reason, I can’t get to run a .bat file that has no parameters and the only thing that it should do is open notepad. I have the following:

rule "apagarPC"
when
   Item apagarPC changed
then

val mqttActions = getActions("mqtt","mqtt:broker:mosquitto")


val String topic = "iotlink/workgroup/mydesktop/commands/run"

mqttActions.publishMQTT(topic,"{command: 'C:\\note.bat', args: '',visible: true, fallback: false}")
logError("Test", "Apagar PC run succesfully")

end

I see the LogError details confirming that I am triggering the rule correctly on my logs but notepad doesn’t open on my PC.

I have tried with all of the following:

mqttActions.publishMQTT(topic,"{command: 'C:\\note.bat', args: , visible: false, fallback: true}")

mqttActions.publishMQTT(topic,"{command: 'C:\\note.bat', args: '/', visible: false, fallback: true}")

mqttActions.publishMQTT(topic,"{\"command\": 'C:\\note.bat', \"args\": '/', \"visible\": false, \"fallback\": true}")

//now visible parameter set to true

mqttActions.publishMQTT(topic,"{\"command\": 'C:\\note.bat', \"args\": '/', \"visible\": true, \"fallback\": true}")

mqttActions.publishMQTT(topic,"{command: 'C:\\note.bat', args: , visible: true, fallback: true}")


mqttActions.publishMQTT(topic,"{\"command\": 'C:\\note.bat', \"args\": '', \"visible\": true, \"fallback\": true}")

Shouldn’t the parameter visible be set to true to see the application ?
Is there any entry in the windows system log ( eventlog ) that gives a hint ?

I have updated previous post. I tried setting up the parameter to visible, it did not work.

Unfortunately nothing on event viewer :frowning:

I don’t think any of those work out to be valid JSON.
Tip; you can save a lot of messing about by using both single quotes ’ and double quotes "

mqttActions.publishMQTT(topic,'{"command": "C:\\note.bat", "args": "/", "visible": false, "fallback": true}")

I think you are correct to use \\ to get one \ in message.
You’d better check if IOTlink expects true or "true", both are valid JSON.
What’s supposed to go in args? Can you omit it?

You can use a tool like mqtt.fx to see what actual message is going over MQTT to sort this part out.

I don’t have args, that’s why I am trying to put empty. I tried removing that parameter because in the web it doesn’t mention if those are all optional or not, but no success:

https://gitlab.com/iotlink/iotlink/-/wikis/Addons/Commands

Based on the examples they show in their documentation they expect true so that should be correct.
I will check how mqtt.fx works.

What I don’t understand is how if I would use the same code as Sebastian_May above, I don’t get it to work…can’t really find what I am doing wrongly :S

His code:

actions.publishMQTT("desktop/workgroup/desktop/commands/run","{command: 'C:\\Windows\\System32\\Displayswitch.exe', args: '/internal', visible: false, fallback: true}")

My code:

mqttActions.publishMQTT(topic,"{command: 'C:\\note.bat', args:'' , visible: false, fallback: true}")

Ok, found something, the logs from IOTlink, gives me this error message:

[WORKGROUP\mypc][2021-08-05 09:51:18 +02:00][ERROR][IOTLinkAddon.Service.CommandsService]: OnRunMessage failure: Illegal characters in path.

So I guess the problem is on the path. Will check what’s wrong there.

I honestly have no idea what’s wrong, I have raised an issue on the git of the tool. I got to see the following in openhab logs as I separated the text to review if the JSON was being generated correctly and this is what I got:

2021-08-05 12:43:04.027 [.eclipse.smarthome.model.script.Test] - { "command": "C:\note.bat", "visible": true, "fallback": true }

So honestly I see that the payload should be created correctly.

Why don’t you find out? You can’t see the effect of escapes etc. there.
If you won’t use a tool like mqtt.fx or mqtt inspector to see what passes through your broker, then create a temporary MQTT string channel in openHAB, subscribe to your topic, link a test String Item, see what you get.

Ok so after crazy amount of tests the solution was easier than everyone could imagine (need of extra \ ).

Notice that sometimes if I put the .bat file in different folder it does not work, I am still investingating this.

Final working rule is:

rule "notepadon"
when
   Item notepad changed
then

val mqttActions = getActions("mqtt","mqtt:broker:mosquitto")
val String topic = "iotlink/workgroup/REPLACEBYYOURPC/commands/run"

val String comms = "{ \"command\": \"C:\\\\Windows\\\\system32\\\\note.bat\" , \"visible\": false , \"fallback\": false }"

mqttActions.publishMQTT(topic,comms)

end

More readable

val String comms = '{ "command": "C:\\\\Windows\\\\system32\\\\note.bat" , "visible": false , "fallback": false }'