[APP][Pro] Broadlink RM4 Pro - RF & IR remote control for Homey

Hi all,

Super cool to see this post — I’ve been wrestling for a while with how to take my own attempt at this further. I’m inexperienced when it comes to developing apps, but I have to say: it’s a wonderfully fun hobby, if a “slightly” time-consuming one.

My RM5 Plus adventure
A very kind community member has lent me an RM5 Plus so I could hook my own app, candlelight, up to it — thanks again Danny! The idea was to chain two flow cards together, so that something like a pronto hex string can travel from my (or a) app over to the Broadlink app and out into the world.

@Sharkys — I’ve made a fork (branch bugfix/rm5-plus), but no clue whether I did that correctly. The app works… but it still needs to be tested properly, and since I’m new to this whole forking thing I genuinely have no idea what the best way forward is, so I’d love your thoughts. In short, what’s in there:

  • Auto discovery, unicast-first so it also works where broadcasts are blocked — which is exactly what happens under Docker while debugging with the CLI (homey app run). There’s an IP override via env.json as a fallback.
  • The room-assignment problem. Once you assign a room in the Broadlink app, the device stops responding and the app never told you why. It turns out the hello/discovery response carries a lock byte in its payload (packet offset 0x7F, 0x01 = locked). Discovery now reads that flag, and instead of silently failing the device raises a warning — with a repair function to go with it.
  • IR/Pronto. I only just spotted that the sending side is now covered in your main branch and works in test version 3.1.69 of 15 July 2026 — nice! What I added on top of that is sending RC5 and NEC, and exposing the raw Broadlink hex on learn as well, with the idea that users can share codes through the community. Broadlink hex in Base64 format seems to be the default format in Home Assistant. FYI: a tool like Sensus makes it easy to convert between the formats, and to Tuya as well. My conversion sits in IrConverter.js, separate from the driver, so it’s reusable.
  • TypeScript. I’ve migrated the protocol layer (Communicate.ts, plus a typed packet model under lib/BroadLink/protocol) as this seems to be more sticked.
  • SVGs. Because apparently my idea of relaxation is questionable, I straightened them all out while I was at it.
  • General clean-up, to the point where it also passes homey app validate --level verified — stricter than this app actually needs, but it seemed a sensible bar to work towards.

If it helps, I’m happy to cut this into separate pull requests so the small ones can go in quickly and we can discuss the big one on its own. Just let me know what works best.

@Sharkys / @Guust_Flater — a question for you both: would it make sense to pull the protocol layer out into its own npm-package, so that both apps could depend on the same implementation instead of each maintaining their own? Right now Guust uses kiwicam-broadlinkjs-rm, Sharkys has a fully custom stack, and I’ve now written a third — which is more or less exactly the fragmentation this thread has been discussing, just one level further down. Curious whether you two think that’s worth doing, or more trouble than it’s worth.

@Guust_Flater — I started building a data model for the protocol. The basics are in place, but I got stuck halfway: the protocol definitions I could find online fall a bit short for the newer models, and writing a new lib while decoding the protocol at the same time was tough going. So I started a separate repo instead, based on a fork of an existing broadlink-dissector project, and wrote fairly elaborate protocol descriptions in markdown files there. Then I got slightly carried away by my own enthusiasm and hyperfocus, and somehow ended up in Broadlink’s cloud protocol and backend. That’s roughly where I ran out of steam, as other priorities took over. Today I read myself back into it and I’m properly up to speed again. So I’d be very happy to co-develop with you guys, if that’s something you’re open to.

@Doekse — where’s the best place to drop a few feature requests for Homey-native things? Two examples: you can send Pronto hex natively, but not from a satellite. And it would be absolutely sexy if other (non-Homey) devices could act as IR/RF satellites too. As came up earlier in this thread, Homey hasn’t had an IR receiver since the 2023 model and native local learning is not an option, an easy way to share IR/RF-codes like via proton hex is very welcome.

Anyway, here’s what I’ve been playing with (all on GitHub), in the order it happened:

Perhaps I’m missing something, but I don’t immediately see why long presses couldn’t be supported. As I understand it, the RM simply records the infrared signal and replays it.

That said, there are some protocol-specific challenges. For example:

  • RC5 uses a toggle bit that flips each time the same button is pressed. Simply replaying the exact same recording repeatedly may therefore not behave the same as repeatedly pressing the button on the original remote.

  • NEC has a dedicated repeat frame specifically designed for long presses. Instead of retransmitting the full command, the remote sends a short repeat pulse while the button is held down. Ideally, the app would detect and reproduce this behaviour rather than simply replaying the full command over and over.


    Image from sbprojects.net

So in principle, I think it should be possible to add. However, it depends on the IR protocol used by the remote and how the learned codes are stored and re-send. At the moment, the app stores a raw recording of the IR waveform and simply replay it.

A more sophisticated approach would be to recognise the protocol, decode the recording into logical fields (protocol, address, command, …), and regenerate a clean transmission when sending. That’s considerably more complex, but it’s also much cleaner: any noise captured during recording can be discarded, protocol-specific features such as RC5 bits can be handled correctly, and the resulting recordings become much shorter and more reliable. Raw recordings often contain multiple repeated frames (uneven, 3x for example, is unfavourable as this can be confusing in combination with a toggle) or long periods of silence after the transmission, which aren’t actually needed.

This was my motivation for adding an easy to export feature for the raw signal traces, as a first step. So they can be shared and/or analysed with external tools such as Sensus or IrScrutinizer, which can help decode, clean up, and validate the captured signals.

Hi Stephan,

Thank you for sharing this. There is clearly a lot of interesting work here, particularly around discovery, detecting locked devices and importing/exporting raw Broadlink commands.

I reviewed the branch in more detail. Unfortunately, I cannot merge or safely cherry-pick it in its current form. It is based on an older version of the app and contains 24 commits affecting 96 files. The functional changes are mixed with pairing and repair UI changes across all drivers, icon and branding updates, a protocol rewrite and a partial TypeScript migration.

The discovery changes also depend on several later refactors, while the Hex/Base64 and Pronto changes use a different implementation from the Pronto support already present in the current master branch. Cherry-picking individual commits would therefore either introduce unrelated changes or require substantial reconstruction.

I would, however, be happy to review new, focused PRs created from the current master branch:

  1. Discovery and lock detection

    • Unicast-first discovery with broadcast fallback.
    • Detection and clear reporting of the Broadlink lock state.
    • No unrelated pairing redesign, icons, branding or TypeScript migration.
    • Please include the exact RM5 model/device type, firmware version, a sanitized discovery-response packet or fixture, and the hardware tests performed.
  2. Raw Broadlink Hex/Base64 support

    • Separate Flow cards for sending and learning/exporting raw Hex/Base64 data.
    • Integrated with the current command handling and Pronto implementation from master.
    • Initially without NEC, RC5, normalization heuristics or long-press handling, as those need separate protocol-specific testing.
    • Please include example codes and the results of sending and learning them on the RM5 Plus.

The existing branch remains useful as research and as a reference implementation, but the safest way forward is to port the selected functionality into small PRs based on current master. That will let us review and test each feature without risking regressions for the other supported Broadlink devices.

I’m happy to help clarify where the relevant functionality should connect to the existing code.