OpenHAB Exec Binding explained in detail on 433MHz radio transmitter example

execbinding
433mhz
wiringpi
Tags: #<Tag:0x00007f51e15944a0> #<Tag:0x00007f51e15942c0> #<Tag:0x00007f51e15940e0>

(Martin) #83

Dear everybody,

I am facing currently the issue that from time to time my transceiver is not sending commands to my 433 plugs. I then have to restart OH / or the pi. Then it works fine for certain calls of some plugs until nothing is working again. I have a combination of two rules due to the fact that I am having to different types of plugs (one is using remote-send, the other one remote-codeäsend channel). The problem is coming in both cases.

Due to the fact that I am not an Linux or coding specialist I expect that the problem could be in the code (transmitter not unlocks or sth. like that)? Maybe @soesas or @Josar you have an idea?

my rule file based on your valuable comments:

rule "Single Plug"
  when
    Member of G_All_Plugs received command
    // Item of Group Power Plugs received command or
  then

    logInfo("Power_Plug", "Schalter" + triggeringItem.name + " to " + receivedCommand)
    val ReentrantLock transmitter = new ReentrantLock
    try {
      // Lock transmitter so other executed rules dont't use it at the same time, Concurrent calls of the rule will wait till the resource is free again.
      transmitter.lock()
      // Get the item which triggered the rule, Split the name and get the second part, the number to set as command.
      val num = triggeringItem.name.toString.split("Power_Plug_Socket_").get(1) 
      // Set the command which should be executed to the output channel, Auto trigger will then execute the Thing.
      if(receivedCommand == ON){
        Remote_Send_Args.sendCommand("1XXX1 " + num +" 1")
      }else{
        Remote_Send_Args.sendCommand("1XXX1 " + num +" 0")
      }// Wait for the command to complete
      while(Remote_Send.state != OFF){
        Thread::sleep(100)
      }// Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
      Thread::sleep(400)
      logInfo("Power_Plug", Remote_Send_Out.state.toString.replaceAll("\r|\n"," ") )
    } catch(Throwable t) {}
    finally 
    { // Free the resource for the next call.
      transmitter.unlock()
    }
 end



rule "Poweroutlet 1"
  when
    Item Power_Plug_ABC_1 received command
  then
     if(receivedCommand == ON){
        Remote_CodeSend_Args.sendCommand("1XXXXXX6 4")
     }else{
       	Remote_CodeSend_Args.sendCommand("1XXXXXX0 4")
     }
      // wait for the command to complete
      while(Remote_Send.state != ON){
         Thread::sleep(500)
      }
      logInfo("Power_Plug_ABC_1", "Results are: \n" + Remote_CodeSend_Out.state )
end

I am using Exec 2.4.0.

Thank you in advance.

(Josar) #84

Make the lock global, so outside the rules, and use it in both rules.

val ReentrantLock transmitter = new ReentrantLock

rule "Single Plug"
  when
    Member of G_All_Plugs received command
    // Item of Group Power Plugs received command or
  then

    logInfo("Power_Plug", "Schalter" + triggeringItem.name + " to " + receivedCommand)
    
    try {
      // Lock transmitter so other executed rules dont't use it at the same time, Concurrent calls of the rule will wait till the resource is free again.
      transmitter.lock()
      // Get the item which triggered the rule, Split the name and get the second part, the number to set as command.
      val num = triggeringItem.name.toString.split("Power_Plug_Socket_").get(1) 
      // Set the command which should be executed to the output channel, Auto trigger will then execute the Thing.
      if(receivedCommand == ON){
        Remote_Send_Args.sendCommand("1XXX1 " + num +" 1")
      }else{
        Remote_Send_Args.sendCommand("1XXX1 " + num +" 0")
      }
      // Wait for the command to complete
      while(Remote_Send.state != OFF){
        Thread::sleep(100)
      }
      // Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
      Thread::sleep(400)
      logInfo("Power_Plug", Remote_Send_Out.state.toString.replaceAll("\r|\n"," ") )
    } catch(Throwable t) {}
    finally 
    { // Free the resource for the next call.
      transmitter.unlock()
    }
 end



rule "Poweroutlet 1"
  when
    Item Power_Plug_ABC_1 received command
  then

    try {
      // Lock transmitter so other executed rules dont't use it at the same time, Concurrent calls of the rule will wait till the resource is free again.
      transmitter.lock()
      // Get the item which triggered the rule, Split the name and get the second part, the number to set as command.
      if(receivedCommand == ON){
        Remote_CodeSend_Args.sendCommand("1XXXXXX6 4")
     }else{
       	Remote_CodeSend_Args.sendCommand("1XXXXXX0 4")
     }
     // wait for the command to complete
      while(Remote_Send.state != ON){
         Thread::sleep(500)
      }
      // Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
      Thread::sleep(400)
     logInfo("Power_Plug_ABC_1", "Results are: \n" + Remote_CodeSend_Out.state )
    } catch(Throwable t) {}
    finally 
    { // Free the resource for the next call.
      transmitter.unlock()
    }

end

This is not tested just edited in the browser, please check for typos. But the basic idea should be clear. Please read the comments and try to understand the explenations.


(Martin) #85

Hi Josar (@Josar) ,

first of all, thank you very much for you help and the adjustment of my coding.

did exactly this, but still have the problem, that after one to two times the system is not sending any messages to the devices. I have the feeling that, if one rule is still in execution and I release the next command (next light) the transmitter gets locked and nothing is working again. Before using the transmitter solution I had to send a command twice if the time of execution was to short in sequence. But no, after the problem, I can’t send out any command.

Is there any chance to implement some peace of code that ends or wait another seconds before sending the command, if the transmitter is already locked?

I do not have any Idea.

Could I pn you my rules file? Maybe you could find a bug in it…

Thank you in advance.

Woogi


(Martin) #86

Hi @Josar,

I figured out that the exec is still in sending mode.

image

this is from the second rule with the exec thing Remote_CodeSend. Do you have any idea, why this is happening? I assume that due to the lock of the transmitter sth. is locked and the command not send out properly.

Furthermore I figured out that my dht22 sensor, as well running with an exec, is not providing data, after the problem occurred. After restart of OH, all is fine until I get the problem caused by a power plug and the cycle starts again… :frowning:

Hope you have a solution or hint for me what I could change…

Thank you and sorry for all the questions…

Woogi


(Josar) #87

@Woogi please post your rules here and also make sure that there is no other rule uses the transmitter.

Maybe this is the problem.


(Martin) #88

Hi @Josar,

please find below my coding for 433 MHz transceiver:

import java.util.concurrent.locks.ReentrantLock
// Val for Transmitter, that no problems if two calls comming
val ReentrantLock transmitter = new ReentrantLock

//////////////////////
//////// Switching 433 MHz Devices
//////////////////////
rule "Single Plug"
  when
    Member of G_All_Plugs received command
    // Item of Group Power Plugs received command or
  then

    logInfo("Power_Plug", "Schalter" + triggeringItem.name + " to " + receivedCommand)
    
    try {
      // Lock transmitter so other executed rules dont't use it at the same time, Concurrent calls of the rule will wait till the resource is free again.
      transmitter.lock()
      // Get the item which triggered the rule, Split the name and get the second part, the number to set as command.
      val num = triggeringItem.name.toString.split("Power_Plug_Socket_").get(1) 
      // Set the command which should be executed to the output channel, Auto trigger will then execute the Thing.
      if(receivedCommand == ON){
        Remote_Send_Args.sendCommand("1ABC1 " + num +" 1")
      }else{
        Remote_Send_Args.sendCommand("1ABC1 " + num +" 0")
      }// Wait for the command to complete
      while(Remote_Send.state != OFF){
        Thread::sleep(100)
      }// Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
      Thread::sleep(400)
      logInfo("Power_Plug", Remote_Send_Out.state.toString.replaceAll("\r|\n"," ") )
    } catch(Throwable t) {}
    finally 
    { // Free the resource for the next call.
      transmitter.unlock()
    }
 end
