Build, flash and recover C124
On this page
This example uses the reusable library in lib/GrokGadgets. It is standalone Arduino firmware, not an ESPHome integration.
Use M5Stack AtomS3 Lite SKU C124, with ESP32-S3FN8 and 8 MB flash. ATOM Lite and AtomS3 with a display are different boards.
Builds and local software tests need no public hosting. For the USB route, run the bridge
and gateway on the same computer. That computer must remain on during use.
The gateway offers local stdio or authenticated HTTP MCP through serve at
http://127.0.0.1:8766/mcp. Its separate device port is authenticated loopback TCP.
Public HTTPS, OAuth, and actual Grok Bot use remain separate gates. Do not expose the device port through a tunnel.
See the hosting FAQ
for who operates each process and the HARD-GROK-REMOTE-001 remote-access gate.
Clean setup
You need Python 3.11 or later, CMake 3.16 or later, Git and a C++14 compiler. The recorded local build used Python 3.14.7 on macOS. Linux USB operation remains unverified.
Run the README quickstart from the repository root. It installs the pinned tools, runs host checks, and compiles C124 without hardware.
The pinned tools and libraries are:
| Dependency | Version |
|---|---|
| PlatformIO | 6.1.18 |
| espressif32 | 6.10.0 |
| Arduino-ESP32 | 2.0.17 |
| Xtensa compiler | 8.4.0+2021r2-patch5 |
| ArduinoJson | 6.21.5 |
| NeoPixel | 1.12.3 |
Verification records contain the full resolved package list and hashes. Downloads need internet access and local disk space. Mac host tests do not verify Linux USB permissions or physical pins.
Inspect build output
The build writes these files in .pio/build/atoms3-lite-usb/:
firmware.binfirmware.elfbootloader.binpartitions.bin
Git ignores build output. tools/package_build.py copies these files, plus boot_app0.bin and flash_args, into artifacts/c124-usb and writes checksums. A successful compile means build verified, hardware pending.
docs/build-checksums.json is the only current checksum record. firmware.bin and firmware.elf follow the installed Xtensa package system (darwin_arm64, darwin_x86_64, or a Linux value), not only the version string 8.4.0+2021r2-patch5. The same source built with another host variant is a different image. Builds pass -ffile-prefix-map so the checkout path and the PlatformIO home are outside the image hash. Bootloader and partition hashes omit those paths. Hash tables in the verification notes are historical snapshots of older commits.
To create a package with source records:
- Commit the tested source.
- From a clean checkout, run
.venv/bin/python tools/package_build.py. - Update
docs/build-checksums.jsonfrom the resulting manifest. - Record that update in a separate evidence commit.
Packaging rebuilds the exact commit. It records clean source state, UTC build time, toolchain versions and SHA-256 hashes. It rejects uncommitted source changes.
Flash when hardware is available
These hardware steps remain unverified. They are separate from the software quickstart. Select and authorize the intended physical board first.
- Connect C124 with a USB-C data cable.
- Run
.venv/bin/pio device list. - Identify the board's port. Do not guess another device's port.
- Close any serial monitor or bridge.
- Replace the port placeholder and upload:
.venv/bin/pio run -e atoms3-lite-usb -t upload --upload-port /dev/cu.usbmodemYOUR_BOARD
On Linux, the port is often /dev/ttyACM0. Inspect the actual port before use. Linux can require membership in a serial-device group, often dialout. You can need to reconnect or log in again after that change. Do not run the entire gateway as root.
The example sends no debug logs on the protocol CDC channel.
pio run -t upload is the flash path for this environment. It writes:
| File | Offset |
|---|---|
bootloader.bin |
0x0 |
partitions.bin |
0x8000 |
boot_app0.bin |
0xe000 |
firmware.bin |
0x10000 |
PlatformIO uploads this Arduino board as DIO, 80 MHz, 8 MB. It rewrites the board file's QIO mode to DIO. No board was flashed in this repository. flash_args in the local package records the same offsets for inspection.
Connect the USB bridge
The device ID is c124- plus the MAC in the order esptool prints, lowercase hex, no separators. MAC bc:9a:78:56:34:12 is c124-bc9a78563412. Each boot creates a new random boot ID. Credentials stay on the host. The USB hello has no credential.
The bridge reads GROK_GADGETS_DEVICE_TOKEN from the environment and adds that token on the loopback connection. Keep the token out of Git.
Install the gateway on this computer, then follow its enrollment and USB bridge steps:
- Run
grok-gadgets-gateway initonce to create the private MCP token and device registry. - Enroll the exact device ID above with
grok-gadgets-gateway enroll DEVICE_ID. - Keep
grok-gadgets-gateway serverunning in one terminal. - In another terminal, set
GROK_GADGETS_DEVICE_TOKENto the value printed once by enrollment. Startpython -m grok_gadgets_gateway.usb_bridge PORTwith the identified serial port.
Use the gateway's Python environment for these commands. The device token protects the local connection; it is separate from the MCP bearer token. The commands exist on simplify-and-fix, but no physical C124 or Grok Bot session has used them here.
If USB disconnects, the bridge retries the same serial path. Plugging the board back in power-cycles it, so the boot ID changes. If the operating system assigns a different port, stop the bridge, identify that port, and restart with it. Automatic recovery is software-tested; physical USB recovery remains unverified.
Recover the board
If the board does not appear as a USB device, follow M5Stack's C124 download-mode procedure:
- Hold the reset button for about two seconds, until the green indicator appears.
- Release the button.
- Identify the new port.
- Upload to that port.
The reset/boot control is different from the front user button. If the board still does not appear, use a direct USB port and a known data cable.
For an unreliable upload connection, reduce upload speed in platformio.ini. Record this build change.
Restore a previous version
- Open a clean checkout of a previously tested commit.
- Repeat that commit's pinned build with the same Xtensa toolchain package
system. - Upload with
pio run -t upload.
That command writes the four images at the offsets above.
For factory restoration, use the manufacturer's M5Burner or Easyloader route. Preserve its source and license. Verify the exact C124 target. No firmware was flashed during the recorded local phase.
First physical acceptance
Record SDK and gateway commits, firmware checksums, operating system, port, timestamps and observations.
- Discover C124.
- Request green, another colour and off. Observe each result.
- Press and release the user button. Check the order of reported events.
- Unplug the board during a command. Check that the gateway marks it offline after its timeout and does not report an unobserved result as confirmed. The bridge should keep retrying.
- Plug the board back in. USB power starts a new boot, so the boot ID changes. Check automatic recovery and fresh state. Restart the bridge only if the port name changed.
- Reboot the board and gateway. Check boot and cursor resets.
- Repeat through Grok Bot only after its account and transport route is verified.
A compiled binary or firmware acknowledgement cannot replace these observations.