Rule / Switch not reliable

Release = Raspbian GNU/Linux 10 (buster)
Kernel = Linux 5.4.51-v7+
Platform = Raspberry Pi 3 Model B Rev 1.2
openHAB 2.5.8-1 (Release Build)

The concept here is to send a “switch off” command to the 433 receiver (poweroutlet) multiple times in the evening because in between it could have been switched on by the remote control unit that lays around in the living room (and is completely independed on purpous from openHab).
Problem seems, that the script is executed just sometimes.
Now, how can I “force” openHab to send the switch off command independent of what it thinks that the state is before?
[A different switch with time rule I use works quite reliably, the difference is that it is executed only once a day, so a different frequency]

Log when it works:

==> /var/log/openhab2/openhab.log <==
2020-10-04 21:10:00.384 [INFO ] [e.smarthome.model.script.LAN abends ] - ausgeschaltet : 12345

==> /var/log/openhab2/events.log <==
2020-10-04 21:10:00.402 [ome.event.ItemCommandEvent] - Item 'Funksteckdose3Switch' received command 12345
2020-10-04 21:10:00.414 [nt.ItemStatePredictedEvent] - Funksteckdose3Switch predicted to become 12345
2020-10-04 21:10:00.447 [vent.ItemStateChangedEvent] - Funksteckdose3Switch changed from 12340 to 12345

… and I put a control log into the script that switches the poweroutlet. In the case above it writes to the log so it means the script is executed correctly.

04/10/2020 21:10:00 Script /opt/433Utils/RPi_utils/Funksteckdose_1.sh mit dem Parameter 12345 gestartet. Kommando: /opt/433Utils/RPi_utils/codesend 12345
sending code[12345]

Log in case the switch has not been executed (and no entry in the script-log):

==> /var/log/openhab2/openhab.log <==
2020-10-04 22:10:00.051 [INFO ] [e.smarthome.model.script.LAN abends ] - ausgeschaltet : 12345

==> /var/log/openhab2/events.log <==
2020-10-04 22:10:00.070 [ome.event.ItemCommandEvent] - Item 'Funksteckdose3Switch' received command 12345
2020-10-04 22:10:00.081 [nt.ItemStatePredictedEvent] - Funksteckdose3Switch predicted to become 12345

–> the line with the “changed from … to …” is now missing.

Rule:

rule "LAN abends aus"
when
	Time cron "0 10 21 ? * MON-SUN *" or
	Time cron "0 10 22 ? * MON-SUN *"
then
	Funksteckdose3Switch.sendCommand(12345) 
	logInfo("LAN abends ","ausgeschaltet : 12345")
	
end

Thing:

Thing exec:command:Funksteckdose-control [ command="/opt/433Utils/RPi_utils/Funksteckdose_1.sh %2$s", interval=0, autorun=true ]

of course the
/opt/433Utils/RPi_utils/Funksteckdose_1.sh %2$s
is in the whitelist…

Item:

String Funksteckdose3Switch "Funksteckdose 3" <poweroutlet> [ "Switchable" ] { channel="exec:command:Funksteckdose-control:input" }

Thanks for any idea … :slight_smile:
Andreas

That’s because it’s already 12345 so there’s no change to the Item’s state.

You’ve sent the command so that should go to the Exec binding. But looking at the Exec binding docs we find:

autorun - A boolean parameter to make the command execute immediately every time the input channel is sent a different openHAB command. If choosing autorun, you may wish to also set interval=0 . Note that sending the same command a second time will not trigger execution.

(emphasis is mine)

So you either need to change the state of your String Item to something other than 12345 before commanding it to 12345 again, or you need to link a Switch Item to the run channel. Then change the Thing to use autorun=false and your rule to update the String Item and then sendCommand(ON) to the Switch Item.

Comment; if you use the String exec input channel (for the %2$s substitution), you must still send the parameter as command and not as update. Even if you use the Switch run channel to make it fire. The state of an Item linked to exec input channel is just ignored.

It’s probably easier for this job to hardcode the exec Thing with no substitution, and just a Switch / run channel to fire it.

