Skip to content

feat: migrate from M5StickCPlus to M5Unified, add M5StickS3 support#3

Open
imliubo wants to merge 3 commits into
anthropics:mainfrom
imliubo:feat/migrate-to-m5unified
Open

feat: migrate from M5StickCPlus to M5Unified, add M5StickS3 support#3
imliubo wants to merge 3 commits into
anthropics:mainfrom
imliubo:feat/migrate-to-m5unified

Conversation

@imliubo
Copy link
Copy Markdown

@imliubo imliubo commented Apr 18, 2026

Migrate from M5StickCPlus to M5Unified — add M5StickS3 support

Summary

Replace the M5StickCPlus-specific library with M5Unified + M5GFX, enabling the same codebase to run on both M5StickC Plus and M5StickS3 without conditional compilation for core functionality.

Changes

Build system (platformio.ini)

  • Extract shared configuration (framework, libs, build flags) into [env]
  • Add [env:m5stack-sticks3] with PSRAM, USB-CDC, and M5PM1 power management

API migration (all source files)

Before (M5StickCPlus) After (M5Unified)
M5StickCPlus.h M5Unified.h
TFT_eSprite / TFT_eSPI M5Canvas / lgfx::v1::LGFXBase
M5.Axp.* M5.Power.* / M5.Lcd.*
M5.Beep M5.Speaker
M5.Imu.getAccelData() M5.Imu.getAccel()
M5.Axp.GetBtnPress() M5.BtnPWR.wasClicked()
RTC_TimeTypeDef / RTC_DateTypeDef m5::rtc_time_t / m5::rtc_date_t
LittleFS.begin(false) LittleFS.begin(true) (auto-format on first boot)

Hardware adaptation

  • Guard LED_PIN with CONFIG_IDF_TARGET_ESP32S3 (S3 has no user LED)
  • Remove AXP192-specific temperature readout (not available on S3)
  • Use M5.Power.getBatteryLevel() instead of manual voltage-to-percentage calculation

Tested on

  • M5StickC Plus (ESP32)
  • M5StickS3 (ESP32-S3)
  • M5StickC Plus2 (ESP32) by @rfdnxbro

This migration was authored with the assistance of Claude Opus 4.6 (Anthropic).

@tonykcn
Copy link
Copy Markdown

tonykcn commented Apr 19, 2026

We really need this PR. Since we're migrating to the more powerful M5StickCPlus2 and its power management module has fundamentally changed, M5Unified seems like the better approach.

@tankyhsu
Copy link
Copy Markdown

tankyhsu commented Apr 19, 2026

Awesome! This M5Unified migration is exactly what we need — a unified API that lets the same codebase run on both C Plus and S3. Looking forward to the merge, I have my M5StickS3 ready to flash 👍

@rfdnxbro
Copy link
Copy Markdown

Following up on the earlier comment about Plus2's fundamentally changed power management — I can confirm this branch works on the M5StickC Plus2 with no config changes at all. Just run the existing m5stickc-plus environment and it flashes and runs correctly.

Verified on Plus2:

  • Build & flash via pio run -e m5stickc-plus -t upload succeed
  • Buddy character renders on boot
  • BLE pairing with Claude Desktop works
  • Approve (button A) / deny (button B) both work end-to-end

This migration is the reason my Plus2 can run the buddy at all — thanks for the work. For future Plus2 users landing here, it might help if the README noted that this env covers Plus2 too.

@knottttt
Copy link
Copy Markdown

Hi, I'm testing this on Windows 11 with M5StickC Plus.

With the original firmware, I get auth ok in the serial log but the
device disconnects immediately after — no JSON commands are ever received
from the desktop. Hardware Buddy stays "Disconnected".

Serial log:
[ble] connected
[ble] mtu=517
[ble] passkey 856869
[ble] auth ok
[ble] disconnected

Does this branch fix the Windows BLE issue, or is this a known problem
with the Claude Desktop Windows side?

@FingerLiu
Copy link
Copy Markdown

Verified on S3:

Build & flash via pio run -e m5stack-sticks3 -t upload succeed
Buddy character renders on boot
BLE pairing with Claude Desktop works

But can not trigger it because I do not have a pro subscription...

Trying to get it work with local claude code now..

@eMUQI
Copy link
Copy Markdown

eMUQI commented Apr 21, 2026

@imliubo Thanks for the great work!

Two observations on M5StickS3 from the device info screen:

  1. Charging status flickers rapidly whenever plugged in.

  2. Battery current always shows 0 mA — is this a hardware limitation on M5StickS3, or is there a way to get the actual value?

@imliubo
Copy link
Copy Markdown
Author

imliubo commented Apr 22, 2026

Hi @eMUQI Thanks for those feedback.

  1. Charging status flickers rapidly whenever plugged in.

I will test and try find the reason.

  1. Battery current always shows 0 mA — is this a hardware limitation on M5StickS3, or is there a way to get the actual value?

Yes, it's hardware limitation, we can't read the charge/discharge current.

@imliubo
Copy link
Copy Markdown
Author

imliubo commented Apr 22, 2026

Hi @knottttt,

I didn't test it with Windows PC, I assume this is a Windows problem.
Has anyone encountered a similar problem?

Comment thread src/main.cpp Outdated
Comment thread src/character.cpp Outdated
fatwang2 added a commit to fatwang2/claude-desktop-buddy that referenced this pull request Apr 23, 2026
- Add a fork note at the top linking the upstream repo and PR anthropics#3.
- Flashing section now shows the per-env commands (m5stickc-plus vs
  m5stack-sticks3) and documents the S3's TinyUSB port-rename quirk
  plus the 1200-baud touch for forcing bootloader entry.
- Controls section mentions how hotkey mode re-routes Hold A/B.
- New "Hotkey mode" section covers enabling, the four modifier
  presets, behavior, and a Keyboard Viewer / Ctrl+click smoke test.
@imliubo
Copy link
Copy Markdown
Author

imliubo commented Apr 23, 2026

Hi @felixrieseberg ,
Thanks for the review. I have corrected the code. Please review it again.

@randybb
Copy link
Copy Markdown

randybb commented Apr 23, 2026

Hope you will add support for StackChan (basically S3Core with stepper motors) as well.

@eMUQI
Copy link
Copy Markdown

eMUQI commented Apr 23, 2026

Hi @imliubo, thanks again for your work on this PR. I tested it on an M5StickS3, but I’m not sure whether these issues were introduced by this PR or if they were already present in the project.

I’m currently seeing a few problems on StickS3:

  1. Time / clock is incorrect
    The desktop does send the time packet, but on-device the clock can still show invalid values / wrong date. From local debugging, this seems related to RTC sync/readback on S3 (setTime / setDate and then getTime / getDate separately).

    28CACB02-B0DB-4468-A25C-74F1D19C27B5
  2. Clock orientation appears wrong on StickS3
    The clock page orientation also seems inverted on S3: when held vertically it may render as landscape, and when held sideways it may render as portrait. I’m not sure if this affects other devices, but on StickS3 the IMU axis mapping used for clock orientation seems incorrect.

  3. Battery / charging status flickers rapidly on the Info page
    While charging, the battery state switches back and forth very quickly between charging / usb / full-like states, so the UI is unstable.

  4. New issue: device restarts when charging and placed upright
    On StickS3, if the device is charging and I stand it upright so the clock screen should activate, it sometimes immediately reboots. I haven’t fully proven root cause, but it looks related to entering the clock path with invalid RTC values.

  5. Brightness setting is not persisted
    Changing brightness works immediately, but after reboot it returns to the brightest level.

Here is a preliminary revision(by codex) for your reference: http://github.com/eMUQI/claude-desktop-buddy/commit/bd5efae2d57dab0bb2a1d274232b12732da52403

@imliubo
Copy link
Copy Markdown
Author

imliubo commented Apr 23, 2026

Hi @eMUQI ,
Thank you for the very detailed testing.

Time / clock is incorrect
Clock orientation appears wrong on StickS3
New issue: device restarts when charging and placed upright

It seems the time only updates after connecting to Claude Desktop. I need to think about how to test this, because I don't have access to Claude.

Battery / charging status flickers rapidly on the Info page

It looks only happen when after charge to full? If in charging state(battery voltage < 4.1v) it was stable. Because StickS3 don't have real PMIC, we detect the charge IC(LGS4056) charge state pin as the charge status, so it maight be a little unstable.
image

Brightness setting is not persisted

Yes, the brightness setting looks not saved.

I've reviewed your code, and it looks like the modifications are quite complete. Perhaps you could merge the code directly into this PR?

@imliubo
Copy link
Copy Markdown
Author

imliubo commented Apr 24, 2026

Hi @eMUQI, thanks again for the detailed testing and the patch!

I found a way to connect to Claude Desktop and I've tested your changes locally on M5StickS3 and everything works well — the clock no longer reboots when standing upright on USB power, the orientation now matches the device posture, the charging status is stable, and the brightness setting persists across reboots.

36537bffd68afb263619abebdd14ec2b

I've cherry-picked your commit (bd5efae) onto this PR with original authorship preserved, and will continue the PR from here. Credit goes to you for the fix. 🙌

Thank you very much for your detailed testing and explanation.

@felixrieseberg
Copy link
Copy Markdown
Member

@imliubo could you please sign your commits? We require all code to be signed. Thank you!

@imliubo
Copy link
Copy Markdown
Author

imliubo commented Apr 27, 2026

@felixrieseberg Done! I've amended ad72036 to include the Signed-off-by trailer and force-pushed the branch. All three commits now carry the signature. Sorry for the oversight!

@imliubo
Copy link
Copy Markdown
Author

imliubo commented May 6, 2026

Hi @felixrieseberg , let me know if there’s anything I should update or improve. Thanks!

@maxromanovsky
Copy link
Copy Markdown

@imliubo could you plz merge? It seems to be approved by @felixrieseberg

imliubo and others added 3 commits May 21, 2026 16:25
Replace the M5StickCPlus-specific library with M5Unified + M5GFX so the
same codebase runs on M5StickC Plus and M5StickS3.

platformio.ini:
- Extract shared config into [env], add [env:m5stack-sticks3] with
  PSRAM, USB-CDC and M5PM1 power management lib

API migration (all source files):
- M5StickCPlus.h → M5Unified.h
- TFT_eSprite / TFT_eSPI → M5Canvas / lgfx::v1::LGFXBase
- M5.Axp.* → M5.Power.* / M5.Lcd.*
- M5.Beep → M5.Speaker
- M5.Imu.getAccelData → M5.Imu.getAccel
- M5.Axp.GetBtnPress() → M5.BtnPWR.wasClicked()
- RTC_TimeTypeDef/RTC_DateTypeDef → m5::rtc_time_t/m5::rtc_date_t
- LittleFS.begin(false) → begin(true) for auto-format on first boot

Hardware adaptation:
- Guard LED_PIN behind CONFIG_IDF_TARGET_ESP32S3 (S3 has no user LED)
- Remove AXP192-specific temp readout
- Use M5.Power.getBatteryLevel() instead of manual voltage calculation

Signed-off-by: imliubo <imliubo@makingfun.xyz>
Avoid formatting LittleFS on the first mount attempt so existing pet data
is not wiped after a firmware upgrade when the filesystem fails to mount
cleanly. Only fall back to a format/remount path when the filesystem still
isn't accessible.

Also restore the previous USB-power semantics for clock and screen-off
behavior by tracking VBUS presence separately from charging state. This
prevents a fully charged device that remains plugged into USB from auto-
blanking once charging current stops.

Signed-off-by: imliubo <imliubo@makingfun.xyz>
…ss setting

(cherry picked from commit bd5efae)
Signed-off-by: imliubo <imliubo@makingfun.xyz>
@imliubo imliubo force-pushed the feat/migrate-to-m5unified branch from 5d04fe3 to 6d28f2c Compare May 21, 2026 08:29
@imliubo
Copy link
Copy Markdown
Author

imliubo commented May 21, 2026

Hi @maxromanovsky , thanks for the nudge! I had misunderstood the signing requirement earlier — only added the Signed-off-by trailer instead of cryptographically signing the commits. All three commits are now signed with SSH (ED25519) and should show as Verified.

@felixrieseberg sorry for the back-and-forth — could you take another look and merge when you have a moment? No code changes since your approval, only signatures. Thanks!

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.

10 participants