How to send IR commands synchroneously

Hello, I need to send sequences of IR commands using IRTrans binding.
Currently, I have only one item declared as:
String IR_mRDC_Salon_command {irtrans="[192.168.0.2:21000:*:*:*]"}

Then, I send commands in a rule with:

IR_mRDC_Salon_command.sendCommand("mydevice,mycommand1")
IR_mRDC_Salon_command.sendCommand("mydevice,mycommand2")
IR_mRDC_Salon_command.sendCommand("mydevice,mycommand3")

Because of the asynchroneous nature of sendCommand(), how can I make sure that the IRTrans binding queues the commands in the right order?
I could use the item state update to manage my own command queue. But this would work if the state update occurs AFTER the command is processed by the hardware. Is this the case?

Any other idea to send commands synchroneously?

Thank you

Hi, i have had a similar problem for my Media receiver with channel commands more than one digit…

I used Thread::Sleep to solve this

rule "T-Home Alexa Voice commands" when Item THOME_PRG_SELECT changed to 491 or Item THOME_ZDF_INFO received command ON then LR_THOME_DVR.sendCommand("4") Thread::sleep(2) LR_THOME_DVR.sendCommand("9") Thread::sleep(2) LR_THOME_DVR.sendCommand("1") Thread::sleep(2) LR_THOME_DVR.sendCommand("NumberEnter") end

Thread::sleeps are probably the way to go for this. If you are planning on issuing commands to your IR device from more than one Rule, I recommend Design Pattern: Gate Keeper to centralize the sending of the commands to the IR device so you only have one place where you need to add the Thread::sleeps or any other logic you may need to add.

You could do something like:

IR_mRDC_Salon.sendCommand("mydevice,mycommand1 mydevice,mycommand2 mydevice,mycommand3")

and in the GateKeeper Rule

import java.util.concurrent.locks.ReentrantLock
var lock = new ReentrantLock

rule "IR Controller"
when
    Item IR_mRDC_Salon received command
then
    lock.lock // Ensures only one instance of the Rule can run at a time
    try {
        val cmds = receivedCommand.split(" ")
        cmds.forEach[cmd | 
            IR_mRDC_Salon_command.sendCommand(cmd)
            Thread::sleep(10)
        ]
    }
    catch(Exception e) {
        logError("IR", "Error handling IR command: " + e)
    }
    finally {
        lock.unlock
    }
end

By combining all the commands into one sendCommand it reduces the number of events in the system and guarantees that all those related commands get executed together and in order.

The lock prevents more than one instance of this Rule from running at a time. So if another command comes in while this on is running that new command has to wait until this one is done.

The Thread::sleep at the end of the for loop guarantees that there will always be that amount of time between commands to the IR device, even if the Rule gets triggered more than once at a time.

1 Like

Great! Thank you!
I refined slightly the rule to allow providing repetition on IR codes: syntax is a space-separated string of

device,command[:repeat]

import java.util.concurrent.locks.ReentrantLock
    var lock = new ReentrantLock


rule "IR Controller 2"
when
    Item IR_mRDC_Salon_send received command
then
    lock.lock // Ensures only one instance of the Rule can run at a time
    try {
        val String[] cmds_iters = receivedCommand.toString.split(" ")

        cmds_iters.forEach[String cmd_it | 
            if(cmd_it.indexOf(":") == -1){
				IR_mRDC_Salon_command.sendCommand(cmd_it)
				Thread::sleep(5)
			}
			else{
				val String[] strsplit = cmd_it.split(":")
				val String cmd = strsplit.get(0)
				val int nbiter = Integer.parseInt(strsplit.get(1))
				for (var i = 1 ; i <= nbiter ; i++){
					IR_mRDC_Salon_command.sendCommand(cmd)
					Thread::sleep(5)
				}
			}
        ]
    }
    catch(Exception e) {
        logError("IR", "Error handling IR command: " + e)
    }
    finally {
        lock.unlock
    }
end

That also made me discover the ‘Design pattern’ topics that will be helpful as I will migrate progressively all my automation scripts written in Python from Evenghost to openHAB.