{"id":51172306,"url":"https://github.com/flavio-fernandes/esp-codex-platform","last_synced_at":"2026-06-27T01:30:38.557Z","repository":{"id":364596903,"uuid":"1245045506","full_name":"flavio-fernandes/esp-codex-platform","owner":"flavio-fernandes","description":"Reusable ESPHome devcontainer and reset-aware embedded workbench starter for safe ESP32 firmware bring-up.","archived":false,"fork":false,"pushed_at":"2026-06-22T04:13:01.000Z","size":183,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-22T05:21:42.854Z","etag":null,"topics":["devcontainer","embedded-workbench","esp-idf","esp32","esphome","esptool","firmware","iot","platformio","rfc2217"],"latest_commit_sha":null,"homepage":"https://flaviof.com","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flavio-fernandes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-20T21:20:24.000Z","updated_at":"2026-06-22T04:13:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/flavio-fernandes/esp-codex-platform","commit_stats":null,"previous_names":["flavio-fernandes/esp-codex-platform"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/flavio-fernandes/esp-codex-platform","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavio-fernandes%2Fesp-codex-platform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavio-fernandes%2Fesp-codex-platform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavio-fernandes%2Fesp-codex-platform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavio-fernandes%2Fesp-codex-platform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flavio-fernandes","download_url":"https://codeload.github.com/flavio-fernandes/esp-codex-platform/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flavio-fernandes%2Fesp-codex-platform/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34839004,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["devcontainer","embedded-workbench","esp-idf","esp32","esphome","esptool","firmware","iot","platformio","rfc2217"],"created_at":"2026-06-27T01:30:37.816Z","updated_at":"2026-06-27T01:30:38.544Z","avatar_url":"https://github.com/flavio-fernandes.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ESP Codex Platform\n\nA small, safety-first starter repo for ESPHome projects that are developed from\na workstation through a Linux dev host and an ESP workbench.\n\nIt is meant to give each new project the boring pieces up front: a repeatable\ndevcontainer, reset-aware flashing wrappers, serial-monitor guardrails, generic\nESPHome smoke examples, and docs that make the workflow easy to hand off.\n\n```text\nMac/workstation -\u003e VS Code SSH -\u003e Linux host -\u003e Docker/devcontainer -\u003e ESP workbench -\u003e ESP board\n```\n\n## What You Get\n\n- ESPHome devcontainer based on the stable ESPHome image.\n- Project-local workbench wrappers in `tools/`.\n- USB-aware workbench status through `tools/espwb-status`.\n- Reset-aware `chip-id`, `flash-id`, `read-flash`, and `write-flash` through\n  `tools/espwb-esptool`.\n- RFC2217 serial monitoring through `tools/espwb-monitor`.\n- Workbench validation through `tools/validate-workbench.sh`.\n- Safe defaults for `SLOT1`, ignored local config, ignored secrets, ignored\n  build output, and ignored local artifacts.\n- Tiny generic ESPHome blink and heartbeat examples.\n- Docs templates for current state, roadmap, GitHub setup, references, public\n  hygiene, and workbench commands.\n\n## What This Is Not\n\nThis is not a generator, package manager, or hardware abstraction layer. It is a\nplain repo you can copy, fork, or use as a starting point.\n\nThis repo intentionally does not include board pinouts, private network values,\nHome Assistant entity IDs, device photos, firmware backups, generated binaries,\nor real secrets. Those belong in the downstream device project, and private\nvalues should stay in ignored local files.\n\n## Prerequisites\n\nInstall these on the Linux host before using the quick start:\n\n- Docker Engine, with your user able to run `docker ps` without `sudo`.\n- Dev Containers CLI, available as `devcontainer` on `PATH`. VS Code with the\n  Dev Containers extension can also build/open the container, but the examples\n  below use the CLI.\n- Git, Bash, and an editor.\n- SSH access from the Linux host or devcontainer to the ESP workbench.\n- Optional: `v4l2-ctl` from `v4l-utils` when using the local camera helpers.\n\nThis repo uses a Dev Container: a Docker-based development environment defined\nin `.devcontainer/` so ESPHome, esptool, and supporting CLI tools are consistent\nacross checkouts. Curious readers can learn more at\n[containers.dev](https://containers.dev/).\n\nThis repo's devcontainer supplies ESPHome, esptool, Python serial tooling,\n`curl`, `jq`, `rg`, `shellcheck`, and other project tools inside the container.\nIt does not install Docker, the `devcontainer` CLI, SSH keys, or workbench\nsystem services on the host.\n\nThe ESP workbench must already provide:\n\n- A reachable workbench API at `${WORKBENCH_URL}`.\n- SSH for `${WORKBENCH_USER}@${WORKBENCH_IP}`.\n- The reset-aware helper `/usr/local/bin/espwb-local-esptool`.\n- RFC2217 serial service for monitoring at `${ESP_PORT}`.\n- A board installed in `SLOT1`, unless a downstream project explicitly\n  documents and approves another slot.\n\n## Quick Start\n\nClone the starter into any directory name and enter it:\n\n```bash\ngit clone https://github.com/flavio-fernandes/esp-codex-platform.git my-esp-project\ncd my-esp-project\n```\n\nThe devcontainer uses the local folder basename, so commands work the same\nwhether the checkout is named `my-esp-project`, `esp-codex-playground`, or\nsomething else.\n\nCreate local-only workbench settings:\n\n```bash\ncp config/workbench.env.example config/workbench.env\n$EDITOR config/workbench.env\n```\n\nKeep `config/workbench.env` private. The committed example uses documentation\nplaceholders such as `192.0.2.10`. Values in `config/workbench.env` act as\nlocal defaults; command-specific environment variables such as\n`ESPWB_SLOT=SLOT2` still override them.\n\nBuild or open the devcontainer:\n\n```bash\ndevcontainer up --workspace-folder . --remove-existing-container\ndevcontainer exec --workspace-folder . esphome version\ndevcontainer exec --workspace-folder . tools/validate-workbench.sh\n```\n\nIf `devcontainer` is not found, install the Dev Containers CLI on the Linux\nhost or open the repository through VS Code's Dev Containers workflow. If\n`docker ps` requires `sudo`, fix the host Docker setup before continuing.\n\nThe devcontainer creates its own `vscode` user and sets\n`updateRemoteUserUID: false` in `.devcontainer/devcontainer.json`. Keep that\nsetting unless the Dockerfile user model changes; it avoids Dev Containers'\nextra UID-rewrite image and the BuildKit warning that rewrite can produce.\n\nIdentify the board before changing or flashing examples:\n\n```bash\ndevcontainer exec --workspace-folder . tools/espwb-esptool flash-id\n```\n\nRecord the detected chip family and flash size. They must match the ESPHome\n`board` value you use later. The probe cannot discover the visible LED pin, so\nget that pin from the board silkscreen, vendor docs, or the downstream\nproject's hardware notes.\n\nCheck the blink example before building it. The committed defaults are a\nplaceholder `featheresp32` board with `4MB` flash and `GPIO13` as the LED pin.\nIn a fork, edit the `board`, `flash_size`, and `status_led_pin` substitutions in\n`examples/generic-blink/generic-blink.yaml` so they match the board installed\nin your workbench slot.\n\nValidate a tiny ESPHome example:\n\n```bash\ndevcontainer exec --workspace-folder . esphome config examples/generic-blink/generic-blink.yaml\ndevcontainer exec --workspace-folder . esphome compile examples/generic-blink/generic-blink.yaml\n```\n\nThe first compile can take several minutes while PlatformIO downloads toolchains\ninto the devcontainer cache. Later compiles are much faster.\n\nCheck the board identity again immediately before flashing:\n\n```bash\ndevcontainer exec --workspace-folder . tools/espwb-esptool flash-id\n```\n\nConfirm the detected chip family and flash size still match the `board` and\n`flash_size` values you put in the blink YAML. Stop here if they do not match.\n\nFlash only after a successful compile of that same YAML:\n\n```bash\ndevcontainer exec --workspace-folder . tools/espwb-esptool write-flash 0x0 examples/generic-blink/.esphome/build/generic-blink/.pioenvs/generic-blink/firmware.factory.bin\n```\n\n## Workbench Tools\n\nStart with status when the workbench state is unclear:\n\n```bash\ndevcontainer exec --workspace-folder . tools/espwb-status\n```\n\nThe status helper checks host, SSH, API, and serial-socket reachability, then\nprints the selected slot state and USB identities reported by the workbench API.\nTreat `serial: reachable` as a portal-socket check only; it does not prove that\nthe application firmware is awake or responding. Native USB boards can expose\ndifferent identities for application firmware, ROM bootloader, and deep sleep.\n\n`tools/espwb-esptool` SSHs to the workbench and calls the reset-aware helper\nthere. Use it for esptool operations and flashing:\n\n```bash\ndevcontainer exec --workspace-folder . tools/espwb-esptool flash-id\ndevcontainer exec --workspace-folder . tools/espwb-esptool chip-id\ndevcontainer exec --workspace-folder . tools/espwb-esptool read-flash 0x0 0x1000 artifacts/readback.bin\ndevcontainer exec --workspace-folder . tools/espwb-esptool write-flash 0x0 path/to/firmware.factory.bin\n```\n\nAfter each operation, the wrapper asks the workbench API to recover/release the\nslot after the RFC2217 portal has restarted. It accepts the API's `running`\nstatus when available, and falls back to checking the slot's RFC2217 TCP port\nwhen the API state is stale but the portal is reachable. This extra step\nprotects ESP32-S3 USB-Serial/JTAG boards from getting wedged when the portal\nreopens the serial device. Set `ESPWB_POST_OPERATION_RECOVER=0` only when\ndebugging that recovery path.\n\nA healthy recovery usually ends with one of these messages:\n\n```text\n== workbench reports SLOT1 recovered and portal running ==\n== workbench reports SLOT1 recovered; RFC2217 TCP port is reachable ==\n```\n\nIf recovery still times out, the wrapper prints the last slot status it saw,\nincluding values such as `present`, `running`, `state`, `last_error`, and any\nTCP connection error.\n\nWhen OpenOCD is available for the slot, the wrapper also checks that the chip\ndid not stay in ESP32-S3 ROM/download code after recovery. If it reports an\nerror like `still appears to be in ESP32-S3 ROM/download code`, the flash may\nhave verified successfully but the application is not running. Release BOOT and\nreset the board, or fix the workbench BOOT/EN fixture wiring/state so unattended\nrecovery can do the same. Set `ESPWB_VERIFY_APP_BOOT=0` only while debugging\nthat verification path.\n\nIf a manual press of the board RESET button makes the freshly flashed app start,\nthe firmware image is valid. Treat that as evidence that the remaining problem\nis the automated post-flash release/reset path, not the ESPHome YAML. On\nESP32-S3 USB-Serial/JTAG boards this often means the board was left in\n`DOWNLOAD(USB/UART0)` and needs a plain reset with BOOT released.\n\nIf `flash-id` fails with a pySerial write timeout and the workbench API reports\nthe board in application USB identity instead of Espressif ROM/download mode,\nthe board has not entered the ROM bootloader. For boards like the\nUnexpectedMaker FeatherS3, the manual recovery sequence is BOOT held while\nRESET is pressed and released; unattended recovery needs equivalent BOOT/RESET\nwiring in the workbench fixture.\n\n`tools/espwb-monitor` opens raw DUT serial logs through RFC2217:\n\n```bash\ndevcontainer exec --workspace-folder . tools/espwb-monitor\n```\n\nBy default it runs `tools/espwb-esptool flash-id` when the monitor exits. This\ngives the reset-aware helper a chance to recover targets that are perturbed by\nclosing an RFC2217 session. Set `ESPWB_MONITOR_RECOVER=0` only when you are\nintentionally debugging monitor close behavior, and only together with\n`ESPWB_MONITOR_ALLOW_UNRECOVERED_EXIT=1`. If a board is blank or stuck after a\nmonitor session, recover it with:\n\n```bash\ndevcontainer exec --workspace-folder . tools/espwb-esptool flash-id\n```\n\nDo not open the workbench `/dev/ttyACM*` device directly with ad hoc serial\ntools for routine monitoring. On ESP32-S3 USB-Serial/JTAG boards, plain serial\nopens can toggle control lines and leave the board in ROM download mode or a\nvisually wedged state. Use `tools/espwb-monitor` and let its post-monitor\nrecovery run.\n\n`tools/workbench-camera-capture` captures one JPEG from a local V4L2 camera on\nthe Linux host, and `tools/workbench-camera-sequence` captures a timed sequence:\n\n```bash\ntools/workbench-camera-capture\ntools/workbench-camera-sequence 4 3\n```\n\nBy default it uses the current workbench camera's stable `/dev/v4l/by-id/...`\npath. Override `WORKBENCH_CAMERA_DEVICE` in `config/workbench.env` when a\ndifferent local camera is attached.\n\n## Safety Rules\n\n- Keep `SLOT1` as the safe default unless a downstream project explicitly\n  approves another slot.\n- Use `tools/espwb-esptool` for flashing and esptool operations.\n- Use RFC2217 only for serial monitoring through `tools/espwb-monitor`.\n- Do not use RFC2217 reset control for flashing.\n- Only flash a `firmware.factory.bin` immediately after compiling the matching\n  YAML; ignored `.esphome/` build trees can contain stale binaries.\n- Keep `config/workbench.env`, `secrets.yaml`, `.env` files, private keys,\n  tokens, generated firmware, `.esphome/`, and `artifacts/` out of git.\n- Run `docs/public-release-checklist.md` before making any repo public.\n\n## Repository Map\n\n- `.devcontainer/` - ESPHome devcontainer definition.\n- `config/workbench.env.example` - safe placeholder workbench settings.\n- `examples/generic-blink/` - tiny GPIO blink smoke test.\n- `examples/feathers3-rgb-blink/` - board-specific FeatherS3 RGB blink smoke\n  test.\n- `examples/generic-heartbeat/` - tiny heartbeat/logging smoke test.\n- `examples/magtag-lvgl-shapes/` - MagTag e-paper LVGL widget example.\n- `tools/espwb-ssh` - project-local SSH wrapper.\n- `tools/espwb-status` - USB-aware workbench and slot status helper.\n- `tools/espwb-esptool` - reset-aware esptool/flashing wrapper.\n- `tools/espwb-monitor` - RFC2217 serial monitor wrapper.\n- `tools/workbench-local-esptool` - reference helper installed on the workbench\n  as `/usr/local/bin/espwb-local-esptool`.\n- `tools/workbench-camera-capture` - optional local V4L2 camera snapshot.\n- `tools/workbench-camera-sequence` - optional timed camera snapshots.\n- `tools/validate-workbench.sh` - local toolchain and workbench validation.\n- `docs/magtag-lvgl-refresh-analysis.md` - root-cause note for MagTag LVGL\n  draw-end events and e-paper refresh behavior.\n- `docs/native-usb-recovery.md` - native USB and direct recovery guide.\n- `docs/workbench-cheatsheet.md` - command reference.\n- `docs/public-release-checklist.md` - public hygiene checks.\n\n## Starting a Device Project\n\nFor a real device repo, keep the first firmware intentionally tiny:\n\n1. Copy this starter or use it as the base repo.\n2. Set local workbench values in ignored `config/workbench.env`.\n3. Validate the devcontainer and workbench path.\n4. Add one minimal board-specific ESPHome YAML.\n5. Run `esphome config` and `esphome compile`.\n6. Confirm board identity with `tools/espwb-esptool flash-id`.\n7. Flash through `tools/espwb-esptool`.\n8. Record the validated facts in `docs/current-state.md`.\n\nAdd display, touch, sensors, Home Assistant, OTA, and UI behavior one step at a\ntime. Keep hardware-specific notes, photos, generated firmware, and private\nvalues in the downstream project, not in this generic starter.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflavio-fernandes%2Fesp-codex-platform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflavio-fernandes%2Fesp-codex-platform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflavio-fernandes%2Fesp-codex-platform/lists"}