Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BarPilot

An unofficial, single-file web app for controlling a BUSY Bar® over its local HTTP API. Everything lives in one barpilot.html - no install, no server, no build step, no dependencies. Double-click it on Windows or macOS and it talks straight to your bar.

Version License: MIT

Animations gallery

Not affiliated. BarPilot is an independent community project. It is not affiliated with, endorsed by, or sponsored by Flipper Devices Inc. "BUSY Bar" is a product of Flipper Devices; it is referenced here only to describe compatibility.

Why

The official apps are limited (and there's no Windows app at all), but the device ships a full local HTTP API with permissive CORS - which means a plain HTML file opened from disk can drive every feature. BarPilot covers all 53 API endpoints, then keeps going: meeting mode, pixel art, a 92-animation gallery, playlists, and a raw API console.

Quick start

  1. Download barpilot.html (or grab it from the latest release).
  2. Double-click it - it opens in your browser (Chrome, Edge, Firefox, Safari).
  3. Put your bar's IP in the Device field (USB networking or Wi-Fi both work). The dot goes green when it's connected.

If your browser is picky about file:// pages, serve the folder instead: python3 -m http.serverhttp://localhost:8000/barpilot.html

Light and dark themes and two colour-blind palettes are in the top bar. BarPilot checks for new releases daily - a green chip appears in the top bar when one is out, and clicking it updates in place (Chrome/Edge) or downloads the new file. Settings live in your browser and survive updates.

What's inside

Quick Status - meetings, presets, custom messages, the ticker with its stamp picker, weekly schedule and night mode

Section Covers
Quick Status Messages - one list, two ways to use it: send a single line or rotate the whole list (live crypto prices, per-line colours, inline stamps + animated stamps placed where you type them), weekly busy schedule (recurring auto-meeting blocks), night mode (dim / display-off / away-message on a timer or nightly schedule), fully configurable one-click presets (text, icon, colour, flashing, LED, duration, on-bar icon - ON AIR / FOCUS / DND / AVAILABLE / COME IN / ON A CALL / BACK AT…), scrolling messages, meeting mode (flashing red banner + live countdown + blinking LED, pickable banner text), END BUSY reset, desktop shortcut generator (.cmd / .command)
Calendar ICS calendar feeds → automatic meeting mode: Google, Outlook / Microsoft 365 (incl. Teams meetings), iCloud, Fastmail, Calendly, 8x8/Zoom-synced events - the bar goes BUSY when events start (configurable lead, event title as banner, duration cap; daily/weekly recurrence). On-call hook: auto-BUSY while you're actually in a call - on Windows two independent detectors (the OS mic/camera-usage records in both registry hives, plus live audio capture sessions - so it works even where newer Teams builds stop writing the records), on macOS ControlCenter's sensor attributions (any app using mic/camera), and a local webhook (curl 127.0.0.1:8765/hook?state=on) wires up everything else (Stream Deck, Shortcuts, watchers). Banner text, display flash and LED blink are configurable (changing the banner mid-call re-labels the live banner), the count-up matches the real call length even when the banner starts mid-call, and a "what does Windows see?" debug view shows the raw detection data when something misbehaves. Feeds and call state go through the local helper - providers block direct browser fetches
Dashboard device / firmware / system / power status, log dump
Timer start/pause/resume/stop sessions (simple, infinite, interval), both timer profiles, raw snapshot JSON
Draw full canvas composer: text, rectangles, images, animations, countdowns; priority, LED blink, JSON mode; audio; asset upload
Pixel Art paint on a 72×16 or 80×80 grid, import & auto-fit images (animated GIFs become animation frames automatically on Chrome/Edge), 231 stamps in 10 packs, a 5×7 pixel-font text stamper, ASCII-art import/export
Animations 92 built-in animations with live-preview gallery - 64 full-bar scenes (space, aquarium, city, weather, cats, dogs, lizards, memes…) + 28 sprite loops. Play/stop, 2-8 fps, clock overlay, periodic clock breaks, rotation playlists with seamless switches and skip controls (buttons, mouse wheel on the now-playing chip, arrow keys). Worker-driven, so background tabs keep animating. Prepare the bar stores every frame on the bar itself, so playback sends only tiny commands (rotation switches and skips cost nothing), animations are deterministic (what you preview is what plays) and the one that was playing resumes after a reload. Physical-switch aware: flip the bar's mode switch off OFF and overlays yield instantly; flip back and they resume
Games Snake, Pong, Tetris, Breakout, Space Invaders, Frogger and Simon played live on the bar with your keyboard (priority 70), score shown on the bar itself (snake: top-right apple count · pong: digits flanking the net), local preview canvas
Sounds the bar has a speaker: a soundboard of built-in sounds (chimes, alerts, the Imperial March opening...) plus your own - record from the microphone or drop in audio files, converted to the bar's .snd format in the browser. Sounds are stored on the bar itself by Prepare the bar, so playing one is a single command
Claude Ask Claude - questions from the app, answers scroll on the bar (claude-opus-5, your own API key). Usage monitor - gauges on the bar in your color (default Claude orange) from three sources: this app's own usage, your Claude Pro/Max plan (a tiny downloadable Python helper serves rolling 5-hour / weekly totals from Claude Code's local transcripts - and if you optionally hand it your Claude Code OAuth token, your official plan percentages; browsers can't call claude.ai cross-origin, hence the helper), or the Anthropic Admin API (org-wide)
Scenes save Draw payloads as named scenes, replay/export/import, daily scheduler
Screen live view of both displays, PNG snapshots, big-screen LED mirror, raw status WebSocket monitor
Input virtual remote (all 10 keys) + keyboard control - entering the section auto-pauses overlays so the bar's own menus are visible
Storage browse /ext, upload/download/rename/delete, mkdir, usage
Settings / Time / Wi-Fi / BLE name, brightness, volume, API access mode, clock sync (automatic on connect - a drifted bar clock skews device-rendered countdowns), timezone picker, Wi-Fi scan/connect with radio-state guidance (currently broken by a firmware Wi-Fi wedge - see Known issues), Bluetooth (experimental - see Known issues)
Smart Home Matter pairing with scannable QR (self-contained QR encoder) + manual code - auto-retries the Matter stack's 503 warm-up, shows live commissioning status, diagnoses Wi-Fi-related blocks; emulated switch (pairing currently blocked by the firmware Wi-Fi wedge - see Known issues)
Account / Updater cloud link with PIN, MQTT backend config, firmware check/install/upload with progress - bundles are inspected before upload (target, security flags, radio-firmware replacement) and refused if incompatible
Console raw request builder for every endpoint, request log, copy-as-curl
Troubleshooter guided checks - connection, API access, power, firmware, display control, Wi-Fi, local helper - with the fix for each and buttons that apply it

Destructive actions always ask for confirmation first.

What's new in 1.26

One fix, worth its own release: on-call detection on macOS works again. The 1.25 rewrite misread how macOS reports microphone use - the system logs a line only when the set of apps using the mic changes, not continuously - so long Zoom and Teams calls were cleared minutes in, or never detected at all. The proven event-driven behaviour is restored: detect on the start event, hold through quiet, clear on the end event. If you use the on-call hook on a Mac, update the helper (barpilot-usage-helper.py) - that is where the fix lives.

What's new in 1.25

Everything since 1.18, tested against a real bar over USB, Wi-Fi and Bluetooth:

  • Sounds (new section): a soundboard for the bar's speaker - built-in sounds plus your own recordings and audio files, converted to the bar's raw .snd format in the browser.
  • Messages: the custom message and the ticker merged into one card - a single list where Send this line puts one message up and Rotate all cycles the list, with the same syntax everywhere (inline stamps, animated stamps, per-line colours, crypto prices).
  • Prepare the bar (Bluetooth section, step 1): sends every sound, all 1,469 animation frames, every stamp and icon, and your settings to the bar's own storage over USB/Wi-Fi. After that, playing any of it is a single small command - which is what makes the slow links usable, makes rotation skips free, and survives page reloads.
  • Your settings live on the bar and follow it: any copy of BarPilot on any machine reads them back on first connect. The helper keeps an offline copy too.
  • Bluetooth control (experimental): drive the bar over BLE through the helper - no Web Bluetooth, so it works from a plain file:// page and on managed machines. Pairing, bonded reconnect, link-paced playback and self-healing after drops are all in, and it is still buggy - treat it as a work in progress (the app says so on the panel too).
  • On-call detection rebuilt and field-tested on Windows: two independent detectors (registry usage records in both hives, plus live audio capture sessions - newer Teams builds stop writing the registry records, the audio engine can't hide), a "what does Windows see?" debug view, the count-up timer backdated to the call's real start, live banner re-labelling, and a stale-meeting bug fixed that silently disabled the automation after an unclean page close.
  • Calendar correctness: deleted occurrences stay deleted (comma-list EXDATE), moved occurrences show only at their new time (RECURRENCE-ID), and duplicates from overlapping feeds/imports are folded - the ghost-event parade is over.
  • Troubleshooter fix buttons re-check themselves: press a fix and the row re-runs its own check and turns green, instead of leaving you wondering. The helper row shows the whole webhook/microphone chain state.
  • Screen panel: front and back brightness side by side, "blank the back screen" no longer blanks both, and the live preview pauses over Bluetooth (with a refresh-once button) instead of silently eating the link.
  • Quick messages diagnose their own 409s: the toast names what actually owns the screen - and if it is your own night mode, the message wins and night lifts.
  • Helper v28 (barpilot-usage-helper.py): serves the app at 127.0.0.1:8765/app, syncs settings across origins and to the bar, proxies calendar feeds, runs the webhook and both call detectors, installs its own optional add-ons, and is hardened against the crashes and silent failures found in the field. BarPilot checks the helper version and says so when it is too old.

Earlier releases: see the release notes.

Known issues (pending)

  • Bluetooth is a work in progress and marked as such in the app: Windows pairing can take several attempts (the bar requires an authenticated bond and does not resume old ones), the link can drop and re-pair, and playback is paced by a link that carries a few KB/s. Everything works over USB and Wi-Fi; treat Bluetooth as a bonus, not the primary transport, until this notice goes away.
  • The bar's Wi-Fi stack can wedge (stock fw 1.1.1): stuck on "connecting" even from a cold boot, Command timed out on scan/disconnect, and the Matter stack then answers 503 (it can't bind while the radio churns). One observed wedge survived forgetting the network, multiple power cycles, a full Wi-Fi clear and a bootloader recovery. Root-caused to an unbounded wait in the firmware's Wi-Fi service - fixed in BarMetal, which also adds the software reboot the stock firmware lacks. On stock firmware there is no reboot API, so recovery is physical (see the unbricking cheatsheet).
  • Even on BarMetal, a radio that has failed may still not scan: that fix lives in the Wi-Fi co-processor firmware, which requires vendor signing. BarMetal keeps the device responsive and self-healing rather than bricked.
  • Matter commissioning additionally requires the phone and the bar on the same network segment (mDNS discovery - VLANs block it without a reflector).
  • The scroll wheel and up/down keys emit nothing observable to clients - only the mode switch and OK/BACK/START buttons are streamed. BarPilot offers on-page skip controls instead; a firmware feature request is filed.

Unbricking cheatsheet (undocumented, discovered the hard way)

The bar is battery-backed, so unplugging it never resets it - a crashed or bootloader-stuck bar just sits there. The physical controls that actually matter:

Action How
Power off hold the OK / spin-dial button ~15 s
Power on hold BACK ~5 s
Enter the bootloader (STM32 DFU) hold OK + BACK together
Exit the bootloader without flashing hold OK for 10-15 s - or, from a computer: dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave (it may print a get_status error - the bar still boots seconds later)

If the screen says "System error - restart device": power off (OK 15 s), then power on (BACK 5 s). There is no reboot API.

Straight off the bar

Real frames captured from the device over the API (/api/screen):

ticker with scrolling text and two animated icons
ticker - scrolling text + two animated icons, placed where you type them
night mode faint clock
night mode - faint clock, every other LED off
snake with its score drawn on the bar
snake - apple count on the bar itself
the this-is-fine scene
"this is fine" - one of 92 built-in animations

Stamps

Stamp packs - 159 stamps in 8 categories

Firmware quirks worth knowing (observed on 1.1.1)

Learned the hard way, verified against a real device:

  • While any timer session runs, the bar rejects all canvas drawing (every priority, even 100) with Not drawn due to low priority.
  • Sessions/cards started on the device itself don't appear in /api/busy/snapshot and can't be stopped via the API. Open on-device menus also block drawing.
  • Turning the emulated smart-home switch ON makes the bar start its own timer-profile session - which then blocks drawing (see above).
  • An active canvas overlay blocks other draws at the same or lower priority - only strictly higher wins (the spec's "equal priority overrides" was not observed).
  • Re-sending a scrolling text element restarts its scroll - send it once and animate other elements around it.
  • /api/screen returns base64 of raw pixels despite its image/bmp content type: front = 72×16 RGB888 (BGR byte order!), back = 80×80 8-bit grayscale.
  • The brightness setting (/api/display/brightness) is accepted and stored but visibly does nothing - dimming has to be done by drawing darker pixels (night mode owns the screen and does exactly that).
  • Apps don't composite: whichever app has the highest priority owns the whole display; anything below it is fully hidden (not blended). A translucent overlay can never dim another app's content.
  • BarPilot layers its overlays deliberately: animations 55 < quick messages 60 < meeting 95.

Notes

  • Settings persist per browser via localStorage (device address, API key, playlists…).
  • The API key (only needed in "key" access mode) is stored in plain text - fine for a LAN gadget, don't reuse a secret you care about.
  • Built and live-tested against firmware 1.1.1 (API 25.0.0). The Console can call anything a future firmware adds.

Going further - official client libraries

BarPilot is deliberately one dependency-free HTML file: nothing to install, nothing to supply-chain-attack. If you want to script the bar from real code, the official clients are the right tool - pin exact versions and verify checksums:

package pinned, hash-verified install
Python busylib 1.0.0 (docs) - sync/async clients, pydantic element models, WS state stream printf 'busylib==1.0.0 --hash=sha256:7f7a4079e028d9f6280f859ec155cb724f049bf473abf14303b26b539dbb312c --hash=sha256:b0a91f7f66015a9f7f91dc180203c28056e7b354cc7b44b3598840b8b0b07a2b\n' > requirements.txt && pip install --require-hashes -r requirements.txt
JS / TS @busy-app/busy-lib 0.17.0 - typed openapi-fetch client, WS state stream, WebGL2 renderer, browser-capable ESM npm install --save-exact @busy-app/busy-lib@0.17.0 (lockfile integrity sha512-N8x54N0sgrxKa0YSnA7BTBB4Hg0EXBH+TBtRgoHXJJTP+88QUw+nLwVaJL2PYRWIVxZZneKKmif+21twjskAOQ==)

The Draw section can export your composed canvas as a ready-to-run barpilot-draw.py pinned to busylib 1.0.0. BarPilot itself never imports these libraries at runtime - a local page pulling remote code would undo the zero-dependency security model.

License & contributing

MIT - free to use, modify, and share with attribution. If you build something on top of it, a credit and a link back here are appreciated, and contributions (PRs, firmware quirk reports, new stamps and scenes) are very welcome.

About

BarPilot — unofficial single-file web controller for the BUSY Bar (Flipper Devices). All 53 API endpoints, meeting mode, pixel art, 73 animations, playlists. Windows & Mac, no install. Not affiliated with Flipper Devices.

Resources

Stars

19 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages