@epthewizard/homebridge-lutron-radiora3
v0.1.2
Published
Homebridge support for Lutron RadioRA 3 keypads, etc. (epthewizard fork of cyaneous/homebridge-lutron-radiora3)
Maintainers
Readme
@epthewizard/homebridge-lutron-radiora3
TL;DR — what this is, and how to check it's working right now
This is a Homebridge plugin that talks directly to your Lutron RadioRA 3 processor and adds
three things HomeKit doesn't otherwise get from RA3: (1) keypad/Pico remote button presses
as HomeKit accessories, (2) fast whole-house scenes (one tap instead of Apple Home's
slow one-device-at-a-time Scenes), and (3) direct, faster control of individual switches/
dimmers for the ones you opt in, instead of RA3's own built-in HomeKit bridge. None of this
needs the internet to run day-to-day — it's a local plugin talking to a local processor over
your LAN. The only step that ever needed internet was npm publish/installing it once via
Homebridge UI's plugin search.
To check whether it's actually installed and working right now:
- Open Homebridge UI (whatever URL/port you use on your Unraid box) in a browser — this is a page served by your own Homebridge container, so it works even with your internet down.
- Plugins tab → look for
@epthewizard/homebridge-lutron-radiora3in your installed list. If it's there, it installed successfully. - Click Settings on its card → this should open a custom pairing screen (not a plain form) → if you haven't paired yet, follow "Pairing with the processor" below.
- Logs tab (or
Homebridge Logsin the UI) → look for lines starting[Lutron RadioRA 3].Processor <id> is running firmware ...means it found and connected to your processor.Device ... not found in accessory cache/Found a Sunnata...lines mean it's discovering your keypads. Errors here are the fastest way to tell what's actually wrong. - In the Home app, look for new accessories named after your keypads/Picos — those only show up once discovery in step 4 succeeds.
If nothing shows up in step 2, the plugin never actually got installed (see "Publishing" below
for the install steps) — that's the most common reason "I did it all" and "nothing's happening"
coexist: the npm publish half and the "install it onto this specific Homebridge instance"
half are two separate steps.
Homebridge plugin for Lutron RadioRA 3 processors (LEAP protocol). Confirmed working
against firmware 26.05.26f000. The platform explicitly checks DeviceType ===
'RadioRa3Processor' and ProductType === 'Lutron RadioRA 3 Project' on startup and refuses
to run against anything else (RA2, Caseta) — this is not a generic Lutron plugin.
homebridge-lutron-radiora3 (unscoped) on npm is cyaneous's real upstream package — this fork
is published separately as @epthewizard/homebridge-lutron-radiora3 (scoped) so it shows up
in Homebridge UI's plugin search under its own identity and can never be confused with, or
silently overwritten by, the original via "Update".
Supports:
- Sunnata Keypads / Sunnata Hybrid Keypads → HomeKit Stateless Programmable Switches (single/double/long press per button)
- Pico remotes (untested on real hardware beyond basic cases)
- RA3 Virtual Buttons (scenes) → HomeKit momentary switches, opt-in (see below)
- Direct switch/dimmer (zone) control → HomeKit Switch/Lightbulb, opt-in, bypassing RA3's native HomeKit bridge (see below)
Shades and fans aren't implemented yet. Switches/dimmers are only controlled directly when you
opt a zone in via options.zones — otherwise RA3's Smart Bridge keeps exposing them to HomeKit
natively, same as always.
Based on lutron-leap-js and homebridge-lutron-caseta-leap.
Requirements
- Node matching what your Homebridge host actually runs — Homebridge 1.7 wants Node
^18.15.0or^20.7.0; a much newer Node (e.g. 22+/24) will still build this plugin but Homebridge itself will warn/misbehave, so use whatever Node your Homebridge install uses. - Homebridge
>=1.6.0. - Your RA3 processor and the Homebridge host on the same network segment (mDNS/
_lutron._tcpdiscovery + a direct TLS connection to the processor on port 8081).
Dev testing setup (this checkout)
npm link below is for iterating locally before you publish an update — see "Publishing
(production deployment)" further down for how it actually gets onto a real Homebridge install.
git clone [email protected]:epthewizard/homebridge-lutron-radiora3.git
cd homebridge-lutron-radiora3
npm install
npm run build # rimraf dist && tsc
npm run lint # eslint
npm link # registers this checkout as the global `@epthewizard/homebridge-lutron-radiora3` packageThen, inside your Homebridge install directory (wherever its own package.json/node_modules live):
npm link @epthewizard/homebridge-lutron-radiora3If you previously had cyaneous's
homebridge-lutron-radiora3(unscoped) installed, remove it first (npm uninstall homebridge-lutron-radiora3in the Homebridge dir) — otherwise you'll have both plugins loaded and registering the same devices.
Restart Homebridge. Useful while iterating:
# clear cached accessories if you've changed how devices/services are modeled
rm ~/.homebridge/accessories/cachedAccessories
# build + link + auto-restart on change, with LEAP/HAP debug logging
DEBUG='leap:*,HAP-NodeJS:Accessory' npm run watchEvery source change requires npm run build (or npm run watch) — the linked dist/ is
what Homebridge actually loads, not the TypeScript source.
Pairing with the processor
Pairing/config happens through the plugin's custom Homebridge UI settings screen
(homebridge-ui/), not by hand-editing config.json:
- Open the plugin's settings in Homebridge UI → it mDNS-discovers processors on the network.
- Select your processor and press the physical pairing button on the RA3 processor when prompted (30s window) — this is the same association flow as pairing the Lutron app.
- The UI generates an RSA keypair, submits a CSR to the processor, and receives back a signed
cert + CA. These get stored as a
secretsentry (processorID,ca,key,cert) in the plugin config — keepconfig.jsonprivate, these are real client certs for your processor.
Multiple processors are supported — just repeat pairing for each; each gets its own secrets entry.
Once a processor is paired/connected, the same settings screen fetches its actual Virtual
Buttons and zones live and shows them as checkboxes (grouped by room for zones) — check the
ones you want, no need to type exact names. This is what feeds options.virtualButtons and
options.zones, described below.
Scenes (Virtual Buttons) — fast, multi-device HomeKit "buttons"
Apple Home Scenes are composed client-side: tapping one sends a separate HAP write to every accessory in the scene, one at a time — slow and visibly sequential with more than a couple of devices. RA3 Virtual Buttons avoid that entirely: each one triggers a Preset (a scene defined on the processor) with a single LEAP command, and the processor fires every affected zone over its own bus at once — the same mechanism a physical keypad scene button uses. Use these instead of Apple Home Scenes for anything multi-device.
This is not limited to keypad-associated loads — a Preset can affect any dimmer, switch, or shade in the whole RA3 project, including ones exposed to HomeKit natively by the Smart Bridge. So if RA3's native HomeKit bridge feels slow when you fire a multi-device Apple Home Scene against those, the fix is the same: define the change as a Preset/Virtual Button in Lutron, expose that one virtual button here, and trigger it (directly or via automation) instead of the Apple Home Scene.
Setup:
- In the Lutron app (or Designer), create/name the Virtual Buttons you want (each tied to a Preset/scene) — this plugin doesn't create them, only exposes existing ones.
- In this plugin's settings screen in Homebridge UI, once connected to your processor, check
the Virtual Buttons you want under "Scenes & Switches" — this writes their names into
options.virtualButtonsfor you. Nothing is exposed by default — this is opt-in, so internal/programming-only virtual buttons in your project don't clutter the Home app. - Restart Homebridge. Each checked one shows up as a HomeKit switch; tapping it fires the scene, and the switch flips back off ~1s later (it's momentary, not persistent state).
- These are ordinary HomeKit switches, so they also work as triggers inside Home app/Shortcuts automations — just don't put more than one in the same Apple Home Scene, or you're back to the slow sequential behavior this is meant to avoid.
Direct switch/dimmer control (bypassing RA3's native HomeKit bridge)
If a single switch or dimmer feels slow in HomeKit, that's not this plugin, and it never was —
dimmers/switches are exposed to HomeKit by the Smart Bridge's own built-in bridge, a completely
separate code path this plugin has no part in. This feature makes this plugin control the zone
directly instead: a HomeKit Switch (or Lightbulb, for dimmable loads) backed by LEAP
commands over the same persistent local connection keypad buttons already use.
This is opt-in per zone, and it has a real gotcha: if you add a zone here while RA3's native
bridge is still also exposing it, the same physical switch shows up twice in the Home app,
with two independently-drifting states. Before adding a zone to options.zones, go disable that
zone's HomeKit export in the Lutron app first.
Setup:
- In the Lutron app, find the zone (switch/dimmer) you want and turn off its HomeKit export.
- In this plugin's settings screen, under "Scenes & Switches", check that zone (grouped by
room, same names as the Lutron app) — this writes its name into
options.zonesfor you. Nothing is touched by default — opt-in, one zone at a time. - Restart Homebridge. It auto-detects dimmable zones (
Lightbulbwith a brightness slider) vs. plain on/off zones (Switch) from the zone's own definition — nothing to configure per-type. This doesn't add dimming to anything — a zone only gets a brightness slider if it's a physically dimmable load and RA3 already knows that; a plain on/off switch stays a plain on/off switch here too, same as it is in the Lutron app and in RA3's native bridge. - State changes made physically (at the switch/keypad) or from another app are reflected back into HomeKit live, via the same LEAP subscription mechanism keypad button presses use — this isn't a one-way remote, it's full two-way control.
This is new and only exercised against firmware 26.05.26f000 so far — if a zone doesn't
respond, or reports the wrong on/off or brightness state, check Homebridge's debug log
(DEBUG='leap:*' ) for the exact LEAP command/response and file a note; the GoToLevel command
shape this uses is the standard one across Lutron's LEAP protocol, but hasn't been verified
against every RA3 zone/device type (shades and fans aren't handled by this yet at all).
Publishing (production deployment)
This fork is published to the public npm registry as @epthewizard/homebridge-lutron-radiora3,
which is what makes it installable the normal way — Homebridge UI's Plugins search, on any
Homebridge install (Docker, Unraid, Pi, whatever), no shell access needed.
First publish / publishing an update — from this checkout, on your dev machine:
npm login # one-time; opens a browser to authorize this machine to your npm account
npm version patch # bumps package.json's version (or `minor`/`major`) — npm refuses to
# republish an already-published version number
npm publish # runs prepublishOnly (lint + build) automatically, then publishesnpm login/npm publish need your npm credentials — this is not something that can be
scripted or done on your behalf, run it yourself in a terminal.
Installing on Homebridge (any host, including Unraid Docker) — in Homebridge UI:
- Plugins tab → search
homebridge-lutron-radiora3(orepthewizard). - Find
@epthewizard/homebridge-lutron-radiora3in the results and click Install. - Restart Homebridge.
- Configure it: click Settings on the plugin card → this opens the custom pairing UI (see "Pairing with the processor" above) → discover your processor → press its physical pairing button → save.
The search box can lag for a while after a fresh publish or version bump. npm's registry (what actually gets installed) updates instantly, but Homebridge UI's search hits npm's separate search index, which can take hours to catch up — confirmed directly:
npm view @epthewizard/homebridge-lutron-radiora3found it immediately after publishing, but it didn't appear in npm's own search API for the exact same package name many hours later. If search comes up empty, install by exact name instead — it doesn't depend on the search index, andhb-servicedoesn't use search at all, so this always works regardless of indexing lag.
Manual install via the Homebridge Terminal (no search needed)
Every Homebridge UI has a Terminal tab that drops you into a shell already inside the
Homebridge container — on the official homebridge/homebridge image (what Unraid's Community
App uses) it identifies itself like this:
Homebridge Terminal
Node.js Version: v24.20.0
Node.js Path: /opt/homebridge/bin/node
Plugin Path: /var/lib/homebridge/node_modules
Install Plugin: hb-service add homebridge-plugin-name
Remove Plugin: hb-service remove homebridge-plugin-name
root@Tower:/homebridge $hb-service is Homebridge's own plugin-install tool — it installs straight from the npm
registry (bypassing the search index entirely, so the lag above never applies here) and
restarts Homebridge for you. From that prompt:
hb-service add @epthewizard/homebridge-lutron-radiora3That's it — no path-guessing, no manual npm install, no separate restart step. To update to a
newer version later, same command again (or hb-service update @epthewizard/homebridge-lutron-radiora3
if your version has that subcommand). To remove it: hb-service remove @epthewizard/homebridge-lutron-radiora3.
Future updates are the same UI's Plugins-tab Update button (once search catches up) or the
hb-service add/update command above (always works) — either way, since it's a real published
package under a name only you own.
Unraid specifically
Confirmed working setup: the official homebridge/homebridge Community App image (hb-service
present, plugins under /var/lib/homebridge/node_modules). Homebridge UI runs on the port you
set during the Unraid template install — open that in a browser, use the Terminal tab
directly for hb-service add, or the Plugins tab search if it's caught up. Either way,
you never need Unraid's separate Docker "Console" button/docker exec — Homebridge UI's own
Terminal tab already gives you a shell inside the container.
Installing a pre-release build directly from GitHub
Before something is published to npm (see "Publishing" above), you can still install straight
from this repo's main branch on a real Homebridge host — useful for testing a fix before
bumping the version. From the Homebridge Terminal (see "Manual install" above for how to get a
shell there):
npm install https://github.com/epthewizard/homebridge-lutron-radiora3.git#main --prefix /var/lib/homebridgeAdjust --prefix to wherever Homebridge's own node_modules actually lives on your host — it's
the Plugin Path the Homebridge Terminal prints on connect (/var/lib/homebridge on the
official Docker image). This clones the repo, builds it (npm run build via the prepare
script — see the homebridge-config-ui-x gotcha below, without that fix this step used to fail),
and installs it like any other npm dependency. Restart Homebridge afterward to pick it up.
Uninstall / go back to the published version:
hb-service remove @epthewizard/homebridge-lutron-radiora3 # removes it entirely, or:
npm install @epthewizard/homebridge-lutron-radiora3 --prefix /var/lib/homebridge # swap back to the npm releaseBoth install under the same package name, so either command cleanly replaces the git-installed copy — no need to remove it as a separate step first.
Known gotchas
- Case-sensitive imports: dev happens on macOS (case-insensitive FS); Homebridge usually
runs on Linux (case-sensitive).
tsconfig.jsonhasforceConsistentCasingInFileNames: truespecifically to catch mismatched import casing at compile time — don't remove it, and don't add a new source file whose import casing doesn't match its filename exactly. - RA3 firmware omits
Bodyon some LEAP responses — e.g./area/<id>/associatedcontrolstationreturns no body at all for areas with no control station.Processor.get*methods treat a missing/unexpected body as "empty result," not an error; keep that pattern if you add new LEAP calls, since firmware behavior here isn't fully documented by Lutron. homebridge-config-ui-xwas removed fromdevDependencies(2026-09-02): it was never actually imported by this plugin's code, but npm's git-dependency install step force-builds all devDependencies, and that package's nativenode-ptyaddon failed to compile on newer Node/clang/gcc — which brokenpm install <git-url>(see below) for everyone. Plainnpm installneeds no flags now; don't add it back todevDependencies(install it ad hoc with--no-saveif you need to manually test the Homebridge UI terminal)..npmignorepreviously excludeddist/(a leftover from a generic project template) — every publish would have shipped a package with no compiled code in it. Fixed; if.npmignoreis ever touched again, confirmnpm pack --dry-runstill listsdist/*.jsfiles.- Migrating from the unscoped
homebridge-lutron-radiora3: accessories are registered under the npm package name, so switching to the@epthewizard/...scope orphans any accessories cached under the old name. Uninstall the old plugin, clear~/.homebridge/accessories/cachedAccessories, and let this plugin rediscover everything on next Homebridge start. Yourconfig.json"platform": "LutronRadioRA3"entry (includingsecrets) doesn't need to change — only the plugin/package name changed, not the platform name.
License
The leap portion of this plugin (src/leap/) is GPL-3.0, inherited from
lutron-leap-js. The rest is Apache-2.0 (see LICENSE).
