Skip to content

CyberUnicorn console: Flipper Zero mode - #3794

Merged
hellofrequencylab merged 3 commits into
mainfrom
claude/console-flipper-mode
Oct 21, 2026
Merged

hellofrequencylab merged 3 commits into
mainfrom
claude/console-flipper-mode

Conversation

@hellofrequencylab

@hellofrequencylab hellofrequencylab commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Requested by Daniel

What

The CyberUnicorn console can now use a Flipper Zero as its tag writer. It recognizes whether the board on the cable is the Unicorn or the Flipper and switches modes. In Flipper mode there is no screen feed and no boot wait, the Scanner and Update tabs are hidden, and the copy says to hold the tag on the back of the Flipper.

Why

Daniel wants to write placards from the console with the Flipper. The Flipper side is the Frequency app (hellofrequencylab/projects#17). While that app is open, the Flipper exposes a second USB serial port that answers this console's protocol: system.status, system.caps, hat.probe, frequency.write_tag and frequency.read_tag. The console's picker only listed the CH340, so the Flipper never showed up.

How to review (owner)

  1. Wait for CI to go green.
  2. On the Vercel Preview, in Chrome on the Mac with the Flipper plugged in and Apps → NFC → Frequency open:
    • Go to /admin/cyberunicorn and click Connect USB. The picker lists the Flipper. Pick the port whose name ends in 3. The header should read FLIPPER 0.1.0, with no screen feed, and the Reader should show "Flipper NFC".
    • Choose a Space and Write placard, then hold a blank NTAG on the back of the Flipper. The placard should appear in the list with its UID, and a phone tap should check in.
  3. Plug the CyberUnicorn back in and connect. Nothing should change for it: same boot wait, same screen feed, all tabs.

How / files

File Change
lib/device/web-serial.ts FLIPPER_VENDOR_ID, usbDeviceOf(port), rememberedConsolePorts() (CyberUnicorn first, then Flipper ports) and pickConsolePort() (CH340 + Flipper filters). The updater keeps pickPort/rememberedPort, which are CH340 only, so a Flipper is never offered for an OS flash. Open errors and the transport label name the Flipper.
components/spaces/loyalty/cyberunicorn-console.tsx connect() now picks the candidate ports and attach() opens one. A Flipper port gets 3 short system.status asks instead of the 40 s boot wait. Remembered Flipper ports are tried in turn, because the first one is the Flipper CLI and never answers. A device state drives the copy, the FLIPPER header, no mirror, and hiding the Scanner and Update tabs.

Verification

  • pnpm exec tsc --noEmit: exit 0. It needs NODE_OPTIONS=--max-old-space-size=8192 locally, because the default heap ran out of memory.
  • pnpm lint on the two files (eslint --max-warnings=0): clean.
  • pnpm exec vitest run lib/device: 9 files, 80 tests passed. The protocol, relay, cable-scan and screen-mirror suites are unaffected.
  • Checked the Vercel preview
  • On hardware, the Flipper app answered this exact protocol from the Mac over /dev/cu.usbmodemflip_I5had0ha3: status, caps, hat.probe, unknown_command, bad_args, and a clean "No card" timeout. That is noted in the Flipper PR.

Notes / follow-ups

  • A real tag write through the console still needs Daniel at the Flipper.
  • tagProblem() keeps its CyberUnicorn wording for busy, no_reader and a plain timeout. The Flipper app never sends the first two. The console demo thread's in-flight PR also edits tagProblem(), so I left that text alone to avoid a conflict.

🤖 Generated with Claude Code

The console's USB picker now lists a Flipper Zero (STMicro VID 0x0483)
as well as the CyberUnicorn's CH340. A Flipper running the Frequency app
answers the same protocol on its second port, so the console tries each
allowed Flipper port, skips the boot wait and the screen feed, hides the
scanner and OS update, and says where to hold the tag. The updater keeps
its CH340-only picker.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@hellofrequencylab hellofrequencylab self-assigned this Oct 21, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
frequency-web Ready Ready Preview Oct 21, 2026 5:55pm UTC

Request Review

Keeps both: Flipper tries and the board's boot-scene line. The abandoned-connect
guard returns false here, since connect now reports whether it reached a device.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Aw32AU4vVqCSEoNA5aP3U

Copy link
Copy Markdown
Owner Author

The test check failed on one test: scripts/backlog-contract.test.ts, "the full --probes=all sweep is green, and stays inside its cost budget". It hit vitest's 90 s timeout. It did not fail an assertion.

On this exact head (59b3808), node scripts/check-backlog.mjs --probes=all exits 0 locally in about 60 s. All 1653 probes agree, including the four cu5k probes this branch touches. So the timeout was the sweep running slow while sharing a loaded CI runner, not a broken probe. I've re-run the failed job once.


Generated by Claude Code

@hellofrequencylab
hellofrequencylab merged commit 5963811 into main Oct 21, 2026
17 of 18 checks passed

This branch was successfully deployed

1 active deployment
Preview — 59b38084 Deployed Oct 21, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants