{"id":50330310,"url":"https://github.com/xydac/sp542e-ha-bridge","last_synced_at":"2026-05-29T09:02:36.088Z","repository":{"id":361101911,"uuid":"1253094274","full_name":"xydac/sp542e-ha-bridge","owner":"xydac","description":"Control a cloud-locked PAUTIX SP542E CCT LED controller from Home Assistant with no extra hardware — a Mac BLE\u003c-\u003eMQTT bridge (BanlanX_6xx protocol)","archived":false,"fork":false,"pushed_at":"2026-05-29T06:39:03.000Z","size":10,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-29T08:27:40.186Z","etag":null,"topics":["banlanx","ble","bluetooth-low-energy","esphome","home-assistant","homeassistant","led-controller","mqtt","reverse-engineering","sp542e"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xydac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-29T06:34:27.000Z","updated_at":"2026-05-29T06:39:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/xydac/sp542e-ha-bridge","commit_stats":null,"previous_names":["xydac/sp542e-ha-bridge"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/xydac/sp542e-ha-bridge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xydac%2Fsp542e-ha-bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xydac%2Fsp542e-ha-bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xydac%2Fsp542e-ha-bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xydac%2Fsp542e-ha-bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xydac","download_url":"https://codeload.github.com/xydac/sp542e-ha-bridge/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xydac%2Fsp542e-ha-bridge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33644313,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["banlanx","ble","bluetooth-low-energy","esphome","home-assistant","homeassistant","led-controller","mqtt","reverse-engineering","sp542e"],"created_at":"2026-05-29T09:02:31.049Z","updated_at":"2026-05-29T09:02:36.081Z","avatar_url":"https://github.com/xydac.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SP542E MQTT ↔ BLE bridge\n\nControls the cloud-locked **SP542E \"BedRoof\" LED controller** from Home\nAssistant with **no new hardware**. A small Python service on the always-on\nMac connects to the controller over BLE and exposes it to HA as an MQTT light.\n\n```\nHA (VirtualBox) ──MQTT──\u003e Mosquitto (on HA) ──MQTT──\u003e bridge.py (Mac) ──BLE──\u003e SP542E\n```\n\nHA needs **no Bluetooth** and **no custom component** — the entity\n`light.bed_roof` appears automatically via MQTT discovery. This works around\nthe VirtualBox VM having no usable Bluetooth.\n\n## Files\n\n| File | Purpose |\n|---|---|\n| `protocol.py` | BanlanX_6xx (`53 ..`) frame builders (power/CCT/brightness). Single source of truth. |\n| `probe.py`    | One-shot: drives the strip directly to confirm the protocol. |\n| `bridge.py`   | The service: MQTT light ↔ BLE. |\n| `run.sh`      | Bootstraps `.venv` (via `uv`), loads `.env`, runs bridge or probe. |\n| `.env.example`| MQTT credentials template → copy to `.env`. |\n| `com.xydac.sp542e-bridge.plist` | launchd LaunchAgent for always-on auto-start. |\n\n## ⚠️ macOS Bluetooth requirement\n\nBLE only works from the Mac's **local GUI session**, never over SSH\n(CoreBluetooth TCC restriction). Run everything from a Terminal sitting at the\nMac. First run will prompt to grant Bluetooth to the Python binary\n(System Settings → Privacy \u0026 Security → Bluetooth).\n\n## Setup\n\n```bash\ncd sp542e-ha-bridge\ncp .env.example .env          # then fill in MQTT_USER / MQTT_PASS\n\n# 1. Confirm the protocol actually drives the light (watch the strip):\n./run.sh probe\n\n# 2. Run the bridge in the foreground to test HA integration:\n./run.sh\n#    -\u003e light.bed_roof should appear in Home Assistant automatically.\n\n# 3. Make it always-on (auto-start at login, restart on crash):\ncp com.xydac.sp542e-bridge.plist ~/Library/LaunchAgents/\nlaunchctl load -w ~/Library/LaunchAgents/com.xydac.sp542e-bridge.plist\n```\n\n## Protocol (BanlanX_6xx, plaintext, over FFE0/FFE1)\n\nThis is a **CCT (tunable-white)** strip — HA exposes color-temp + brightness +\non/off, no RGB. The controller speaks the **BanlanX_6xx** family (SP630E-style),\n*not* the LED-BLE `7E..EF` protocol and *not* idealLED AES (both were tried and\nsilently ignored). It advertises manufacturer id `0x5053` with advert data\n`5d 10..` (model id `0x5d`).\n\nFrames are plaintext on write characteristic **FFE1** (service FFE0), shaped\n`53 \u003ccmd\u003e 00 01 00 \u003clen\u003e \u003cpayload\u003e`. **Writes must be acknowledged**\n(`response=True`) or the device ignores them — this was the key gotcha.\n\n| Command | Bytes |\n|---|---|\n| Power ON / OFF | `53 50 00 01 00 01 01` / `53 50 00 01 00 01 00` |\n| Static-white mode | `53 53 00 01 00 02 02 01` (set before CCT/white-brightness) |\n| Color temp (static) | `53 61 00 01 00 02 \u003ccold\u003e \u003cwarm\u003e` (`\u003ccold\u003e`/`\u003cwarm\u003e` 0–255; `0x60` = dynamic) |\n| Brightness | `53 51 00 01 00 02 \u003cwhich\u003e \u003clevel\u003e` (`\u003cwhich\u003e` 0=color 1=white; `\u003clevel\u003e` 0–255) |\n| State query | `53 02 00 01 00 01 01` → device replies multi-packet status (fw, IP, name) |\n\n`color_temp` is in **mireds**: `MAX_MIREDS`=370 (~2700K warm), `MIN_MIREDS`=153\n(~6500K cool); `protocol.py:cct()` maps mireds → cold/warm bytes.\n\nProtocol reference: [`monty68/uniled`](https://github.com/monty68/uniled)\n`custom_components/uniled/lib/ble/banlanx_6xx.py` (the SP542E isn't in UniLED's\nmodel list, but it's this family).\n\n## Caveats\n\n- **Availability = Mac uptime.** If the Mac sleeps/powers off, the light is\n  uncontrollable and HA shows it unavailable. (Always-on desktop = fine.)\n- **Optimistic state.** The controller has no reliable state read, so the\n  bridge tracks state locally; changes made via the original app/remote won't\n  reflect back in HA.\n- **One BLE connection.** Keep the original phone app disconnected.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxydac%2Fsp542e-ha-bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxydac%2Fsp542e-ha-bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxydac%2Fsp542e-ha-bridge/lists"}