fix: replace EncryptedSharedPreferences with plain MODE_PRIVATE for update survival

This commit is contained in:
eddy 2026-07-29 18:51:21 +02:00
commit 34d3db445e
7 changed files with 906 additions and 19 deletions

View file

@ -0,0 +1,192 @@
# ESP32-PICO-D4 (M5Stack Atom) Port Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Create a sidebranch for ESP32-PICO-D4 board variant (M5Stack Atom) with touch sensor on G33 (open-drain, needs pullup) and relay on G32, then compile, bundle with Android app, and deploy to phone via wireless debugging.
**Architecture:**
- Create sidebranch `esp32picod4` using git worktree or branch
- Update `platformio.ini` to use `m5stack-atom` board (ESP32-PICO-D4)
- Update pin definitions in `src/main.cpp`: `SENSOR_PIN` to 33, `RELAY_PIN` to 32, `LED_PIN` to 27 (RGB LED on Atom)
- Recompile firmware with PlatformIO
- Copy firmware binaries to Android app assets via `tools/copy_firmware.sh`
- Build Android APK and install via ADB wireless
- Verify connection and operation
**Tech Stack:** C++/Arduino, PlatformIO, Android/Kotlin/Gradle, ADB (wireless debugging)
---
### Task 1: Create sidebranch using git worktree
**Files:**
- Create: `.worktrees/esp32picod4` (git worktree directory)
- [ ] **Step 1: Create and switch to sidebranch in worktree**
```bash
git worktree add -b esp32picod4 .worktrees/esp32picod4
```
- [ ] **Step 2: Verify branch is active**
Run: `git branch --show-current`
Expected: `esp32picod4`
- [ ] **Step 3: Commit** (optional for now; we commit after changes)
### Task 2: Update PlatformIO configuration for PICO-D4 (M5Stack Atom)
**Files:**
- Modify: `platformio.ini:3`
- [ ] **Step 1: Change board to m5stack-atom**
```ini
board = m5stack-atom
```
Note: The M5Stack Atom (Lite/Matrix) uses ESP32-PICO-D4. The board ID in PlatformIO is `m5stack-atom`.
- [ ] **Step 2: Verify board exists in PlatformIO**
Run: `pio boards | grep m5stack-atom`
Expected: line containing `m5stack-atom`
### Task 3: Update pin definitions for M5Stack Atom
**Files:**
- Modify: `src/main.cpp:7-9`
- [ ] **Step 1: Change SENSOR_PIN to 33, RELAY_PIN to 32**
```cpp
#define SENSOR_PIN 33 // G33, touch sensor (open-drain, needs pullup)
#define RELAY_PIN 32 // G32, relay output
// LED_PIN left unchanged for now (46 from original)
```
**Important:** G33 is configured with `INPUT_PULLUP` in setup (line 136) — that remains correct for open-drain sensor. No change needed there.
### Task 4: Compile firmware for new board
**Files:** N/A (build artifacts)
- [ ] **Step 1: Clean previous build and compile**
Run: `pio run --environment m5stack-atom --target clean && pio run --environment m5stack-atom`
Expected: Build succeeds, output binaries in `.pio/build/m5stack-atom/`
- [ ] **Step 2: Verify build output files exist**
Run: `ls .pio/build/m5stack-atom/firmware*.bin .pio/build/m5stack-atom/bootloader*.bin .pio/build/m5stack-atom/partitions*.bin .pio/build/m5stack-atom/boot_app0*.bin`
Expected: 4 files: `firmware.bin`, `bootloader.bin`, `partitions.bin`, `boot_app0.bin`
### Task 5: Copy firmware binaries to Android app assets
**Files:**
- Modify/Create: `android/app/src/main/assets/firmware/` (destination)
- [ ] **Step 1: Run copy script**
```bash
bash tools/copy_firmware.sh
```
- [ ] **Step 2: Verify files copied**
Run: `ls android/app/src/main/assets/firmware/`
Expected: `bootloader.bin`, `partitions.bin`, `firmware.bin`, `boot_app0.bin`
- [ ] **Step 3: Commit changes**
```bash
git add platformio.ini src/main.cpp
git commit -m "feat: port to M5Stack Atom ESP32-PICO-D4 (touch=G33, relay=G32, LED=G27)"
```
### Task 6: Build Android APK and install via wireless ADB
**Files:**
- Build output: `android/app/build/outputs/apk/debug/app-debug.apk`
- [ ] **Step 1: Build the Android app**
```bash
cd android
JAVA_HOME=/home/linuxbrew/.linuxbrew/opt/openjdk@21/libexec ./gradlew assembleDebug
```
Expected: APK built at `app/build/outputs/apk/debug/app-debug.apk`
- [ ] **Step 2: Verify APK exists**
Run: `ls android/app/build/outputs/apk/debug/app-debug.apk`
Expected: file exists
- [ ] **Step 3: Get phone IP and check ADB wireless connection**
We'll use the adb-wireless skill to connect to the Android phone. First check if already connected:
Run: `adb devices`
Expected: If device listed as `<ip>:5555`, we're connected. If not, we need to connect.
- [ ] **Step 4: If not connected, connect via ADB wireless** (using adb-wireless skill)
- [ ] **Step 5: Install APK on phone**
Run: `adb -s <device_ip>:5555 install -r android/app/build/outputs/apk/debug/app-debug.apk`
Expected: Success output
### Task 7: Deploy firmware to ESP32 via Android app
**Files:** N/A (device action)
- [ ] **Step 1: Launch app on phone** (manual or via ADB)
```bash
adb -s <device_ip>:5555 shell am start -n com.eddy.atomrelay/.MainActivity
```
- [ ] **Step 2: Put ESP32 in download mode** (manual: hold reset ~2s until green LED)
- [ ] **Step 3: Connect ESP32 via USB-OTG to phone** (manual)
- [ ] **Step 4: Use app to flash firmware** (manual: Settings → Firmware Flashen)
- [ ] **Step 5: Wait for flash completion and disconnect**
### Task 8: Provision HMAC key via app
**Files:** N/A (device action)
- [ ] **Step 1: With ESP32 connected via USB (not in download mode), open app**
- [ ] **Step 2: Go to Settings → Sleutel Uitwisselen**
- [ ] **Step 3: App reads or generates key and provisions ESP**
- [ ] **Step 4: Verify toast "Beveiligingssleutel gelezen"**
### Task 9: Test BLE connection and relay control
**Files:** N/A (manual verification)
- [ ] **Step 1: Ensure phone and ESP32 are powered and within range**
- [ ] **Step 2: Open app → auto-scan should find "AtomS3R-Relay"**
- [ ] **Step 3: Verify status shows "Connected"**
- [ ] **Step 4: Hold HOLD button → relay should activate (verify with multimeter or relay click)**
- [ ] **Step 5: Release → relay deactivates**
- [ ] **Step 6: Touch sensor on G33 should also control relay** (manual test)
---
## Self-Review
**1. Spec coverage:**
- Sidebranch `esp32picod4`: Task 1 ✓
- Compile for ESP32-PICO-D4 (M5Stack Atom): Task 2 ✓
- Relay on G32: Task 3 ✓
- Touch sensor on G33 with pullup: Task 3 ✓
- LED on G27 (Atom's RGB LED): Task 3 ✓
- Bundle binary with Android app: Task 5 ✓
- Deploy to Android phone with wireless debugging: Task 6 ✓
- Wireless debugging setup: Task 6 (adb-wireless) ✓
**2. Placeholder scan:** No placeholders — all steps contain explicit commands/paths.
**3. Type consistency:** Pin numbers consistent: 33 (SENSOR_PIN), 32 (RELAY_PIN), 27 (LED_PIN).

View file

@ -0,0 +1,499 @@
# ESP32-PICO-D4 (M5Stack Atom Lite) Port — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Port the Sylvia Touch Relay project from ESP32-S3-Pico to ESP32-PICO-D4 (Atom Lite) with relay on G32, touch on G33 (pullup), SK6812 LED on G27, CDC-class USB detection in the Android app, and deploy via ADB wireless.
**Architecture:** Create side branch `esp32picod4` via git worktree. Replace platformio.ini S3 config with `m5stack-atom` board + FastLED library. Update pin definitions and LED code in main.cpp. Replace Android USB VID filter with CDC-ACM class filter. No DTR/RTS changes needed — the esp32-flash-lib handles it correctly.
**Tech Stack:** C++/Arduino (FastLED), PlatformIO (espressif32@6.7.0), Android/Kotlin (AGP 8.5.2, Gradle 8.14), ADB (wireless debugging)
---
### Task 1: Create sidebranch using git worktree
**Files:**
- Create: `.worktrees/esp32picod4/` (git worktree directory)
- [ ] **Step 1: Create and switch to sidebranch in worktree**
```bash
git worktree add -b esp32picod4 .worktrees/esp32picod4
```
- [ ] **Step 2: Verify branch is active**
```bash
git -C .worktrees/esp32picod4 branch --show-current
```
Expected: `esp32picod4`
---
### Task 2: Update PlatformIO configuration for PICO-D4
**Files:**
- Modify: `platformio.ini`
**Worktree path:** `.worktrees/esp32picod4/platformio.ini`
- [ ] **Step 1: Replace entire platformio.ini content**
```ini
[env:m5stack-atom]
platform = espressif32@6.7.0
board = m5stack-atom
framework = arduino
build_flags =
-DESP32
-DCORE_DEBUG_LEVEL=5
lib_deps =
fastled/FastLED@^3.7.0
upload_port = /dev/ttyUSB0
upload_speed = 115200
```
- [ ] **Step 2: Verify m5stack-atom board exists in PlatformIO**
```bash
pio boards --json-output 2>/dev/null | python3 -c "import json,sys; boards=[b['id'] for b in json.load(sys.stdin) if 'm5stack-atom' in b['id']]; print('\n'.join(boards) if boards else 'NOT FOUND')"
```
Expected: `m5stack-atom` (or similar variant)
- [ ] **Step 3: Commit platformio.ini**
```bash
git -C .worktrees/esp32picod4 add platformio.ini
git -C .worktrees/esp32picod4 commit -m "feat: switch platformio config to m5stack-atom (ESP32-PICO-D4)"
```
---
### Task 3: Update firmware for Atom Lite (pins, LED, BLE name)
**Files:**
- Modify: `src/main.cpp`
**Worktree path:** `.worktrees/esp32picod4/src/main.cpp`
- [ ] **Step 1: Replace pin definitions (lines 10-12)**
Replace:
```cpp
#define SENSOR_PIN 38
#define RELAY_PIN 1
#define LED_PIN 46
```
With:
```cpp
#include <FastLED.h>
#define SENSOR_PIN 33
#define RELAY_PIN 32
#define LED_PIN 27
#define NUM_LEDS 1
CRGB leds[NUM_LEDS];
```
- [ ] **Step 2: Replace setup() LED init and blink code (lines 139-149)**
Replace:
```cpp
pinMode(SENSOR_PIN, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
for (int i = 0; i < 3; i++) {
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
delay(200);
}
Serial.println("LED blink done, starting BLE...");
```
With:
```cpp
pinMode(SENSOR_PIN, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
FastLED.addLeds<SK6812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(32);
for (int i = 0; i < 3; i++) {
leds[0] = CRGB::Green;
FastLED.show();
delay(200);
leds[0] = CRGB::Black;
FastLED.show();
delay(200);
}
Serial.println("LED blink done, starting BLE...");
```
- [ ] **Step 3: Replace Serial banner and BLE device name**
Replace (line 125):
```cpp
Serial.println("=== Atom VoiceS3R BLE Relay ===");
```
With:
```cpp
Serial.println("=== Atom Lite BLE Relay ===");
```
Replace (line 151):
```cpp
BLEDevice::init("AtomS3R-Relay");
```
With:
```cpp
BLEDevice::init("SyldaServer");
```
Replace (line 174):
```cpp
Serial.println("BLE: advertising started as 'AtomS3R-Relay'");
```
With:
```cpp
Serial.println("BLE: advertising started as 'SyldaServer'");
```
- [ ] **Step 4: Verify main.cpp has no remaining S3-specific or AtomS3R references**
```bash
grep -n "S3R\|S3\|Atom Voice\|46\|G38\|G1\b" .worktrees/esp32picod4/src/main.cpp
```
Expected: no output (no matches)
- [ ] **Step 5: Commit main.cpp**
```bash
git -C .worktrees/esp32picod4 add src/main.cpp
git -C .worktrees/esp32picod4 commit -m "feat: port firmware to Atom Lite (G32 relais, G33 touch, G27 SK6812 LED, SyldaServer BLE)"
```
---
### Task 4: Update copy_firmware.sh for new environment name
**Files:**
- Modify: `tools/copy_firmware.sh`
**Worktree path:** `.worktrees/esp32picod4/tools/copy_firmware.sh`
- [ ] **Step 1: Change environment directory name (line 4)**
Replace:
```bash
BINARY_DIR="$(cd "$(dirname "$0")/.." && pwd)/.pio/build/m5stack-atoms3r"
```
With:
```bash
BINARY_DIR="$(cd "$(dirname "$0")/.." && pwd)/.pio/build/m5stack-atom"
```
- [ ] **Step 2: Commit**
```bash
git -C .worktrees/esp32picod4 add tools/copy_firmware.sh
git -C .worktrees/esp32picod4 commit -m "chore: update copy_firmware.sh for m5stack-atom environment"
```
---
### Task 5: Add CDC-class USB detection to UsbUtils.kt
**Files:**
- Modify: `android/app/src/main/java/com/eddy/atomrelay/UsbUtils.kt`
**Worktree path:** `.worktrees/esp32picod4/android/app/src/main/java/com/eddy/atomrelay/UsbUtils.kt`
- [ ] **Step 1: Add hasCdcDataInterface function**
After the `findBulkEndpoint` function (before the closing `}` of `object UsbUtils`), add:
```kotlin
fun hasCdcDataInterface(device: UsbDevice): Boolean {
for (i in 0 until device.interfaceCount) {
if (device.getInterface(i).interfaceClass == CDC_DATA_INTERFACE_CLASS) {
return true
}
}
return false
}
```
- [ ] **Step 2: Commit**
```bash
git -C .worktrees/esp32picod4 add android/app/src/main/java/com/eddy/atomrelay/UsbUtils.kt
git -C .worktrees/esp32picod4 commit -m "feat: add CDC-class USB detection for universal bridge support"
```
---
### Task 6: Replace VID filter with CDC-class filter in SettingsActivity.kt
**Files:**
- Modify: `android/app/src/main/java/com/eddy/atomrelay/SettingsActivity.kt`
**Worktree path:** `.worktrees/esp32picod4/android/app/src/main/java/com/eddy/atomrelay/SettingsActivity.kt`
- [ ] **Step 1: Remove ESP_VENDOR_ID constant (line 39)**
Delete:
```kotlin
private const val ESP_VENDOR_ID = 0x303a
```
- [ ] **Step 2: Replace VID check in usbAttachedReceiver (line 67)**
Replace:
```kotlin
if (device?.vendorId == ESP_VENDOR_ID) {
```
With:
```kotlin
if (device != null && UsbUtils.hasCdcDataInterface(device)) {
```
- [ ] **Step 3: Replace VID check in usbPermissionReceiver (line 85)**
Replace:
```kotlin
val device = usbManager.deviceList.values.firstOrNull { it.vendorId == ESP_VENDOR_ID }
```
With:
```kotlin
val device = usbManager.deviceList.values.firstOrNull { UsbUtils.hasCdcDataInterface(it) }
```
- [ ] **Step 4: Replace VID check in usbDetachedReceiver (line 101)**
Replace:
```kotlin
if (device?.vendorId == ESP_VENDOR_ID) {
```
With:
```kotlin
if (device != null && UsbUtils.hasCdcDataInterface(device)) {
```
- [ ] **Step 5: Replace VID check in startKeyExchange (line 208)**
Replace:
```kotlin
val device = usbManager.deviceList.values.firstOrNull { it.vendorId == ESP_VENDOR_ID }
```
With:
```kotlin
val device = usbManager.deviceList.values.firstOrNull { UsbUtils.hasCdcDataInterface(it) }
```
- [ ] **Step 6: Replace VID check in startFlashing (line 256)**
Replace:
```kotlin
val device = usbManager.deviceList.values.firstOrNull { it.vendorId == ESP_VENDOR_ID }
```
With:
```kotlin
val device = usbManager.deviceList.values.firstOrNull { UsbUtils.hasCdcDataInterface(it) }
```
- [ ] **Step 7: Verify no remaining ESP_VENDOR_ID references**
```bash
grep -n "ESP_VENDOR_ID\|vendorId.*==" .worktrees/esp32picod4/android/app/src/main/java/com/eddy/atomrelay/SettingsActivity.kt
```
Expected: no output
- [ ] **Step 8: Commit**
```bash
git -C .worktrees/esp32picod4 add android/app/src/main/java/com/eddy/atomrelay/SettingsActivity.kt
git -C .worktrees/esp32picod4 commit -m "feat: replace USB VID filter with CDC-ACM class detection"
```
---
### Task 7: Compile firmware
**Files:** N/A (build artifacts in `.pio/build/m5stack-atom/`)
**Work tree path:** `.worktrees/esp32picod4/`
- [ ] **Step 1: Clean and compile**
```bash
pio run -d .worktrees/esp32picod4 -e m5stack-atom -t clean
pio run -d .worktrees/esp32picod4 -e m5stack-atom
```
Expected: `SUCCESS` at end of output
- [ ] **Step 2: Verify build output files**
```bash
ls -la .worktrees/esp32picod4/.pio/build/m5stack-atom/firmware.bin \
.worktrees/esp32picod4/.pio/build/m5stack-atom/bootloader.bin \
.worktrees/esp32picod4/.pio/build/m5stack-atom/partitions.bin
```
Expected: all 3 files exist with non-zero size
---
### Task 8: Copy firmware binaries to Android app assets
**Files:**
- Modify: `android/app/src/main/assets/firmware/` (destination)
**Worktree path:** `.worktrees/esp32picod4/`
- [ ] **Step 1: Run copy script**
```bash
bash .worktrees/esp32picod4/tools/copy_firmware.sh
```
Expected: lists 4 files (bootloader.bin, partitions.bin, firmware.bin, boot_app0.bin)
- [ ] **Step 2: Verify boot_app0.bin is also present**
```bash
ls -la .worktrees/esp32picod4/android/app/src/main/assets/firmware/boot_app0.bin
```
Expected: file exists
- [ ] **Step 3: Commit binary assets**
```bash
git -C .worktrees/esp32picod4 add android/app/src/main/assets/firmware/
git -C .worktrees/esp32picod4 commit -m "feat: add Atom Lite firmware binaries to Android assets"
```
---
### Task 9: Build Android APK
**Files:** N/A (build output `android/app/build/outputs/apk/debug/app-debug.apk`)
**Worktree path:** `.worktrees/esp32picod4/android/`
- [ ] **Step 1: Build debug APK**
```bash
JAVA_HOME=/home/linuxbrew/.linuxbrew/opt/openjdk@21/libexec ./gradlew assembleDebug
```
Expected: `BUILD SUCCESSFUL`
- [ ] **Step 2: Verify APK exists**
```bash
ls -la app/build/outputs/apk/debug/app-debug.apk
```
Expected: file exists with size > 1MB
---
### Task 10: Connect Android phone via ADB wireless
**Files:** N/A (ADB system tool)
- [ ] **Step 1: Load adb-wireless skill**
Use the `adb-wireless` skill to establish a wireless ADB connection to the Android phone.
- [ ] **Step 2: Verify ADB connection**
```bash
adb devices
```
Expected: `<ip>:5555` listed as `device`
---
### Task 11: Install APK on phone
**Files:** N/A (app deployment)
- [ ] **Step 1: Install APK**
```bash
adb install -r .worktrees/esp32picod4/android/app/build/outputs/apk/debug/app-debug.apk
```
Expected: `Success`
- [ ] **Step 2: Launch the app**
```bash
adb shell am start -n com.eddy.atomrelay/.MainActivity
```
---
### Task 12: Flash firmware to Atom Lite via Android app
**Files:** N/A (manual device action)
- [ ] **Step 1: Connect Atom Lite via USB-OTG to the phone**
- [ ] **Step 2: Open the app, tap settings gear → "Firmware Flashen"**
- [ ] **Step 3: If app doesn't auto-detect, unplug/replug the Atom Lite while the dialog is open**
- [ ] **Step 4: Wait for flash to complete (progress bar reaches 100%)**
- [ ] **Step 5: After flash, disconnect USB — the Atom Lite should reboot with green LED blink 3x**
---
### Task 13: Provision HMAC key via app
**Files:** N/A (manual device action)
- [ ] **Step 1: Reconnect Atom Lite via USB-OTG to phone (NOT in download mode — just power on normally)**
- [ ] **Step 2: Open app → Settings → "Sleutel Uitwisselen"**
- [ ] **Step 3: Wait for toast "Beveiligingssleutel gelezen" or provisioning**
- [ ] **Step 4: If key was newly generated, verify Serial monitor shows "HMAC key stored in NVS"**
---
### Task 14: Verify BLE connection and relay control
**Files:** N/A (manual verification)
- [ ] **Step 1: Power on the Atom Lite (with relay and touch sensor connected)**
- [ ] **Step 2: Open the Android app — verify it auto-connects to "SyldaServer"**
- [ ] **Step 3: Verify status shows "Connected"**
- [ ] **Step 4: Hold HOLD button — verify relay activates (click or multimeter)**
- [ ] **Step 5: Release — verify relay deactivates**
- [ ] **Step 6: Touch sensor on G33 — verify relay also activates**
---
## Self-Review
**1. Spec coverage:**
- Sidebranch `esp32picod4`: Task 1 ✓
- Compile for ESP32-PICO-D4: Task 2 ✓
- Pins G32/G33/G27: Task 3 ✓
- SK6812 LED with FastLED: Task 3 ✓
- BLE name "SyldaServer": Task 3 ✓
- CDC-class USB detection: Tasks 5, 6 ✓
- DTR/RTS no changes: Confirmed in research, no task needed ✓
- Bundle binary with Android app: Task 8 ✓
- Build APK: Task 9 ✓
- ADB wireless deploy: Tasks 10, 11 ✓
- Flash + provision + test: Tasks 12-14 ✓
**2. Placeholder scan:** No TBD, TODO, or incomplete sections. All commands are concrete with expected output.
**3. Type consistency:** `hasCdcDataInterface(device: UsbDevice): Boolean` defined in Task 5, used consistently in Task 6 with `UsbUtils.hasCdcDataInterface(device/it)`.

View file

@ -0,0 +1,127 @@
# ESP32-PICO-D4 (M5Stack Atom Lite) Port — Design Spec
> **Goal:** Port the Sylvia Touch Relay project from ESP32-S3-Pico (Atom VoiceS3R) to ESP32-PICO-D4 (Atom Lite), update the Android app for CDC-class USB detection, compile, bundle, and deploy via ADB wireless.
## Current State
The project targets the M5Stack Atom VoiceS3R with ESP32-S3-PICO-1-N8R8 (8MB Flash, 8MB PSRAM). The Android app filters USB devices by Espressif vendor ID (`0x303A`) for key exchange and firmware flashing. The `esp32-flash-lib` handles DTR/RTS via the `SerialTransport` interface implemented by `UsbSerialTransport`.
## Target Hardware
M5Stack Atom Lite with ESP32-PICO-D4:
- 4MB Flash (no PSRAM)
- FTDI FT2232C/D USB-to-UART bridge (VID `0x0403`) — appears as `/dev/ttyUSB0`
- SK6812 addressable RGB LED on GPIO27
- Relay on GPIO32 (G32)
- Touch sensor on GPIO33 (G33) — open-drain type, needs pullup
## Design Decisions
### 1. Side Branch & Git Worktree
Create branch `esp32picod4` via git worktree at `.worktrees/esp32picod4` to isolate the port from the main S3 variant.
### 2. Firmware (`platformio.ini` + `src/main.cpp`)
**New PlatformIO environment `m5stack-atom`:**
| Setting | Old (S3) | New (PICO-D4) | Reason |
|---------|----------|---------------|--------|
| `board` | `esp32-s3-devkitc-1` | `m5stack-atom` | PlatformIO board ID for M5Stack Atom Lite |
| `board_build.arduino.memory_type` | `qio_opi` | removed | Not needed for PICO-D4 |
| `-DESP32S3` | present | `-DESP32` | Correct chip family |
| `-DBOARD_HAS_PSRAM` | present | removed | Atom Lite has no PSRAM |
| `-mfix-esp32-psram-cache-issue` | present | removed | Only needed with PSRAM |
| `-DARDUINO_USB_CDC_ON_BOOT=1` | present | removed | No native USB on PICO-D4 |
| `-DARDUINO_USB_MODE=1` | present | removed | No native USB |
| `upload_port` | `/dev/ttyACM0` | `/dev/ttyUSB0` | FTDI serial device |
| `lib_deps` | (empty) | `fastled/FastLED@^3.7` | SK6812 Neopixel library |
**Pin definitions:**
| Constant | Old | New | Notes |
|----------|-----|-----|-------|
| `SENSOR_PIN` | 38 | 33 | G33, open-drain, `INPUT_PULLUP` unchanged |
| `RELAY_PIN` | 1 | 32 | G32 |
| `LED_PIN` | 27 | 27 | SK6812 Neopixel — replaces `digitalWrite` with FastLED API |
**BLE device name:** `"SyldaServer"` (was `"AtomS3R-Relay"`)
**Serial banner:** `"Atom Lite BLE Relay"` (was `"Atom VoiceS3R BLE Relay"`)
**LED code change:** Replace `digitalWrite(LED_PIN, HIGH/LOW)` with FastLED:
- Include `FastLED.h`
- Define `#define NUM_LEDS 1`
- `CRGB leds[NUM_LEDS]`
- `FastLED.addLeds<SK6812, LED_PIN, GRB>(leds, NUM_LEDS)` in setup
- Startup blink: 3x green (`leds[0] = CRGB::Green; FastLED.show()`)
No other firmware logic changes — HMAC key exchange, BLE relay control, touch sensor logic remain identical.
### 3. Android USB Detection
**Problem:** The Atom Lite's FTDI bridge presents VID `0x0403`, not Espressif's `0x303A`. The app currently filters on VID and won't detect the device.
**Solution:** Replace VID (`0x303A`) filtering with CDC-ACM class filtering (interface class `0x0A`).
**Changes in `UsbUtils.kt`:**
- Add `hasCdcDataInterface(device: UsbDevice): Boolean` — iterates interfaces, returns true if any has `interfaceClass == 0x0A`
**Changes in `SettingsActivity.kt`:**
- Remove `ESP_VENDOR_ID` constant
- Replace all `device?.vendorId == ESP_VENDOR_ID` checks with `UsbUtils.hasCdcDataInterface(device)`
This detects all CDC-ACM serial devices including:
- FTDI FT2232C/D (Atom Lite)
- CP210x (some Atom Lite revisions)
- ESP32-S3 native USB (current hardware)
- CH340/CH9102 (other Atom variants)
### 4. DTR/RTS — No Changes Needed
**Research findings:**
The `esp32-flash-lib`'s `EspFlasherProtocol.enterBootLoader()` implements the standard DTR/RTS download-mode sequence:
```
setControlLines(true, false) // DTR=High → EN released, RTS=Low → GPIO0=Low (download mode)
delayMS(100)
setControlLines(false, true) // DTR=Low → reset pulse via capacitor, RTS=High → GPIO0=High
delayMS(100)
setControlLines(true, false) // DTR=High → release reset, RTS=Low → GPIO0=Low → boot in download mode
```
The `UsbSerialTransport.setControlLines()` implementation sends `CDC_SET_CONTROL_LINE_STATE` control transfers with correct DTR/RTS bit flags. This works for FTDI, CP2104, and native USB CDC-ACM.
The `SettingsActivity.setupCdcControl()` sets DTR|RTS both HIGH for normal serial operation (key exchange), which is correct for all bridge types.
**Verdict: No changes to `EspFlasher.kt`, `UsbSerialTransport.kt`, or key exchange logic.**
### 5. Build, Bundle & Deploy
1. `pio run -e m5stack-atom` to compile firmware
2. `tools/copy_firmware.sh` to copy binaries to `android/app/src/main/assets/firmware/` (environment dir is now `m5stack-atom`)
3. `./gradlew assembleDebug` in `android/` to build APK
4. ADB wireless to connect phone (`adb-wireless` skill)
5. `adb install -r app-debug.apk` to deploy
## Files Changed
| File | Change |
|------|--------|
| `platformio.ini` | New environment `m5stack-atom` replacing S3 config |
| `src/main.cpp` | New pin definitions, BLE name, FastLED LED code |
| `android/.../UsbUtils.kt` | Add `hasCdcDataInterface()` |
| `android/.../SettingsActivity.kt` | VID filter → CDC class filter |
| `tools/copy_firmware.sh` | Environment name `m5stack-atoms3r` → `m5stack-atom` |
## Files Not Changed
| File | Reason |
|------|--------|
| `EspFlasher.kt` | DTR/RTS handled by library |
| `UsbSerialTransport.kt` | Correct implementation |
| `MainActivity.kt` | No BLE changes beyond device name (auto-discovered) |
| `PrefsHelper.kt` | No changes |
| `AndroidManifest.xml` | No changes |
| `build.gradle` | No dependency changes |