docker.md (3931B)
1 # Docker: reproducible build environment 2 3 Spin up the firmware build toolchain on any machine without installing 4 PlatformIO, the pioarduino platform, or the xtensa toolchain by hand. The 5 [`Dockerfile`](../Dockerfile) at the repo root bakes all of that in, pinned, so 6 a build on your laptop and a build in CI produce the same artifacts. 7 8 > **Scope:** this containerizes **building**. It does **not** containerize 9 > flashing or provisioning — those touch host hardware (USB serial, Bluetooth) 10 > that Docker Desktop can't reach on macOS/Windows. See *Flashing* below. 11 12 ## What's pinned 13 14 | Layer | Pin | Where | 15 |---|---|---| 16 | PlatformIO Core | `6.1.19` | `ARG PLATFORMIO_VERSION` in the Dockerfile (matches the dev machine) | 17 | Arduino platform | pioarduino `55.03.38` (core 3.x / IDF 5.x) | `[core3x]` in `firmware/platformio.ini` | 18 | Base image | `python:3.13-slim` | Dockerfile | 19 | Libs | NimBLE-Arduino `^2.1.0`, U8g2 `^2.35.30` | `firmware/platformio.ini` | 20 21 The image build **self-verifies**: it compiles `esp32dev_v3` + `oled_v3` as its 22 final step, so `docker build` failing means the firmware doesn't compile. 23 24 ## Build the image 25 26 ```sh 27 # from the repo root 28 docker build -t badge-fw . 29 ``` 30 31 First build pulls the base image + pioarduino platform + xtensa toolchain (a few 32 hundred MB, one time); they're cached in the image afterwards, so later container 33 builds are fast and need no network. 34 35 ## Build firmware 36 37 Two modes: 38 39 **A) Baked-in source** (self-contained — good for CI / a clean checkout): 40 ```sh 41 docker run --rm badge-fw pio run -e oled_v3 # the badge build (default env) 42 docker run --rm badge-fw pio run -e esp32dev_v3 # serial dev build (deprecated) 43 ``` 44 45 **B) Live working tree** (iterate on the host, build in the container): 46 ```sh 47 docker run --rm -v "$PWD/firmware:/project" badge-fw pio run -e oled_v3 48 ``` 49 The mount shadows the baked-in source with your edits; the toolchain cache 50 (`/opt/pio`) is separate, so builds still run offline. Build artifacts land in 51 `firmware/.pio/build/<env>/` on the host (already git-ignored). 52 53 > On Linux, a bind-mounted build writes `.pio` as root. Add `--user "$(id -u):$(id -g)"` 54 > if you want host-owned artifacts. 55 56 ## Get the binary out (baked-in mode) 57 58 ```sh 59 id=$(docker create badge-fw) 60 docker cp "$id:/project/.pio/build/oled_v3/firmware.bin" ./firmware.bin 61 docker rm "$id" 62 ``` 63 (Mode B writes it straight to `firmware/.pio/build/...` on the host — no copy needed.) 64 65 ## Flashing 66 67 Flashing needs a USB serial port, which **Docker Desktop on macOS/Windows cannot 68 pass into a container**. So: 69 70 - **macOS / Windows:** build in the container, **flash from the host** with your 71 local PlatformIO (`cd firmware && pio run -e oled_v3 -t upload`), or flash the 72 extracted `firmware.bin` with esptool. (Host serial notes live in the 73 `esptool-serial-access` memory.) 74 - **Linux host:** you *can* flash from the container by passing the device: 75 ```sh 76 docker run --rm --device=/dev/ttyUSB0 -v "$PWD/firmware:/project" \ 77 badge-fw pio run -e oled_v3 -t upload --upload-port /dev/ttyUSB0 78 ``` 79 (`/dev/ttyACM0` for native-USB boards.) 80 81 ## Provisioning 82 83 The Web-Bluetooth provisioning page (`provisioning/index.html`) is a **host + 84 browser** task — BLE doesn't cross the container boundary, and it needs 85 Chrome/Edge with Web Bluetooth. Serve it on the host: 86 `cd provisioning && python3 -m http.server 8000`. 87 88 ## Maintaining 89 90 - **Bump PlatformIO Core:** change `ARG PLATFORMIO_VERSION` and rebuild. Keep it 91 matched to the dev machine's `pio --version`. 92 - **Bump the Arduino platform:** edit the pioarduino tag in 93 `firmware/platformio.ini` (`[core3x]`) — the Dockerfile picks it up, no Docker 94 edit needed. 95 - **A new env that pulls new libs:** the warm layer installs deps for 96 `esp32dev_v3` + `oled_v3`; if you add an env you want pre-warmed, add it to the 97 `pio pkg install` line. Other envs still build, they just fetch their platform 98 on first use.