@rlkoshak, @rossko57 Thanks, I think you put some of my loose ends of strings together.
Here I think I will use Rich’s trick (sending Funksteckdose3Switch.sendCommand(0000) or so just before the “real” command) because I use the script for different 433s and so it should be “neutral” for different inputs.
In fact I recognized the “note that sending …” in the description but if you do not understand in the right way it is hard to remember …

One more thing, I use also the following:
Thing

Thing exec:command:Abruf-Anruferliste [ command="/etc/openhab2/scripts/fritzbox.sh", interval=0, autorun=true ]

Item

String CallList {channel="exec:command:Abruf-Anruferliste:input" }

Rule

rule "update calllist"
when
	Time cron "0 0/3 8-23 * * ?" //every 3 minutes from 8:00 to 23:00
then
	logInfo("Fritzbox"," Calllist wird neu geladen")
	CallList.sendCommand(ON)
end

So, here again the input channel (I tried with the run channel but must have missed something also in this case …).
This seems fairly the same as above and it seems this command is not interpreted as “sending the same command a second time”?

A counter argument is that each device should be represented by it’s own Thing in openHAB. Each device should definitely be represented by it’s own Item in openHAB. Given that, “hard coding” the arguments to the one script like rossko57 suggests is perfectly reasonable.

In your rules and on your sitemap you shouldn’t have to know or care what technology a given device uses or details like “12345”. You should only have to care that a given Item represents a certain device (e.g. Livingroom_Lamp).

Well, you are sending an ON command to a String Item linked to the input Channel. And if the Item is already “ON”, it’s not changing so the script isn’t run same as before.

What you probably want is to set autorun=false, link a Switch Item to the run channel and then sendCommand ON to that.

What’s weird about that setup is that you don’t use the input command value at all - no %2$s substitution in your URL.
I’ve no idea how the hidden machinery works, but wonder if what needs to ‘change’ to fire autorun is that evaluation of the command. That’ll always be ‘different’ if its stored as “void from last use” because it never gets evaluated and used.

It’s just an oddball way to use the binding.

Guess you are right, I will work it over and then post an update :slight_smile:

When you don’t have an input that you are using, set autrun to false and only link a Switch Item to the run Channel. That should always respond to an ON command even if the Switch Item is already ON.

Hi again, so for this topic (sending simply “on” to run a script) this was the solution:
Thing:

Thing exec:command:Abruf-Anruferliste [ command="/etc/openhab2/scripts/fritzbox.sh", interval=0, autorun=false ]

Item:

Switch CallList {channel="exec:command:Abruf-Anruferliste:run", autoupdate="false"}

Rule:

rule "update calllist"
when
	Time cron "0 0/3 8-23 * * ?" //every 3 minutes from 8:00 to 23:00
then
	logInfo("Fritzbox"," Calllist wird neu geladen")
	CallList.sendCommand(ON)
end

And we see in the log that it perfectly works:

2020-10-06 18:06:00.016 [INFO ] [ipse.smarthome.model.script.Fritzbox] -  Calllist wird neu geladen

==> /var/log/openhab2/events.log <==
2020-10-06 18:06:00.054 [ome.event.ItemCommandEvent] - Item 'CallList' received command ON
2020-10-06 18:06:00.086 [vent.ItemStateChangedEvent] - CallList changed from OFF to ON
2020-10-06 18:06:00.817 [vent.ItemStateChangedEvent] - CallList changed from ON to OFF

Thanks a lot, great help! :+1:

For the other topic, sending a command twice and have it executed, I now use this rule:

rule "LAN abends aus"
when
	Time cron "0 10 21 ? * MON-SUN *" or
	Time cron "0 10 22 ? * MON-SUN *"
then
	Funksteckdose3Switch.sendCommand(0000)
	Thread::sleep(2000)
	Funksteckdose3Switch.sendCommand(12340) 
end

First sendCommand “resets” the state of the Item (and triggers the script with bogus…), the other one triggers the script with the right arg for “On”.
The Thread::sleep was necessary because the commands were to fast one after the other, so the sender or so gave up and did not send the second, real command (ok, could have been filtered out in the script as alternative …).
Again: thanks a lot, now it works :slight_smile:

I tried to follow also your argument which I fully understand:

Idea: leave Thing neutral as it is and use the “:input” channel.
I already created one Item for every poweroutlet, but how do you “fill” the channel?
Basically 2 starting points: a) Sitemap with Switch and b) Rule; both sending just “ON” or “OFF” and then translate these commands to the real commands for the 433Util (e.g. “12345” and “12340”, respectively) in the Item.
Unfortunately I was not able to figure this out
(again I might not understand the concept: sendCommand from Switch/Rule; received by Item with possibility to translate to something else; send it to the Thing which then executes the script with the arg?).
Is there a way (translation table works “in the wrong direction” only)?

A much shorter sleep would be preferable. A Timer would be even better. You could even use the Expire binding to automatically reset the Item to 0000 after a second. When you sleep in a rule you consume a thread. When you have enough of them sleeping you will consume all the available threads doing nothing and preventing any other rules from running.

That’s because OH is designed and expects there to be a one-to-one relationship between Things and devices.One Thing represents one device. By leaving the Thing “neutral”, as you say it, you break that assumption. So you are stuck with having to write rules to work around the fact that you have violated one of the foundational assumptions.

Unfortunately, the Exec binding doesn’t make doing this without using rules challenging and in the end, having a “neutral” Thing ends up being what will most convenient (allowing a transformation on the commands to the Exec binding would solve this issue nicely).

So if we have the one Exec Thing that passes the input Channel Item as an argument to the script:

  1. Create a Switch Item not linked to any Channels for each device. These are the Items you use to represent the device in openHAB. So they go on your sitemap and they are commanded from other Rules.

  2. Create a rule that gets triggered when these Items are commanded. You can create one Rule per Item or get clever and create one rule to handle them all. Based on which Item received the ON/OFF command and what the command was determine the 12345 string that needs to be passed to the script.

  3. Instead of using the Exec Thing, just call executeCommandLine from the Rule.

1 Like

@rlkoshak Great! Much better concept than before
Thing: –
Item:

Switch Funksteckdose2Switch "Funksteckdose 2" <poweroutlet>

Rule:

val execscript = "/opt/433Utils/RPi_utils/Funksteckdose_1.sh "
rule "Funksteckdose 2 (SAT) Schalter"	
when
	Item Funksteckdose2Switch received command
then
	if (receivedCommand == ON) {
		executeCommandLine(execscript + 12345) // Sat an
		}
		
	if (receivedCommand == OFF) {
		executeCommandLine(execscript + 12340) // Sat aus
		}
end

// Rule für Funksteckdose 2 (SAT), Schaltung zeitgesteuert

rule "Wochentags Sat aus"
when
	Time cron "0 05 21 ? * MON-FRI *" or
	Time cron "0 10 0 ? * MON-FRI *"
then
	Funksteckdose2Switch.sendCommand(OFF)
end

Sitemap:

sitemap default label="Erste Sitemap"
{
    Frame label="Funksteckdosen" {
        Switch item=Funksteckdose2Switch label="Sat (DG) Funksteckdose"        
    }
}

I tried to create a rule which covers all devices, something like
when
Item Funksteckdose1Switch received command or
Item Funksteckdose2Switch received command
then
… find out from which Switch the “receivedCommand” but was not successful to work that out.
Anyway, in the end, the rules get quite complex and differ from Switch to Switch so at the moment it makes sense to create one rule set per Switch even if then some Code is redundant.

  1. Put all the Items into a Group. Let’s call it Devices. Add all the relevant Items to that one Group.

  2. Get clever with the naming of your Items. See Design Pattern: Encoding and Accessing Values in Rules. I’ll show putting the values into the Item name. So the Funksteckdose2Swith would be Funksteckdose2Switch_12345_12340.

  3. Trigger the Rule using the Member of trigger

  4. Pull the number to send out of the triggeringItem’s name.

val execscript = "/opt/433Utils/RPi_utils/Funksteckdose_1.sh "

rule "Devices"
when
    Member of Devices received command
then
    val parts = triggeringItem.name.split('_')
    val arg = if(receivedCommand == ON) parts.get(1) else parts.get(2)
    executeCommandLine(execscript + arg)
end

Those three lines and some clever naming of your Items will handle all your devices.

Well, really clever! Just worked, makes the whole procedure more structured and saves some redundant code :grinning: :+1: :man_student: