Broadlink IR sending inconsistent data

I am running the latest version of HA with a Broadlink integration and an RM4C mini.
I have learned codes and set up buttons to run the codes. The codes run just fine if pressed once but more often than not, a second press of the SAME code will send two sets of codes.
To illustrate: I press ‘1’ I get ‘1’ if I press ‘1’ again so as to get 11 (channel), I get 111. This is repeated with all the number buttons where the result can be clearly seen. It seems to happen with all other buttons as well but since there is no visible feedback, it is hard to tell for sure.
Any idea what I could have done wrong in the setup - the traditional remote works as expected.
Oh, I can press 12345 and I actually get 12345 … it’s only if I press a key twice in a row that the error occurs. If I pres 1223 I get 12223. If I press the ‘2’ keys rapidly I will get only a single key transmitted as in I send 1223 but hit the ‘2’ too quickly one after the other and it translates as ‘123’ and if I wait a bit too long between the ‘2’ keys I will see ‘12223’.
I am suspecting a connection to delay_secs and hold_secs for skipping the second key in pressing the key rapidly but haven’t got a clue how pressing the same key twice can send three commands for the same key.

Any help would be appreciated.

A quick update - I ‘learned’ the code for ‘1’ again and sent it back out with the remote.send_command and it behaves exactly the same - pressed once I get ‘1’ pressed twice I get ‘111’ (or two ones when the second one is sent). I tried different delay and hold times with no change observed. I again confirmed that if I press the ‘1’ twice on the standard remote control, the received code is ‘11’.

I had a similar issue when I first bought the broadlink. Besides learning individual commands, try to learn sequences… if you want 11 to work, try the following:

      - service: remote.learn_command
        data:
          entity_id: remote.your_remote
          device: television
          command:
            - 1
            - 1

It might not be practical though, depending on your usecase

Thanks obaldius but that just isn’t practical. I would have to have a button for every channel I watch (ie ch 211 because of the ‘11’ combination) and ch 213 since I can’t have some channels on a single button and others on multiple buttons. The way I have set things up is that there is a script for each button (or presumably button sequence) so all of a sudden you add let’s say 100 different scripts that show up every time you want to use the entity picker for anything making this a big mess. It’s bad enough having to dig through all the scripts even though there are only maybe 50 so far. I haven’t figured out yet how to break things up or if it is even practical to break things up.

I understand. If you’re into Node Red you could give this a shot, it might work better:

I haven’t tried it myself though

This subject can get quite tricky…

Are you doing everything via the UI or do you learn buttons by capturing codes, retrieving it from the log and then manually coding the scripts?

I’d you have the raw codes, try to compare it with a DB like this: http://irdb.tk/find/.

I couldn’t find the right terms now and can’t remember exactly but there are different encodings and protocols. My suspicion is that your original remote is sending some kind of composite code and what’s captured isn’t exactly right, or said differently, not what the device is expecting on the second keypress.

This is highly speculative, but capture the same button twice (without pressing anything else in between) and see if the codes are identical. Perhaps the original remote control has some kind of state that affects multiple button presses. Or, if it is indeed identical, wait longer or shorter between repeated (simulated) presses to see if it makes a difference.

I am mixing up ui and yaml but for these tests I am doing strictly ui so as to not introduce an error somehow.
Great idea about capturing a double key press and comparing it.
Thanks!

parautenbach, great idea but unfortunately there must be some ‘this is the end of the key press code’ kinda thing embedded because I can not learn the code for two presses of the ‘1’ key. The RM4C Mini knows that I have hit the ‘1’ key and thinks it is done.

obaldius, you had another method of learning two codes but I do not understand how to implement this since all my code learning was done through the remote.learn_command service from the ui.

I compared the learned codes from earlier (button 1) with the new recording of what was supposed to be button 11 (but recorded as a button 1). Anyway, the two codes did not match!
There was some mention of ‘rolling codes’ in my research - I will dig into what exactly that is and see if maybe there is a link.

1 Like

Learned 4 more instances of the ‘1’ button and they are all different from each other but all result in a ‘1’ received if pressed once and multiple one’s received when the ‘1’ is pressed a second time.

Capture them separately, one after the other and compare the two codes – not as part of the same learn action.

EDIT: That will teach me to read everything before replying. I see you got further with it now.

I did it from the UI too. In my case, I fristly learnt all individual codes from the UI: 1, ,2, 3, etc… Once all were learned, I assumed that if I called the send_command service like the example below it would work:

      - service: remote.send_command
        data:
          entity_id: remote.your_remote
          device: television
          command:
            - 1
            - 2
            - 3

But it didn’t, it was inconsistent… so I ended up learning all sequences and they worked.

It worked for me because I just had like 15 or 20 codes to be learned… but if you want to emulate all the combinations this is definetely not practical.

I did some major digging into IR codes, how they are transmitted and everything in between. I ended up understanding only a tiny fraction of what is going on but it was enough to get me going.
For those looking for the same information, this is what I found out:
The remote IR codes that my cable box used (Arris 2150 as supplied by Shaw Cable) expects most (some/all) buttons to have two separate codes. Call them code a and code b. Each button, when first pressed, emits the ‘A’ code and the next press will be the ‘B’ code before going back to the ‘A’ code on the third button press.
If you learned only a single code (alternative set to false during the learn command), then the receiving equipment would get confused when the second key press was from the ‘A’ commands and not the ‘B’ commands.
The secret was to learn two codes (alternative: true) for keys such as numbers were the same number could be sent twice in a row.
I also needed to change the scripts for each button press - I had sent the b64 codes directly but I did not know how to alternate between the two b64 codes for key presses so instead I called the button names (command: button name) together with all the other parameters. Example:


entity_id: remote.universal_remote_remote
device: Shaw
command:
  - Next
num_repeats: 1
delay_secs: 0.1
hold_secs: 0.1

This would execute the stored commands for the button labeled ‘Next’ for the Shaw remote control.
Note that you could execute many key presses by listing them under commands such as:

command:
  - Button 1
  - Button 1
  - Button 2

This would send out the key sequence ‘112’ (I named the key presses as ‘Button 1’‘Button 2’ etc when I learned the key codes)

This fixed all the inconsistent behaviour so far but I have not yet exhaustively tested things.
Note that when called this way, the system automatically toggles between the two codes recorded per key and takes care of all the details.

I should point out that there are many many encoding schemes. It’s pretty much the wild west as far as codes is concerned. Any manufacturer can do their own thing. Some adhere to standards, some expand on standards and others do their own thing. In other words, this method worked for me with my equipment but might not work for you.

A somewhat related note: if you manually edit the config/.storage/Broadlink_remote_‘mac address’_codes file, be prepared for some big surprises and make a backup before you edit the file!!!
It took me several hours to track down an extra comma that resulted in the file content being unreadable and no codes being sent at all. I believe it was also the cause of my RM4C mini becoming unavailable even if no codes were sent which totally baffled me.

Also keep in mind that if you do edit that file, you need to reboot the HA host computer to make that change permanent. I do not believe that just restarting the Supervisor (or server) or any other sub system will result in the file change to be permanent. I suspect the file stays in RAM and is re-written when accessed.

1 Like

The bullet points above should be dash marks

Edit: fixed original post

Thanks a lot for sharing that, I’ll definetely give it a try

You can edit and format as code. See the editor toolbar. Just select, click and you’re done.

Wow that was awkward … took a while to figure out too

1 Like

Thanks, this was super useful. I was trying to figure out how to USE the ‘alternates’ that I was recording, and from this I learned that it’s done automatically. Awesome.

Even better, I was seeing some odd behavior that I couldn’t explain, but when you said that some buttons you wouldn’t expect ALSO send 2 codes, and to use alternates for those, suddenly it clicked and things are working. Thanks!

Edit: I just noticed it says ‘Alternatives’ in the UI, but that should obviously be ‘alternates’. Since to function properly the system must alternate between them.

For anyone else who stumbles across this, the representation of these codes is literally a number of ms (or some unit of time) between IR pulses and for the IR pulses themselves. I recorded the Mute button on my amp 3 times:

      "mute2": [
        "JgAYABodOjo5HhweGx8cHR0dHTodHTk7GwANBQ==",
        "JgAaAB4aHR0cHjkeHB4cHhwdHR0cOh4dOTscAA0F"
      ],
      "mute3": [
        "JgAYABsdOjo5HhweHB4cHhweGzsdHTk7HAANBQ==",
        "JgAaABoeHB4dHTkeHB4cHR0dHR0dOh0dOjobAA0F"
      ],
      "mute4": [
        "JgAYABweOTo6HR0dHR0cHhweHDodHTo6HQANBQ==",
        "JgAaABsdHB4cHjkdHR0cHh0dHR0cOxweOTodAA0F"
      ]

It’s not totally obvious at first but they’re all different. I think this must be due to subtle variations in timing that are recorded, but they’re all interpreted by the device the same way. All 3 of these work. I’ll follow up with a detailed analysis, for future readers. The amp is a Rogue Audio Cronus Magnum III, btw.

I asked ChatGPT why the recordings differ:

Why do the recordings differ?

The differences in your recorded IR (infrared) codes despite identical functionality are due to how IR remotes often encode their signals—and how recording tools interpret them.

Key reasons for variation:

1.

Tolerance in Timing

IR remotes send data as a series of modulated pulses (usually 38 kHz) with precise timing. Consumer-grade IR recorders don’t always capture this timing with millisecond-level precision, so small variations in pulse durations or intervals result in different encoded base64 data—even when the signal is functionally identical.

2.

Protocol Permissiveness

Many IR protocols (e.g., NEC, Sony, RC5, proprietary formats) allow for:

  • Tolerances in pulse length
  • Repeat codes or variations on retransmission
  • Checksum or toggle bits that change with each press

So your remote might:

  • Change a sequence counter
  • Flip a toggle bit
  • Vary gap timing slightly

These still get accepted by the amp because the command payload is the same or functionally equivalent.

3.

Encoding Artifacts

Your signal is encoded as base64, almost certainly representing raw pulse duration values (often in LIRC’s Pronto or Broadlink-like format). Any small difference in pulse width will yield a different binary pattern, hence different base64 strings.

4.

Multiple Command Variants

Some remotes intentionally rotate among a few valid encodings for a single command. This adds resilience to noise or supports auto-repeat detection.


Conclusion

Even though the encoded IR data looks different, the decoded payloads are functionally equivalent, and the amp’s IR decoder is designed to tolerate minor variation or interpret multiple forms of the same command.

If you’re trying to automate IR transmission (e.g., via ESPHome, LIRC, or Broadlink), just use one of the working variants. Most systems don’t need you to alternate or cycle variants unless the device specifically requires it.

I also asked for a detailed analysis of the data itself:

Detailed analysis of base64 IR data for Cronus Magnum III Mute Button

The data you’ve shown are base64-encoded representations of raw IR signals, likely in a format similar to that used by Broadlink, LIRC, or Pronto Hex systems. Let’s decode and analyze one signal fully, and then generalize to explain why they differ.


Step 1: Decode Base64

Taking the first string from “mute2”:

"JgAYABodOjo5HhweGx8cHR0dHTodHTk7GwANBQ=="

Base64 decoding (in hex):

26 00 18 00 1A 1D 3A 3A 39 1E 1C 1E 1C 1B 1F 1C 1D 1D 1D 3A 1D 1D 39 3B 1B 00 0D 05

Breaking this down:

Byte(s) Meaning (assumed)
0x26 Likely a header (Jg== = 0x26) — denotes IR protocol or mode
0x00 0x18 Number of bursts or encoding type (varies by format)
Remaining Raw pulse data — alternating on and off durations

Let’s convert them to decimal pulse widths:

[26, 0, 24, 26, 29, 58, 58, 57, 30, 28, 30, 28, 27, 31, 28, 29, 29, 29, 58, 29, 29, 57, 59, 27, 0, 13, 5]

These represent durations in ticks, often in units of us × scaling factor. In many IR formats, each value represents the length of an on or off period in microseconds divided by a constant (commonly 26.3μs in Pronto Hex, or just “tick units” in LIRC or Broadlink).

So, alternating:

  • Index 0: ON for 26 ticks
  • Index 1: OFF for 0 (likely noise or sync)
  • Index 2: ON for 24
  • Index 3: OFF for 26
  • Index 24: OFF for 5 ticks

Together, this is a full signal made up of:

[ON, OFF, ON, OFF, ..., ON, OFF]

Step 2: Why It Differs Yet Works

The structure encodes the same logical command , but:

  • Slight timing jitter (from repeat presses or electrical noise) causes minor shifts in the durations.
  • Some remotes alternate toggle bits (e.g., Sony and NEC do this).
  • Broadlink (and others) often do no normalization, so each raw IR capture has timing jitter.
  • Differences of ±1 tick (~±26μs) are usually below the detection threshold for the receiver.

Step 3: Verifying Equivalence

Even though the signals differ:

  • They match the same burst pattern: same number of pulses, similar timings
  • The core modulated pattern maps to the same command bitstream
  • The amplifier accepts any of them because its IR decoder uses a tolerant windowing algorithm

If we were to decode them all to binary bits (which requires knowing the protocol—e.g., NEC, RC5, etc.), you’d likely get the same command ID, e.g., 0xA45B or similar.


Summary

  • These base64 strings encode raw IR pulse durations
  • Timing varies slightly per press due to normal hardware behavior
  • Functionally, they are equivalent at the decoder’s logic level
  • You only need to store one working code for automation

If desired, I can extract and plot the waveform to show equivalence, or try decoding to a bit-level signal assuming a specific protocol (e.g., NEC or Sony).