//////////////////////
//////// Update of Status Power Plugs by using manual shutter
//////////////////////
rule "Poweroutlet Update"
  when
      Item MQTT_data changed
  then
      switch MQTT_data.state 
      {
        case "26ABC5": Power_Plug_Socket_1.postUpdate(ON)
        case "26ABC8": Power_Plug_Socket_1.postUpdate(OFF)
        case "26ABC7": Power_Plug_Socket_2.postUpdate(ON)
        case "26ABC0": Power_Plug_Socket_2.postUpdate(OFF)
        case "26ABC5": Power_Plug_Socket_3.postUpdate(ON)
        case "26ABC8": Power_Plug_Socket_3.postUpdate(OFF)
        //case "26ABC7": Power_Plug_Socket_4.postUpdate(ON)
        //case "26ABC0": Power_Plug_Socket_4.postUpdate(OFF)
      }
      if(MQTT_data.state.toString !="") MQTT_data.postUpdate("")
end
//////////////////////////
/////// Leinwand_Remote
//////////////////////////
rule "Leinwand"
  when
    Item Leinwand_Remote received command
  then
    try { //new
        // Lock transmitter so other executed rules dont't use it at the same time, Concurrent calls of the rule will wait till the resource is free again.
        transmitter.lock() //new
     switch (receivedCommand){
      case UP:    
      {
        Remote_CodeSend_Args.sendCommand("ABC") // first stop command due to physical device that first needs stop command
        Thread::sleep(1000) // 1 Second to wait, else the system can not execute both commands.
        Remote_CodeSend_Args.sendCommand("ABC")
      }
      case STOP:  Remote_CodeSend_Args.sendCommand("ABC")
      case DOWN:	
      {
        Remote_CodeSend_Args.sendCommand("ABC")
        Thread::sleep(1000)
        Remote_CodeSend_Args.sendCommand("ABC")
      }
    }logInfo("Leinwand", "Results are: \n" + Remote_CodeSend_Out.state)

   // Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
   Thread::sleep(400) //new
  } catch(Throwable t) {} //new
  finally //new
    { // Free the resource for the next call. //new
      transmitter.unlock() //new
    }
end
//////////////////////////
/////// Leinwand Steuerung Alexa
//////////////////////////
rule "Leinwand Steuerung"
when
  Item Leinwand_Remote_Alexa_UpDown received command
then
  try { //new
        // Lock transmitter so other executed rules dont't use it at the same time, Concurrent calls of the rule will wait till the resource is free again.
        transmitter.lock() //new
    // 0% is up, 100% down, 50% stop (workaround....)
    switch (receivedCommand){
      case 0:    
      {
        Remote_CodeSend_Args.sendCommand("ABC") // first stop command due to physical device that first needs stop command
        Thread::sleep(1000) // 1 Second to wait, else the system can not execute both commands.
        Remote_CodeSend_Args.sendCommand("ABC")
      }
      case 50:  Remote_CodeSend_Args.sendCommand("ABC")
      case 100:	
      {
        Remote_CodeSend_Args.sendCommand("ABC")
        Thread::sleep(1000)
        Remote_CodeSend_Args.sendCommand("ABC")
      } 
     }logInfo("Leinwand", "Results are: \n" + Remote_CodeSend_Out.state)
    
    // Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
    Thread::sleep(400) //new
  } catch(Throwable t) {} //new
  finally //new
    { // Free the resource for the next call. //new
      transmitter.unlock() //new
    }
end
/////////////////////////////////////////////////////////////////////////
/////// Power Plugs Lidl, old Code
//////////////////////////
rule "Poweroutlet Lidl 1"
  when
    Item Power_Plug_Lidl_1 received command
  then
    try {
      // Lock transmitter so other executed rules dont't use it at the same time, Concurrent calls of the rule will wait till the resource is free again.
      transmitter.lock()
      if(receivedCommand == ON){
        Remote_CodeSend_Args.sendCommand("ABC 4")
     }else{
       	Remote_CodeSend_Args.sendCommand("ABC 4")
     }
      // wait for the command to complete
      while(Remote_Send.state != ON){
         Thread::sleep(500)
         }
      // Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
      Thread::sleep(400)
      logInfo("Power_Plug_Lidl_1", "Results are: \n" + Remote_CodeSend_Out.state )
      } catch(Throwable t) {}
    finally 
    { // Free the resource for the next call.
      transmitter.unlock()
    }
end

rule "Poweroutlet Lidl 2"
  when
    Item Power_Plug_Lidl_2 received command
  then
    try {
      transmitter.lock()
      // Get the item which triggered the rule, Split the name and get the second part, the number to set as command.
      if(receivedCommand == ON){
        Remote_CodeSend_Args.sendCommand("ABC 4")
     }else{
       	Remote_CodeSend_Args.sendCommand("ABC 4")
     }
      // wait for the command to complete
      while(Remote_Send.state != ON){
         Thread::sleep(500)
         }
      // Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
      Thread::sleep(400)
      logInfo("Power_Plug_Lidl_2", "Results are: \n" + Remote_CodeSend_Out.state )
      } catch(Throwable t) {}
    finally 
    { // Free the resource for the next call.
      transmitter.unlock()
    }
end

rule "Poweroutlet Lidl 3"
  when
    Item Power_Plug_Lidl_3 received command
  then
    try {
      transmitter.lock()
      // Get the item which triggered the rule, Split the name and get the second part, the number to set as command.
      if(receivedCommand == ON){
        Remote_CodeSend_Args.sendCommand("ABC 4")
     }else{
       	Remote_CodeSend_Args.sendCommand("ABC 4")
     }
      // wait for the command to complete
      while(Remote_Send.state != ON){
         Thread::sleep(500)
         }
      // Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
      Thread::sleep(400)
      logInfo("Power_Plug_Lidl_3", "Results are: \n" + Remote_CodeSend_Out.state )
      } catch(Throwable t) {}
    finally 
    { // Free the resource for the next call.
      transmitter.unlock()
    }
end

rule "Poweroutlet Lidl 4"
  when
    Item Power_Plug_Lidl_4 received command
  then
    try {
      // Lock transmitter so other executed rules dont't use it at the same time, Concurrent calls of the rule will wait till the resource is free again.
      transmitter.lock()
      if(receivedCommand == ON){
        Remote_CodeSend_Args.sendCommand("ABC 4")
     }else{
       	Remote_CodeSend_Args.sendCommand("ABC 4")
     }
      // wait for the command to complete
      while(Remote_Send.state != ON){
         Thread::sleep(500)
         }
      // Mulltiple trigger do not work if there is no break here, maybe external skript needs some time to properly free resources.
      Thread::sleep(400)
      logInfo("Power_Plug_Lidl_4", "Results are: \n" + Remote_CodeSend_Out.state )
      } catch(Throwable t) {}
    finally 
    { // Free the resource for the next call.
      transmitter.unlock()
    }
end

This is the code for the dht22, which wasn’t working any longer as well after the 433 plugs are not working any longer:

//Rule to read transfer the string of the dht22 temperature sensor
rule "Temp"
    when
        Item Temp_wohnzimmer_out received update
    then
        Klima_temp_wz.postUpdate(Temp_wohnzimmer_out.state.toString)
    Thread::sleep(5000)
    logInfo("temp", "Temperatur: " + Klima_temp_wz.state + "°C")
end 

//Rule to read transfer the string of the dht22 humidty sensor
rule "Hum"
    when
        Item Hum_wohnzimmer_out received update
    then
        Klima_hum_wz.postUpdate(Hum_wohnzimmer_out.state.toString)
    Thread::sleep(5000)
    logInfo("Humi", "Luftfeuchtigkeit: " + Klima_hum_wz.state + "%")
end 

Log file is providing the following eg testet this morning:

2019-02-08 09:44:56.665 [INFO ] [se.smarthome.model.script.Power_Plug] - SchalterPower_Plug_Socket_3 to ON
2019-02-08 09:44:57.733 [INFO ] [se.smarthome.model.script.Power_Plug] - using pin 0 sending systemCode[1ABC1] unitCode[3] command[1]
2019-02-08 09:45:00.035 [INFO ] [se.smarthome.model.script.Power_Plug] - SchalterPower_Plug_Lidl_2 to ON
2019-02-08 09:45:12.483 [INFO ] [se.smarthome.model.script.Power_Plug] - SchalterPower_Plug_Socket_1 to ON

As you can see, first switch worked and then nothing was happening. Shouldn’t it be the case that even if the system is still working the request wait until the transmitter is free again?

Sorry, I am a bit lost.

Thank you in advance.


(Josar) #89

OH is configured to have, i think, 5 threads to handle rules. When you use Thread.sleep this occupies a thread. I think this can be a problem.

Maybe there is a hidden error try to print everything.

