# Developing follow-me-stairs This document covers how the repository is organized, the tools for the setup wizard, and facts the firmware and wizard depend on. For installation and settings, see the [README](../README.md). ## Repository layout | Path | Contents | |---|---| | `example/apollo-mtr-1.yaml` | Complete device configuration: Apollo's MTR-1 configuration, pinned to a release in Apollo's repository, plus the follow-me package | | `firmware/follow-me.yaml` | The ESPHome package: tracking, the window, effects, night light, WLED pause, and the setup button on the sensor's web page. Its header comment documents the behaviour in detail. | | `firmware/follow-me.h` | WLED connection: a background task for address lookup, LED count, strip type and WLED on/off, and the DDP sender | | `firmware/follow-me-calibration.h` | The stored setup, the stair geometry built from it, and the sensor's `/followme` web addresses | | `firmware/follow-me-wizard.h` | Generated by `wizard/tools/embed.mjs`. The wizard page with its fonts, gzipped. Do not edit it by hand. | | `firmware/follow-me-button.js` | Adds the "Set up Follow-Me" button to the sensor's web page, through `web_server` `js_include` | | `firmware/follow-me-effects.h` | The per-LED effect patterns. It compiles on a desktop for previews. | | `wled/README.md` | The WLED settings that follow-me needs | | `wizard/wizard.html` | The setup wizard, as one page | | `wizard/fonts/` | IBM Plex Sans and Mono, Latin subset, SIL OFL 1.1 | | `wizard/tools/embed.mjs` | Builds `firmware/follow-me-wizard.h` from the wizard and its fonts | | `wizard/tools/serve.mjs` | Serves the wizard from a computer on the local network | | `wizard/tools/drive.mjs` | Runs the wizard in headless Chrome from a list of steps, and saves screenshots | | `wizard/tools/walk-*.json` | Step lists for `drive.mjs`: one complete setup with the simulated walker per stair shape | ## Changing the wizard After a change to `wizard/wizard.html` or `wizard/fonts/`, rebuild the embedded page, then build and install the firmware again: ```sh node wizard/tools/embed.mjs ``` To serve the wizard from a computer, run this from the repository root: ```sh node wizard/tools/serve.mjs 8080 ``` Then open `http://:8080/` on a phone, and enter the sensor's address in the bar at the top. To use the simulated walker instead of the radar, add `?sim=1` to the address. To run a complete setup without a phone, run this while `serve.mjs` is running: ```sh node wizard/tools/drive.mjs "http://127.0.0.1:8080/?sim=1" 1280 820 wizard/tools/walk-l.json ``` `drive.mjs` saves the screenshots named in the step list to the current folder, and prints "no page errors" when the page raised no errors. It uses Google Chrome at its macOS path. To use another Chrome, set `CHROME` to its path. ## Walk grading The Walk screen grades each stretch of the walk: each flight, and the landing. A stretch fails when one of these is true: | Check | Fails when | |---|---| | Coverage | The radar has no reading for 3 steps or more | | Drift | More than 25% of the stretch's readings are outside the stairs, farther than half the stair width from the walking line | | Step spacing | A flight's average step is less than half or more than twice 260 mm, or more than twice the other flight's | The limits are constants at the top of the walk report section in `wizard/wizard.html`. A setup loaded from the sensor has no radar readings, so only step spacing is checked. "Show raw numbers" shows the walk in the radar's own frame, in mm. ## Firmware facts - Frames go to WLED over DDP, UDP port 4048. Each LED takes 4 bytes on strips with a white LED and 3 bytes on other strips, as WLED reports. A frame is split over as many packets as the strip needs, for strips up to 1500 LEDs. - LED numbers are raw indexes on the WLED controller, the same numbers DDP uses. WLED's segments do not change them. - Where the strip has a gap, for example a jumper across a landing, the firmware finds it from the LED spacing. A window that crosses the gap lights both sides. - The setup is stored in the sensor's flash. A change to the size of the stored setup erases it, and the setup wizard must be run again. ## Web addresses on the sensor | Address | Method | Use | |---|---|---| | `/followme` | GET | The setup wizard | | `/followme/calibration` | GET, POST | The stored setup | | `/followme/targets` | GET | The radar's raw targets, for the wizard's live view | | `/followme/preview` | POST | Lights one LED, for the Match screen | These addresses have no authentication. Any device on the network can use them. ## LD2450 facts - The LD2450 reports target x mirrored. The stored setup keeps the radar's own frame. Code that draws radar readings or decides left and right must negate x. - The LD2450 sees about 60° to each side and about 6 m out. The wizard warns when part of the stairs is outside that area. ## Browser installer | Path | Contents | |---|---| | `installer/apollo-mtr-1.factory.yaml` | The installer firmware: `example/apollo-mtr-1.yaml` without Wi-Fi credentials, with Improv over USB serial and the access point | | `installer/index.html` | The installer page. `__VERSION__` is replaced with the release version. | | `.github/workflows/installer.yml` | Builds the firmware with ESPHome and publishes the page, the firmware and its manifest to GitHub Pages | The workflow runs on the GitHub mirror when a tag that starts with `v` arrives, for example `v2026.10.0`. The tag without the `v` becomes the firmware's project version. The site holds one firmware: the latest build. The installer firmware leaves out Improv over Bluetooth. With it, flash use goes from 69% to 91%.