Broadlink binding for RMx, A1, SPx and MP. Any interest?

thanks… ill try it and report back…

Hi @lagging
there is 1st version of my rule. I did not tested yet with real IR codes but looking at the logs it works:

rule "Imposta Canale Sky"
when
	Item SALOTTO_IR_IFTTT received command
then
    val sState = SALOTTO_IR_IFTTT.state.toString
	logInfo("IR.SKY.Channel","Ricevuto Canale Sky "+sState)
    
    var len = sState.length
    logInfo("IR.SKY.Channel","Lunghezza Canale Sky "+len.toString)

    var String digit = ""
    var int charIndex = 0
    while(charIndex < sState.length){
        digit = sState.toString.substring(charIndex,charIndex+1)
        logInfo("IR.SKY.Channel","index Ciclo / Digit da Inviare :"+charIndex.toString+" / "+digit)
        SALOTTO_IR.sendCommand("IR_SKY_"+digit)
        Thread::sleep(500)
        charIndex = charIndex+1
    }

end

Basically IFTTT update item SALOTTO_IR_IFTTT with the string containing the channel (IE 401 or 5001), then rule iterate throught digit of received string and Update the Broadlink Item (SALOTTO_IR) with the map name IR_SKY_ and the digit. A sleep should give time to broadlink to receive command and sent to my TV set top Box.

This Night I will test.

Marco

1 Like

The Broadlink RM2 was working for months… then I had to reset it and re-add it to openhab.
Now I’m getting

OFFLINE - CONFIGURATION_ERROR

I added the IV and Authentication key…
anything changed recently?

Thanks

:slightly_smiling_face: this just proves how many different ways there are to achieve a goal. I had not thought about using lenght + substring that way. I’d have gone with regex digit by digit until null :slightly_smiling_face:
Yours is way leaner.

Inspired by @marcolino7’s question (and solution), I I have fashioned together a BUFFER for the outgoing commands, to be sent via a a RM device to the other RF433 controlled devices, either coming from different sources in short bursts or at the same time from a single source.

My situation is that I have different devices in separate rooms controlled via a single rf433 Broadlink RM3(still in range), so the chance of more than one command arriving as input to OH and needing to be sent almost simultaneously by the RM3 is quite real.

@marcolino7 ’s situation is that he receives 1,2,3 or 4 digits as a string from IFTTT (from a hook from a Google voice command), and those need to be chained into 1,2,3 or 4 IRcommands.

In short, I thought- both situations could be solved creating a “buffering into a pipeline of commands” mechanism, like a queue at the butcher’s of sorts.

Starting from imports, you will need
import java.util.HashMap
import java.lang.String
and the following global variables:
var Timer rf433Timer = null
var String rfqueue=''
var String rfqueueB=''

At this point you also need to have created (as per the guides for this binding) a broadlink.map file with your rf commands in hex code format, matching them to command names(command_name = hex code).

Take note of the ms needed for each command to work properly, as that is the length of the timeout for that command, then place them in a HashMap within your rules file as global val(L not R). Mine spread between 800ms(-ish) for ON/OFFs and 4800ms for a 50% dimmer increase/decrease, so this is my hashmap:

val HashMap<String,Integer>timeoutMap = newHashMap(
'Dario_Luce_Toggle' -> 750, 'Dario_Led_On' ->850, 'Dario_Led_Off'->850, 'Dario_Dimmer'->4800, 'Dario_MemDim'->850, 'Dario_Vent_Off'->800, 'Dario_Vent_1'->850, 'Dario_Vent_2'->850, 'Dario_Vent_3'->850,
'Camera_Luce_Toggle' -> 750, 'Camera_Led_On' ->850, 'Camera_Led_Off'->850, 'Camera_Dimmer'->4800, 'Camera_MemDim'->850, 'Camera_Vent_Off'->800, 'Camera_Vent_1'->850, 'Camera_Vent_2'->850, 'Camera_Vent_3'->850,
'Sogg_Luce_Toggle' -> 750, 'Sogg_Led_On' ->850, 'Sogg_Led_Off'->850, 'Sogg_Dimmer'->4800, 'Sogg_MemDim'->850, 'Sogg_Vent_Off'->800, 'Sogg_Vent_1'->850, 'Sogg_Vent_2'->850, 'Sogg_Vent_3'->850)

Create your own dummies representing statuses of your own RF433 or IR commanded items. You may want to expose those dummies vie openhabcloud and tag them to receive voice commands.

Add the followinng to your items:

String RM3_in <text>
String RM3_Queue <text>
String RM3_out <text> {channel="broadlink:rm3:_____xyz______:command"}
Switch RM3_Busy_lock <switch>

Then write a set of rules, that aside from representing the correct logic statuses of your devices on your sitemap, all send their commands to a first collector dummy item, that I called RM_in.
The commands sent are the names of the commands you have defined in the broadlink.map.

An example from my rules:

 rule"fan ON while powered on"
     when 
      Item Vent_Dario received command ON or Item Vent_Dario received command OFF
      then
      if (receivedCommand==ON){
        PotVent_Dario.postUpdate(1)
        sendCommand(RM3_in,"Dario_Vent_1")}
      if (receivedCommand==OFF){
        PotVent_Dario.postUpdate(0)
        RM3_in.sendCommand("Dario_Vent_Off")
      }
 end

RM3_in feeds into the FIRST “digestion” RULE for the buffer/queue.
The buffer is represented in this rule by the 2 global variables (rfqueue for the first command it receives, and it stores the following ones in the global variable rfqueueB), and at the first entry in the queue, feeds also into the item RM3_Queue, which triggers the follow-up second rule.

rule "Feeding the RF433 queue"
when Item RM3_in received command
then
if(rfqueue==''){
    rfqueue=receivedCommand.toString
    RM3_Queue.postUpdate(rfqueue)
    logInfo("FEEDING RFQUEUE","addedto it: "+rfqueue)
 }
 else {
  if (rfqueueB==''){
    rfqueueB=receivedCommand.toString
  }
  if (rfqueueB!=''){
     rfqueueB=rfqueueB+"-"+receivedCommand.toString  
  }
  logInfo("FEEDING RFQUEUE-BUSY!","rfqueueB waiting to be added"+rfqueueB)
 }
RM3_in.postUpdate('-')
end

IN THE SECOND “output” RULE
-The rule checks if the rfqueue and rfqueueB are empty and if rfqueueB isn’t, it chains it after the old rfqueue (and empties it)
-takes the oldest command received and sends it to RM3_Out (the item linked to the channel of the binding in your items file- finally!)
-matches it to the duration of the command in the hashmap and creates a timer forcing the queue to wait for their turn.
-saves the remaining part of the que into the variable rfqueue and into the item RM3_Queue, effectively triggering (the rule) itself to restart, until the queue is empty.

rule "Emptying the RF433 queue- transmitting commands"
when Item RM3_Queue changed
then
 logInfo("RFQUEUE","LOCK?")
  if(RM3_Busy_lock==OFF){
  return;      
  }
  else{
    if(rfqueueB!=''){
      postUpdate(RM3_Busy_lock,OFF)
      logInfo("RFQUEUE","PASSED, locked")
      logInfo("RFQUEUE","rfqueueB to be added! "+rfqueueB)
       if (rfqueue!=''){
         logInfo("RFQUEUE","rfqueueB:the rfqueue was NOT empty")
         rfqueue=rfqueue+"-"+rfqueueB
         rfqueueB=''
       }
       if (rfqueue==''){
         logInfo("RFQUEUE","rfqueueB:the rfqueue was empty")
         rfqueue=rfqueueB
         rfqueueB=''
       }
    } 
    if(rfqueue!=''){
      postUpdate(RM3_Busy_lock,OFF)
      logInfo("RFQUEUE","que not empty, PASSED, locked")
      var String remainingQueue=''
      var String currentCommand=''
        if(!rfqueue.contains("-")){
            currentCommand=rfqueue
            logInfo("RFQUEUE","Que with single command: "+rfqueue)
            remainingQueue=''
         }
        if(rfqueue.contains("-")){
            currentCommand=rfqueue.split('-').get(0)
            logInfo("RFQUEUE","que with minuses,current command: "+currentCommand)
             var int stripIndex = (currentCommand.length()+1)
            remainingQueue=rfqueue.substring(stripIndex)
            logInfo("RFQUEUE","que with minuses,remainingQue: "+remainingQueue)
         }
     if(rf433Timer===null){
         var timeout=timeoutMap.get(currentCommand)
         var notifyme="received "+currentCommand+" so will wait for "+timeout+"ms "
         logInfo("EXTRACTION FROM HASHMAP","REPORT:"+notifyme)
         RM3_out.sendCommand(currentCommand)
         logInfo("RFQUEUE","The remaining Queue that arrives "+remainingQueue)
         rf433Timer= createTimer(now.plusMillis(timeout),[|
             rfqueue=remainingQueue
             RM3_out.postUpdate('')
             logInfo("RFQUEUE","UNLOCKED")
             postUpdate(RM3_Busy_lock,ON)
             rf433Timer=null
             RM3_Queue.postUpdate(rfqueue)
          ])
        }
    } 
  }
end

NOTE1:
In testing the flow of rules within simple UI (and using way longer command durations to be able to follow what happens), I’ve noticed some double commands as a response to a single click… If you experience anything similar, that behaviour of course is unavoidable and mirrored in the Queue….

NOTE2:
Somehow, logically, in the second rule, last block, I’d have liked for the line rfqueue=remainingQueue to be positioned right before the Timer lambda (VSC complains about it as well), but then, while testing it, someweird behaviours appeared when feeding new commands to rfqueueB while rfqueue wasn’t empty. I haven’t found any better solution than having the mentioned line inside the lambda (…empirically it works…)

NOTE3:
As I haven’t been able to make reentrant lock and timers play nice with each other (timers slip into another thread and the re-entrant lock in the original thread unlocks too soon), I chose to prioritize the use of Timer vs Thread::sleep over the use of re-entrant lock.

On the way I tried to simulate a comparable behaviour was with a dummy item called RM3_Busy_lock, however in the end it is almost useless, as feeding RM3_Queue EXCLUSIVELY the first time from the input rule, and the remaining times at the end of the output rule to cycle back, while passing the meaningful data through global variables, is effectively already achieving the desired effect…

However RM3_Busy_lock comes with a perk:
it can be used to colour any rf433 Item in your sitemap, so you get a graphical representation of the actual “busy - sending” situation , with labelcolor=[RM3_Busy_lock==OFF="red", RM3_Busy_lock==ON="green"] valuecolor=[RM3_Busy_lock==OFF="red", RM3_Busy_lock==ON="green"] .

NOTE4:
I’ve noticed that using global variables instead of items to pass stringed Queue values from a rule to another has resulted in more reliable execution, yet, because the last rule in the pipeline needs to be triggered by something, the item RM3_Queue comes into play (following the variable rfqueue really)

CONCLUSION:
I’m hoping this way we’ll all get a nice stream of commands no matter how many you throw at the RM_, and all will be transmitted correctly in due time and orderly fashion.

Using this mechanism there is no need to put a Thread::sleep in each and every rule involving an rf433/IR command, and the risk of having 2 rules firing almost simultaneously blocking 2 threads and loosing at least one of the commands in the process is avoided all together.

My first tests seem positive, if you’re happy with it, you can obviously remove all the logInfo s as I’ve placed them for my own troubleshooting purposes.

PLEASE UNDERSTAND. that I have been learning to program following rulesDSL and @rlkoshak’s design patterns for about 6 months,I’m no expert, my solution can be improved and built upon, shortened and solidified, by knowledgeable peeps on this forum, it’s possibly the first decently complex thing I’ve written.

I thought for instance of feeding the queue into a list type variable and than a for.each type lambda with a timer… or maybe a re-entrant queue …but I got lost in the caveats of the stuff I don’t know nor understand and decided to work with what I kinda grasped so far.
Feel free to improve on this, share and explain why&how, I, for one, am eager to learn…

PS
If you wanna play with it, for testing purposes,I used a sitemap like this:

Frame label="input"{
   Switch item=RfTest label="Comandi" mappings=['Dario_Luce_Toggle'=Luce, 'Dario_Led_On'=Led_On, 'Dario_Led_Off'=Led_Off, 'Dario_Dimmer'=Dimmer, 'Dario_MemDim'=MemDim, 'Dario_Vent_Off'=Vent_Off, 'Dario_Vent_1'=Vent_1, 'Dario_Vent_2'=Vent_2, 'Dario_Vent_3'=Vent_3]
}
Frame label="gestione Broadlink RM3"{
    Text item=RM3_in label="Rm3 IN [%s]" icon="text"
    Text label="" icon=""
    Text item=RM3_Queue label="Rm3 Queue[%s]" labelcolor=[RM3_Busy_lock==OFF="red", RM3_Busy_lock==ON="green"] icon="text"
    Text item=RM3_Busy_lock label="RM3_Busy? [MAP(available.map):%s]" labelcolor=[RM3_Busy_lock==OFF="red", RM3_Busy_lock==ON="green"] valuecolor=[RM3_Busy_lock==OFF="red", RM3_Busy_lock==ON="green"]icon="switch"
    Text item=RM3_out label="Rm3 OUT [%s]" icon="text"
}

ofc adding to your items also
String RfTest <switch>

and available.map in the transform folder

ON=Available
OFF=BUSY
-=-
undefined=-
uninitialized=-
NULL=-

Hope you’ll Njoy it!

Have you seen the Design Pattern: Gate Keeper post? In particular the version using Thread safe queues?

I think it is a way simpler approach and more importantly a safer approach. Depending on timing, trying to maintain the queue in a String is going to get double entries or miss entries entirely. And using reentrant locks can be really dangerous.

I posted my previous post on friday , at the time i had already read through the gatekeeper DP but did not understand it properly until saturday (most likely because of the pains i went through to write this solution of mine, as i said i’m learning).

Regarding safety of data through strings: with the double global vars rfqueue and rfqueueB my buffer is doing pretty well, even if the que gets fed new values while the timer lambda is running. At this time i’m not sure what will happen with the reentrant.queue in that condition, but that is besides the point:
simplicity makes for better code - I’ll do some reading, give it a try and see!

Any further concearn or issue i might face, i’ll post in that thread before reposting an improved version here.

Following @rlkoshak’s advice (Thank you!) i reworked the Buffer :slight_smile:

Now it’s way more compact

  • instead of using 2 global variables (rfqueue+rfqueueB) it uses only one
  • instead of being split in 2 rules it’s all in a single one
  • there is no use anymore for the item Rm3_Queue, all remaining items and (also in the sitemap) stay as they were
  • I have kept the hashMap use i for varying the lenght of the looping timer.
  • i have kept RM3_Busy_lock purely to paint in red the items while sending a command and in green when available (in the sitemaps), you can remove it if you wish.
  • there are a few postUpdate(Item_Name,'') -those in my mind are pure “tidying up”, but aren’t strictly necessary and can be removed
  • again all logInfo -'s are there for debugging purposes and follow my own need for clarity. they can all be removed or changed according to your own wishes.

For simplicity’s sake, i’m pasting here my whole rules relevant section, including imports:

import java.util.HashMap
import java.util.concurrent.ConcurrentLinkedQueue

var ConcurrentLinkedQueue<String> rfqueue = new ConcurrentLinkedQueue()
var Timer rf433Timer = null

val HashMap<String,Integer>timeoutMap = newHashMap(
'Dario_Luce_Toggle' -> 750, 'Dario_Led_On' ->850, 'Dario_Led_Off'->850, 'Dario_Dimmer'->4800, 'Dario_MemDim'->850, 'Dario_Vent_Off'->800, 'Dario_Vent_1'->850, 'Dario_Vent_2'->850, 'Dario_Vent_3'->850,
'Camera_Luce_Toggle' -> 750, 'Camera_Led_On' ->850, 'Camera_Led_Off'->850, 'Camera_Dimmer'->4800, 'Camera_MemDim'->850, 'Camera_Vent_Off'->800, 'Camera_Vent_1'->850, 'Camera_Vent_2'->850, 'Camera_Vent_3'->850,
'Sogg_Luce_Toggle' -> 750, 'Sogg_Led_On' ->850, 'Sogg_Led_Off'->850, 'Sogg_Dimmer'->4800, 'Sogg_MemDim'->850, 'Sogg_Vent_Off'->800, 'Sogg_Vent_1'->850, 'Sogg_Vent_2'->850, 'Sogg_Vent_3'->850)

rule "RF433 buffering in a single rule"
when Item RM3_in received command
then
    var String lastCommand=receivedCommand.toString
    rfqueue.add(lastCommand)
    postUpdate(RM3_in,'')
    var String currentQue=rfqueue.toString
    var String notifyMe1=lastCommand+" so the queue now is "+currentQue
    logInfo("RF433 Buffer","outside the loop: added "+notifyMe1)
    if(rf433Timer !== null){
      logInfo("RF433 Buffer","outside the loop: not interferring with the running Timer")
      }
    else{
        rf433Timer = createTimer(now, [ |
        logInfo("RF433 Buffer","iterating the output loop")
        postUpdate(RM3_Busy_lock,ON)
        postUpdate(RM3_out,'')
        var currentCommand = rfqueue.peek
        if(currentCommand === null) {
           rf433Timer = null
           logInfo("RF433 Buffer","inside the loop- LAST RUN")
          }
        else {
           postUpdate(RM3_Busy_lock,OFF)
           RM3_out.sendCommand(rfqueue.poll) 
           var timeout=timeoutMap.get(currentCommand)
           var notifyMe2="sent "+currentCommand+" so will wait for "+timeout+"ms "
           logInfo("RF433 Buffer","inside the loop: "+notifyMe2)
           var exitingQue=rfqueue.toString
           logInfo("RF433 Buffer","inside the loop: the remaining Queue is "+exitingQue)
           rf433Timer.reschedule(now.plusMillis(timeout))
          }
        ])
     }
end

The following portion is relevant if you want to test it with the RfTest item i mentioned at the end of my previous post, to quickly throw at the buffer as many commands as possible.

rule "extraction from hashmap"
when Item RfTest changed
then
if(RfTest.state instanceof StringType) {
var myKey=RfTest.state.toString
sendCommand(RM3_in,myKey)
}
end

Hope it works for everyone, any constructive feedback is welcome :slight_smile:

1 Like

it’s really interesting. thanks for sharing

i have one Rm2 and 4 mini. is there to instantiate easy this code for each device?

G

Wow, you really have many of them!
I guess it’s doable.
If the command names contain a first part which tells you their destination room (and so the target rm_ you need to transmit the command from), you can declare and name the number of concurrent queues you need at the beginning as global vars and then feed the right queue for the corresponding device, maybe within a single rule.

I don’t have any time to tinker with it until the end of the week(if I’m lucky, else after the 16th Aug)… If you wish to move it forward, look into the DRY DP

Thanks Dario. i will go to vacation and i will have a look

Thanks for sharing !!! and contributing

@themillhousegroup, this could be self explanatory as the binding is called 2.4, but does it only work with openhab 2.4?
I’m using latest 2.5 at the moment (snapshot) and it throws errors when searching for things.

2019-08-07 10:51:23.251 [WARN ] [org.apache.felix.fileinstall        ] - Error while starting bundle: file:/C:/openHAB2/addons/org.openhab.binding.broadlink-2.4.0-BETA-17.jar
org.osgi.framework.BundleException: Could not resolve module: org.openhab.binding.broadlink [298]
  Another singleton bundle selected: osgi.identity; type="osgi.bundle"; version:Version="2.2.0.201707060032"; osgi.identity="org.openhab.binding.broadlink"; singleton:="true"

	at org.eclipse.osgi.container.Module.start(Module.java:444) ~[?:?]
	at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:383) ~[?:?]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1260) [10:org.apache.felix.fileinstall:3.6.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1233) [10:org.apache.felix.fileinstall:3.6.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:1221) [10:org.apache.felix.fileinstall:3.6.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:515) [10:org.apache.felix.fileinstall:3.6.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:365) [10:org.apache.felix.fileinstall:3.6.4]
	at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:316) [10:org.apache.felix.fileinstall:3.6.4]