catch(Throwable t) { logInfo("Throwable", t.getMessage() }

I can also imagine if you have a transmitter and a receiver connected, that you receive what you send and so use up the threads or create an endless loop when triggering a sendcommand on a received command.


(Martin) #90

Hi @Josar,

finally I made it. I figured out that I had a coding bug inside which I developed by putting nearly behind each row a lofInfo :wink: So I discovered that I used the wrong exec command. Instead of Remote_CodeSend_out.state I used Remote_Send_out.state. An other bug was that my single plugs have been assigned to the same group as the Lidl plugs which lead to the issue that the system went in both rules and blocked crosswise.

The only issue I am still having and that is confusing me. During the first received update of the item till the sending, there are 5 seconds. Is that normal?

2019-02-20 21:51:26.559 [ome.event.ItemCommandEvent] - Item 'Power_Plug_Lidl_2' received command ON
2019-02-20 21:51:26.571 [vent.ItemStateChangedEvent] - Power_Plug_Lidl_2 changed from OFF to ON
2019-02-20 21:51:26.582 [GroupItemStateChangedEvent] - G_All_Plugs changed from OFF to ON through Power_Plug_Lidl_2
2019-02-20 21:51:26.587 [GroupItemStateChangedEvent] - Alle_Lichter_WZ changed from OFF to ON through Power_Plug_Lidl_2
2019-02-20 21:51:26.591 [GroupItemStateChangedEvent] - Alle_Lichter changed from OFF to ON through Alle_Lichter_WZ
2019-02-20 21:51:31.721 [ome.event.ItemCommandEvent] - Item 'Remote_CodeSend_Args' received command 1xxxxxx5 4
2019-02-20 21:51:31.730 [nt.ItemStatePredictedEvent] - Remote_CodeSend_Args predicted to become 1xxxx5 4
2019-02-20 21:51:31.737 [vent.ItemStateChangedEvent] - Remote_CodeSend_Args changed from 1xxxx3 4 to 1xxxx5 4
2019-02-20 21:51:31.739 [vent.ItemStateChangedEvent] - Remote_CodeSend changed from OFF to ON
==> /var/log/openhab2/openhab.log <==
2019-02-20 21:51:32.124 [INFO ] [thome.model.script.Power_Plug_Lidl_2] - Results are: sending code[1xxxx3]

Thank you very much for your help. Kindly,
Woogi


(jespiex) #91

Hello all,

(Disclaimer, this is my first post here, hope I am following the rules and proper formatting of my post :slight_smile: )

I just started using OpenHAB a couple of weeks ago and am really enjoying all of the learning and (most of the times succesfully) building of my items, thing, rules etc. Especially thanks to people like @Josar made it possible for me to understand OpenHAB really fast so BIG thank you!

Last year I bought some CoCo (KlikAanKlikUit) 433mhz switches, which I can control using my RaspBerry Pi. For the last three days I really tried to implement Exec binding to turn my CoCo´s on and off. When I issue the command sudo -u openhab /home/pi/wiringPi/raspKaku/kaku A 1 on my CoCo turns on. This tells me the openhab user has enough rights and my command works.

Unfortunately, I just can´t get the Exec binding to work. I tried to implement the easiest way possible to send an ´on´ command. The following is my latest and greatest attempt yet;
I made a thing:

Thing exec:command:yourcommand [ command=“sudo -u openhab /home/pi/wiringPi/raspKaku/kaku A 1 on”, interval=0, autorun=false ]

I made some items:

Switch YourTrigger

// state of the execution, is running or finished
Switch yourcommand {channel=“exec:command:yourcommand:run”}
// Arguments to be placed for ‘%2$s’ in command line
String yourcommand_Args {channel=“exec:command:yourcommand:input”}
// Output of command line execution
String yourcommand_out {channel=“exec:command:yourcommand:output”}

I made a rule; rule "Your Execution" when Item YourTrigger changed then yourcommand_Args.sendCommand() end

And of course I added the switch to the sitemap withSwitch item=YourTrigger

But for the love of… the CoCo won´t turn on. Does anyone has any clue as to where I could poke some more to make this work? logging is clean, it only states the trigger switching from on to off. (Edit, formatting and thanks to OP)


(Udo Hartmann) #92

I’m pretty sure you have to set autorum=true (that is: if input is updated, run the command automatically)

Please always use code fences when posting code, configuration or logs.