Commit Graph
120 Commits
Author SHA1 Message Date
Hermann Björgvin de7ac5ec36 Merge pull request #37 from HermannBjorgvin/revert-29-oauth-usage-endpoint
Revert "switch daemon to `/api/oauth/usage` endpoint"
2026-05-24 20:04:18 +00:00
Hermann Björgvin 12184549ff Revert "switch daemon to /api/oauth/usage endpoint" 2026-05-24 20:04:07 +00:00
Hermann Björgvin 912061f1ac Merge pull request #29 from BrianPugh/oauth-usage-endpoint
switch daemon to `/api/oauth/usage` endpoint
2026-05-24 19:30:03 +00:00
Brian Pugh 525ebe8921 switch daemon to /api/oauth/usage endpoint 2026-05-24 15:26:43 -04:00
Hermann Björgvin efc5641840 Merge pull request #36 from AlexanderYW/add-waveshare-amoled-216-c6-board
feat(boards): Add Waveshare ESP32-C6-Touch-AMOLED-2.16 support
2026-05-24 18:54:25 +00:00
Hermann Björgvin b75dda8a85 Merge pull request #28 from BrianPugh/macos-keychain
macos uses keychain; remove stale comments
2026-05-24 18:50:19 +00:00
Hermann Björgvin f7272ac7cf Merge pull request #30 from BrianPugh/fix-flash-all-environments
Bugfix: specify board target
2026-05-24 18:48:01 +00:00
Alexander Wennerstrøm f5f43aa8aa fix(boards): Remove redundant AXP2101 charging configuration for Waveshare ESP32-C6-Touch-AMOLED-2.16
- These settings were causing conflicts with the on-chip fuel gauge reference configuration
- Simplify power initialization by relying on BSP defaults instead of overriding them
2026-05-24 09:48:35 +02:00
Alexander Wennerstrøm 9f75de55a2 feat(boards): Add secondary button support to Waveshare ESP32-C6-Touch-AMOLED-2.16
- Enable BTN_FWD_GPIO (GPIO 10) as secondary button for mode toggle (Shift+Tab)
- Update BOARD_HAS_SECONDARY_BUTTON flag from 0 to 1
- Clarify button layout: BOOT (primary PTT), PWR (cycle screens via AXP), KEY (secondary mode toggle)
- Document KEY GPIO discovery method (empirical scanning of unused GPIOs)
- Update button_count calculation to include secondary button when available
- Initialize both BTN_BACK_GPIO and BTN_FWD_GPIO in input_hal_init()
- Refactor input_hal_is_held() to use switch statement for cleaner multi-button handling
2026-05-24 09:47:31 +02:00
Alexander Wennerstrøm ab8b64d949 feat(boards): Add Waveshare ESP32-C6-Touch-AMOLED-2.16 support
- Add complete board support for Waveshare ESP32-C6-Touch-AMOLED-2.16 with SH8601 display driver
- Implement board initialization with AXP2101 PMU rail configuration for LCD and touch power
- Add display driver for SH8601 QSPI panel (480×480 resolution)
- Add CST9217 touch controller support via I2C
- Add QMI8658 IMU initialization and sensor reading
- Add AXP2101 power management and battery monitoring
- Add input handling for BOOT button (GPIO 9)
- Configure PlatformIO environment with C6-specific build flags and 16 MB flash layout
- Update capability flags documentation to clarify BOARD_HAS_PSRAM build-flag macro usage
- C6 has no external PSRAM; shared code gates on this flag to use internal SRAM and reduce LVGL buffer sizes
- Screenshot capture disabled on this board due to internal SRAM constraints
2026-05-24 08:36:53 +02:00
Brian Pugh b7b8e3f5ca must specify board target (e.g. waveshare_amoled_216), fixes 'flash all environments' bug. 2026-05-21 21:08:59 -04:00
Brian Pugh acd4819737 macos uses keychain; remove stale comments 2026-05-21 21:08:13 -04:00
Hermann Björgvin c25e89672a Merge pull request #27 from orbisai0security/fix-ble-rx-buf-bounds-check
fix: add buffer-length check in ble.cpp
2026-05-21 19:52:00 +00:00
orbisai0security 5079ea1af4 fix: V-002 security vulnerability
Automated security fix generated by OrbisAI Security
2026-05-21 10:04:37 +00:00
Hermann Björgvin 09b5ba8c72 Updated affiliate link 2026-05-21 09:47:01 +00:00
Hermann Björgvin 7ae95a83ab Merge pull request #25 from tobby168/upstream-refactor
Add AMOLED-1.8 board + device-abstraction refactor for community ports
2026-05-21 01:55:22 +00:00
tobby168andClaude Opus 4.7 20351212b2 Device-abstraction refactor: HAL + per-board folders + responsive UI
Replaces the build-flag-driven #ifdef sprawl (~30 blocks across 6 files)
with a small HAL in firmware/src/hal/ and per-board folders under
firmware/src/boards/. Shared code (main.cpp, ui.cpp, splash.cpp) no
longer contains a single `#ifdef BOARD_*` — optional features are
guarded by BoardCaps (runtime) and BOARD_HAS_* macros (compile-time,
inside the board's own files).

Why: lets community contributors port to new ESP32 + AMOLED + touch
combos by dropping in a boards/<name>/ folder + a PlatformIO env,
without touching shared files. See docs/porting/adding-a-board.md.

Highlights:

- New HAL: display_hal, touch_hal, input_hal, power_hal, imu_hal,
  board_caps. Each board provides display.cpp, touch.cpp, input.cpp,
  power.cpp, imu.cpp, caps.cpp, board_init.cpp + private hardware
  drivers (e.g. io_expander.{h,cpp} on AMOLED-1.8).
- PlatformIO build_src_filter selects each board's folder per env.
- ui.cpp picks fonts and layout from board_caps() via compute_layout()
  with screen-height breakpoints (>= 460 → large, else compact).
- splash.cpp computes CELL = min(W,H)/20 — responsive instead of two
  hardcoded values.
- idle.cpp (from #24) rewired through display_hal + power_hal — no
  longer depends on the deleted display_cfg.h / power.h.
- power_hal gains power_hal_is_vbus_in() for idle's
  IDLE_SLEEP_WHEN_CHARGING gate.
- boards/template/ + docs/porting/{adding-a-board,hal-contract,
  capability-flags}.md to bootstrap new ports.
- display_cfg.h, power.{h,cpp}, imu.{h,cpp}, io_expander.{h,cpp}
  deleted from src/ root (moved into boards/<name>/ or hal/).

Verification: both `pio run -e waveshare_amoled_216` and
`pio run -e waveshare_amoled_18` succeed unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 18:27:24 -07:00
tobby168andClaude Opus 4.7 f3ed2425bf Add Waveshare ESP32-S3-Touch-AMOLED-1.8 (368×448) board support
Port the firmware to a second Waveshare AMOLED board variant alongside
the original 2.16" / 480×480. Selection is at build time via a board
macro; both envs continue to build and flash independently.

Hardware delta vs AMOLED-2.16:
  * Display: SH8601 QSPI (vs CO5300), 368×448 portrait (vs 480² square),
    SCLK on GPIO 11 (vs 38), RST routed through an XCA9554 I/O expander
    (vs direct GPIO).
  * Touch: FT3168 @ 0x38 (vs CST9220 @ 0x5A). Driven by a ~30-line
    inline FocalTech-protocol reader in main.cpp — Waveshare's
    Arduino_DriveBus library is GPLv3 and would force the project's
    license, which the README explicitly avoids.
  * I/O expander: new XCA9554/PCA9554 @ I2C 0x20 gates LCD_RST, TP_RST,
    audio amp enable, and the PWR button. Wrapped in io_expander.{h,cpp}.
    Must initialize BEFORE display/touch or both stay in reset.
  * PMU + IMU: same AXP2101 + QMI8658 as 2.16, so power.cpp/imu.cpp
    largely reuse. IMU is initialized for I2C bus health but rotation
    is fixed at 0° (the portrait panel doesn't benefit from auto-rotate
    and the strip-rotation CPU path is excluded entirely).
  * Buttons: only BOOT (GPIO 0) is a direct GPIO; PWR is read via
    XCA9554 EXIO4 polling. No third button — the AMOLED-2.16's
    Shift+Tab key (GPIO 18) is dropped for this board.
  * Flash: 16MB (vs 8MB), partition table set to default_16MB.csv.

Code structure:
  * display_cfg.h hosts a #ifdef BOARD_AMOLED_18 / #else / #endif split
    with a PlatformDisplay typedef so call sites elsewhere stay clean.
  * main.cpp, power.cpp, ui.cpp, splash.cpp gate board-specific bits on
    the same macro. Layout constants (panel heights, content Y, font
    choices on the Bluetooth screen) compress for the 368×448 portrait
    footprint so two usage panels + bottom animation label fit without
    horizontal overflow.
  * Splash scales the 20×20 pixel-art grid to 360×360 (CELL=18 vs 24)
    and centers in the portrait canvas.
  * Old AMOLED-2.16 env is unchanged at the source level (gated under
    #ifndef BOARD_AMOLED_18) and continues to compile + flash on the
    original hardware.

CLAUDE.md updated with the two-board pin maps, build/flash commands
for both envs (macOS + Linux device paths), and the per-board gotchas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 18:19:03 -07:00
Hermann Björgvin 57e5d73c6e Merge pull request #24 from tobby168/feature/auto-sleep
Auto-sleep screen after 30 min idle
2026-05-20 17:36:20 +00:00
tobby168 e0829cebdf idle: add IDLE_SLEEP_WHEN_CHARGING and IDLE_WAKE_ON_TOUCH
Addresses review feedback on #24:

- New config IDLE_SLEEP_WHEN_CHARGING (default false): while USB is
  plugged in we don't enter sleep and we wake immediately if power
  comes back. Covers both "I like watching Clawd animations on my
  plugged-in desk device" and "alternative hardware without a battery
  is always on USB, sleep would be odd."

- New config IDLE_WAKE_ON_TOUCH (default true): a touch on the dark
  panel wakes the device. The first touch is swallowed (mirrors the
  button wake-consumption), so tapping a dark screen wakes without
  also toggling splash<->usage. Set false to keep the original
  pets/sleeves-safe behaviour where touch is fully ignored while
  asleep.

power.{h,cpp} grow a power_is_vbus_in() helper backed by
pmu.isVbusIn() — distinct from isCharging() so the no-battery case
("plugged in, nothing to charge") is detected correctly.
2026-05-19 20:39:03 -07:00
tobby168 6655b0f6d0 firmware: auto-sleep screen after 30 min idle
AMOLED brightness fades to 0 after IDLE_TIMEOUT_MS without a physical
button press; any of the three buttons (BTN_BACK / BTN_FWD / PWR) fades
it back in. The first press from sleep is consumed for wake only —
Space / Shift+Tab / cycle-screen only fire on the second press, so
reaching for the device to glance at it doesn't accidentally send PTT
to Claude.

Touch never counts as activity and is fully swallowed while asleep:
pets and sleeves can't wake it, and LVGL can't secretly toggle
splash<->usage behind a black panel.

Rotation handling defers while asleep so its blank+ramp doesn't fight
the idle fade; a rotation that happens during sleep is detected and
ramped in on wake.

All tunables live in idle_cfg.h (timeout, fade durations, default
brightness) — nothing is hard-coded in main.cpp.

AMOLED brightness=0 is true 0 emission on these self-emissive panels,
so no extra power-management plumbing (light-sleep, AXP rail gating)
is needed to get the battery savings.
2026-05-19 12:41:49 -07:00
Hermann Björgvin 9ff81966fb Merge pull request #21 from georgetasioulis/fix-ble-state-on-reconnect 2026-05-18 18:33:10 +00:00
George TasioulisandClaude Opus 4.7 0b47a54956 Keep BLE UI state at CONNECTED while re-advertising
After #18 (MAX_CONNECTIONS=2), onConnect sets need_advertise=true to
fill the second slot. start_advertising() then unconditionally overwrote
state to ADVERTISING, so with a single connected client the UI flipped
CONNECTED -> ADVERTISING on the next tick and stayed there until a
second central attached.

Only flip the state to ADVERTISING when no clients are connected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:59:16 +03:00
Hermann Björgvin baed1d722b Merge pull request #18 from tobby168/macos-ble-compat 2026-05-18 00:46:19 +00:00
tobby168andClaude Opus 4.7 f252a871c4 Make BLE pairing work on macOS, allow daemon + HID to coexist
macOS Bluetooth quirks made the original BLE setup unusable from a Mac
host. Five focused changes to fix discovery, pairing, the keyboard
identification wizard, and concurrent connections, plus a couple of
cross-platform daemon/script niceties.

Firmware (ble.cpp):
  * Advertise the standard HID Service UUID (0x1812) in the primary
    packet. Without it, macOS Sequoia's Bluetooth Settings GUI
    recognizes the device internally but silently hides it from the
    "Nearby Devices" list. Service UUIDs >16-bit overflow the 31-byte
    advertising packet, so the custom data-service UUID moved to the
    scan response.
  * Switch PnP ID from Apple's USB vendor (0x05AC + Magic Keyboard
    PID 0x820A) to Espressif's BT SIG vendor (0x02E5). macOS validates
    Apple-claimed HIDs against known device IDs and refuses to surface
    a Connect button for spoofers.
  * Add the LED output report (Num/Caps/Scroll Lock) to the HID
    descriptor — macOS treats a keyboard descriptor without LEDs as
    "incomplete" and triggers the Keyboard Setup Assistant repeatedly.
  * Set HID country code to 33 (US ANSI) instead of 0 (Not Supported)
    so macOS can identify the layout without asking the user.
  * Bump CONFIG_BT_NIMBLE_MAX_CONNECTIONS to 2 and restart advertising
    after each accept. macOS holds one connection for the HID keyboard
    link; the daemon now gets its own slot for the data service in
    parallel, instead of either side starving the other.

screenshot.sh: auto-pick /dev/cu.usbmodem101 on macOS vs /dev/ttyACM0
on Linux, fall back to PlatformIO's bundled Python if pyserial isn't
on the system Python (PEP 668 blocks `pip install` on Homebrew Python),
and pass the actual framebuffer dimensions to ffmpeg instead of
hardcoding 480x480.

daemon/claude_usage_daemon.py: log API HTTP status + response body on
4xx/5xx so silent token-expiry failures (the daemon was reporting
{"s":0,"w":0} payloads instead of surfacing a 401) are visible in the
daemon log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 16:56:05 -07:00
Hermann Björgvin e3709b66e7 Update README.md 2026-05-14 19:01:56 +00:00
Hermann Björgvin 78c3a43c53 Update README.md 2026-05-14 19:01:23 +00:00
Hermann Björgvin 2774ae846e Merge pull request #6 from HermannBjorgvin/macos-support
Add macOS host support
2026-05-14 18:40:43 +00:00
512039e740 Add macOS host support
Cherry-picks the macOS-specific pieces from PR #5: Python daemon using
bleak (CoreBluetooth backend), LaunchAgent template, flash-mac.sh, and
install-mac.sh. Token is read from the macOS Keychain ("Claude
Code-credentials" service); Linux behavior is unchanged. README split
into "macOS installation" and "Linux installation" sections with
parallel Flash / Pair / Install subsections.

Co-Authored-By: Chris Davidson <36679917+lorddavidson@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 18:39:13 +00:00
Hermann Björgvin 9aa6954d42 Merge pull request #4 from BlockedPath/main 2026-05-14 15:50:52 +00:00
Hermann Björgvin 8ceb9f6e4f Update README.md
Added affiliate link
2026-05-14 12:23:27 +00:00
justin c2bd57a300 Fix formatting in CLAUDE.md for code block and add missing line breaks 2026-05-14 01:11:15 -04:00
Hermann Björgvin 40d7af93d8 Update README to reflect changes in demo and animations
Removed demo section and added attribution for Clawd animations.
2026-05-12 01:53:20 +00:00
Hermann Björgvin 4c9363440a Update README.md 2026-05-12 01:51:53 +00:00
Hermann Björgvin HaraldssonandClaude Opus 4.7 bd2afb544f Swap demo video link for inline GIF in README
GitHub's clickable-thumbnail trick worked but was awkward; a 500x500
12fps GIF renders inline everywhere. Drop the now-unused thumbnail.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 17:05:36 +00:00
Hermann Björgvin HaraldssonandClaude Opus 4.7 7281fb3c2f Use clickable thumbnail for demo video in README
GitHub strips relative src on <video> tags, so swap to an image link
pointing at the raw mp4. Extracted a frame for the thumbnail so the
two demo cells aren't visually identical.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 17:02:12 +00:00
Hermann Björgvin HaraldssonandClaude Opus 4.7 11dfa3e4b9 Add Demo section to README with photo and video
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 16:57:49 +00:00
Hermann Björgvin Haraldsson 7736ef1bab Capitalize Clawdmeter and extend tagline 2026-05-11 03:29:34 +00:00
Hermann Björgvin Haraldsson 48783bfb4b Drop open/public from library references in README 2026-05-11 03:10:50 +00:00
Hermann Björgvin Haraldsson 4e56ba4749 Rename to clawdmeter, link claudepix from splash section 2026-05-11 03:09:41 +00:00
Hermann Björgvin Haraldsson 2f40906816 Humanize README prose across remaining sections 2026-05-11 02:56:09 +00:00
Hermann Björgvin Haraldsson 1635729486 Humanize README intro paragraph 2026-05-11 02:51:29 +00:00
Hermann Björgvin Haraldsson 1a8c4038aa Rename creatures to Clawd in README and drop middle name 2026-05-11 02:44:36 +00:00
Hermann Björgvin Haraldsson b48a11c62f Correct Clawd attribution: singular animation, x.com link, mascot wording 2026-05-11 02:43:01 +00:00
Hermann Björgvin Haraldsson 3aa857f3c4 Capture Usage screenshot with live session/weekly data 2026-05-11 02:37:58 +00:00
Hermann Björgvin Haraldsson 62b226b793 Move Screens section above Features in README 2026-05-11 02:36:41 +00:00
Hermann Björgvin Haraldsson f92e1bba3e Remove stale demo.gif from previous Panlee panel 2026-05-11 02:35:43 +00:00
Hermann Björgvin Haraldsson 4b32236f67 Refresh README screenshots and prune controller-era references
Replace the 480x320 Panlee-era usage/bluetooth/controller PNGs with
fresh 480x480 captures of the current UI (Usage, Bluetooth, Splash).
Drop the Controller screen column entirely — that screen was removed
when buttons took over its shortcuts.

README cleanup: daemon poll cadence corrected to 60s, splash mood-
group + auto-rotation behaviour documented, "tap the logo to cycle"
replaced with the actual middle-button gesture, Lucide section
rewritten to point at tools/png_to_lvgl.js instead of the dead inline
Python+inkscape recipe, and intro line drops "touch controller" since
touch only toggles splash now. demo.gif flagged as stale (recapture is
a hardware task).
2026-05-11 02:33:29 +00:00
Hermann Björgvin Haraldsson 68a99cfb87 Extract make_usage_panel helper for Session/Weekly
The two panels in init_usage_screen() differed only in y-offset, pill
text, and which globals received the children — same widget tree, same
sizes, same positions. Fold into make_usage_panel() so the layout intent
shows up in two call sites instead of being duplicated by hand.

Verified by pixel-diff: pre- and post-refactor screenshots of the Usage
screen are byte-identical.
2026-05-11 02:26:18 +00:00
Hermann Björgvin Haraldsson c2f669e39f Move rotation-detect + brightness-ramp into one helper
The detect-rotation/blank/redraw block and the brightness step-up block
were two stateful chunks in loop() glued by a brightness_ramp global.
Fold them into handle_rotation_change() with local static state — the
'on rotation change, flash to black then ramp back' invariant lives in
one place and the loop body shrinks.
2026-05-11 02:22:33 +00:00