2019-08-07 10:51:29.707 [WARN ] [org.eclipse.jetty.server.HttpChannel] - /rest/discovery/bindings/broadlink/scan
javax.servlet.ServletException: javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.IncompatibleClassChangeError: Expected static field org.openhab.binding.broadlink.internal.discovery.BroadlinkDiscoveryService.scheduler
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:88) ~[?:?]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) ~[90:org.eclipse.jetty.server:9.4.18.v20190429]
	at org.eclipse.jetty.server.Server.handle(Server.java:505) ~[90:org.eclipse.jetty.server:9.4.18.v20190429]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370) [90:org.eclipse.jetty.server:9.4.18.v20190429]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267) [90:org.eclipse.jetty.server:9.4.18.v20190429]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305) [80:org.eclipse.jetty.io:9.4.18.v20190429]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) [80:org.eclipse.jetty.io:9.4.18.v20190429]
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) [80:org.eclipse.jetty.io:9.4.18.v20190429]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333) [93:org.eclipse.jetty.util:9.4.18.v20190429]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310) [93:org.eclipse.jetty.util:9.4.18.v20190429]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168) [93:org.eclipse.jetty.util:9.4.18.v20190429]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126) [93:org.eclipse.jetty.util:9.4.18.v20190429]
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366) [93:org.eclipse.jetty.util:9.4.18.v20190429]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:698) [93:org.eclipse.jetty.util:9.4.18.v20190429]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:804) [93:org.eclipse.jetty.util:9.4.18.v20190429]
	at java.lang.Thread.run(Unknown Source) [?:?]
Caused by: javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.IncompatibleClassChangeError: Expected static field org.openhab.binding.broadlink.internal.discovery.BroadlinkDiscoveryService.scheduler
	at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:489) ~[?:?]
	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228) ~[?:?]
	at com.eclipsesource.jaxrs.publisher.internal.ServletContainerBridge.service(ServletContainerBridge.java:76) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:873) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:542) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146) ~[?:?]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) ~[?:?]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) ~[?:?]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1700) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) ~[?:?]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480) ~[?:?]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1667) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201) ~[?:?]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) ~[?:?]
	... 15 more
Caused by: org.glassfish.jersey.server.ContainerException: java.lang.IncompatibleClassChangeError: Expected static field org.openhab.binding.broadlink.internal.discovery.BroadlinkDiscoveryService.scheduler
	at org.glassfish.jersey.servlet.internal.ResponseWriter.rethrow(ResponseWriter.java:278) ~[?:?]
	at org.glassfish.jersey.servlet.internal.ResponseWriter.failure(ResponseWriter.java:260) ~[?:?]
	at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:509) ~[?:?]
	at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:334) ~[?:?]
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) ~[?:?]
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) ~[?:?]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:315) ~[?:?]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:297) ~[?:?]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:267) ~[?:?]
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317) ~[?:?]
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305) ~[?:?]
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154) ~[?:?]
	at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473) ~[?:?]
	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228) ~[?:?]
	at com.eclipsesource.jaxrs.publisher.internal.ServletContainerBridge.service(ServletContainerBridge.java:76) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:873) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:542) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146) ~[?:?]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) ~[?:?]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) ~[?:?]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1700) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) ~[?:?]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480) ~[?:?]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1667) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201) ~[?:?]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) ~[?:?]
	... 15 more
Caused by: java.lang.IncompatibleClassChangeError: Expected static field org.openhab.binding.broadlink.internal.discovery.BroadlinkDiscoveryService.scheduler
	at org.openhab.binding.broadlink.internal.discovery.BroadlinkDiscoveryService.waitUntilEnded(BroadlinkDiscoveryService.java:56) ~[?:?]
	at org.openhab.binding.broadlink.internal.discovery.BroadlinkDiscoveryService.startScan(BroadlinkDiscoveryService.java:44) ~[?:?]
	at org.eclipse.smarthome.config.discovery.AbstractDiscoveryService.startScan(AbstractDiscoveryService.java:211) ~[?:?]
	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScan(DiscoveryServiceRegistryImpl.java:382) ~[?:?]
	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScans(DiscoveryServiceRegistryImpl.java:367) ~[?:?]
	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScan(DiscoveryServiceRegistryImpl.java:216) ~[?:?]
	at org.eclipse.smarthome.io.rest.core.internal.discovery.DiscoveryResource.scan(DiscoveryResource.java:97) ~[?:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
	at java.lang.reflect.Method.invoke(Unknown Source) ~[?:?]
	at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81) ~[?:?]
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144) ~[?:?]
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161) ~[?:?]
	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160) ~[?:?]
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99) ~[?:?]
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389) ~[?:?]
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347) ~[?:?]
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102) ~[?:?]
	at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326) ~[?:?]
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) ~[?:?]
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) ~[?:?]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:315) ~[?:?]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:297) ~[?:?]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:267) ~[?:?]
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317) ~[?:?]
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305) ~[?:?]
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154) ~[?:?]
	at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473) ~[?:?]
	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341) ~[?:?]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228) ~[?:?]
	at com.eclipsesource.jaxrs.publisher.internal.ServletContainerBridge.service(ServletContainerBridge.java:76) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:873) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:542) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146) ~[?:?]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) ~[?:?]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) ~[?:?]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1700) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) ~[?:?]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) ~[?:?]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480) ~[?:?]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1667) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201) ~[?:?]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247) ~[?:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144) ~[?:?]
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) ~[?:?]
	... 15 more

cheers!

Well, it seemed there was a couple of things that I remedied to get it working.
1, Openhab had cached an older version (2.2) of the binding and had that active instead of the new one.
I stopped it and uninstalled it via karaff.
Started the new binding and didn’t have any logged errors.
But I could not get the RM3 to be discovered, but manually it worked like a charm.
I think somehow my network is probably blocking multicast (?).
Great binding and thank you!

Hello, i’m sorry but I filled the fields as indicated and I have a warning that appears at the top of the page which mentions in red that the MAC address does not correspond to a RM2

I experienced same error and reason was that RM bridge was running on phone not connected on same wifi ssid as RM3. Could you check if both android device with RM bridge and your broad link are on same network. RM bridge must be running (green circle with word Started)

Yes the RM bridge is well started with the green circle and it is on the same network because I run http://rm-bridge.fun2code.de/rm_manage/code_learning.html with chrome on the same phone!
I also tested by connecting my tablet (which is also on the same SSID as the phone) on http://rm-bridge.fun2code.de/rm_manage/code_learning.html and I have the same error
if I insist several times I then have an error HTTP/404

Hi, I have a RM3 mini and I downloaded the latest bingind (rev.17) but can’t find the RM3 ?
Is there any way to add it manually?
Thanks Lorenzo

I was not probably clear - could you confirm your broadlink device is on same wifi SSID as your phone where you run RM bridge please

Hi, yes you can add it manually:

  • in Paper UI in inbox click on +
  • click on Broadling binding
  • click Add Manually
  • select Broadlink RM3
  • fill 097628343fe99e23765c1513accf8b02 in Authentication Key field
  • fill 562e17996d093d28ddb3ba695a2e6f58 in IV field
  • click on Show More
  • input IP address of your RM3 device in field Network address
  • input 80 in network port
  • input MAC address of your RM3 device to field MAC address

if you have static IP - keep on Static IP switch,
if your RM3 get address randomly by DHCP - switch Static IP to OFF

now click on add (blue circle on top) and it’s done

I confirm that RM bridge and the RM3 mini box are of course the same SSID wifi … by cons I entered the keys you gave in the post following your answer to know:
097628343fe99e23765c1513accf8b02 for the authentication key
562e17996d093d28ddb3ba695a2e6f58 for the key IV
and my thing has become active
Now it has evolved: I manage to enter without error manually …

Thank you

now how do I insert these codes?
In my item