Skip to content

Commit d22da2d

Browse files
committed
board-detect: identify the firmware in the beacon, and build for WROOM + C5
Two halves of the same release. Beacon identity. The liveness beacon is now "PING FTRP <ver>" rather than a bare "PING". Detection parses it and matches the magic, instead of treating any received bytes as proof of a board, which let a board flashed with something else pass as ours. The version drives a three-way Start Portal outcome: no magic beacon prompts an install, an older version prompts an update, current proceeds. A handshake watchdog drops back to that prompt if a detected board never reaches broadcasting within ~8s, rather than sitting on "Starting portal..." forever. "Flash Firmware" becomes "Reinstall firmware" and flashes the image bundled in the fap, so there is no SD file picker, and the flasher's done screen now says to tap RESET, which the board genuinely needs because it is still held in the download bootloader. Boards. The sketch would not compile on the 3.x core at all: onStaIp() resolved a station MAC through esp_netif_get_sta_list(), which esp-idf 5 removed. On 3.x the assign event carries the MAC directly, so both paths now sit behind ESP_ARDUINO_VERSION_MAJOR. That unblocks the C5, which only exists in the 3.x line, and CI compiles S2 and WROOM on the pinned 2.0.17 and the C5 on 3.3.11 so the branch cannot rot. Releases attach one merged image per board, flashable at 0x0 with no esptool on PATH (tools/merge-image.py, which the C5 core install would otherwise remove). Async libraries move to the maintained ESP32Async forks, since the me-no-dev ones do not build on 3.x. Fixes #1. Claude-Session: https://claude.ai/code/session_01UraqY8Ld2E3zzGVN636Lw7
1 parent ba34f12 commit d22da2d

18 files changed

Lines changed: 380 additions & 125 deletions

.github/workflows/build.yml

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
path: flipper/flytrap/dist/flytrap.fap
3737

3838
esp32-firmware:
39-
name: Build ESP32-S2 firmware
39+
name: Build ESP32 firmware (S2, WROOM, C5)
4040
runs-on: ubuntu-latest
4141
steps:
4242
- uses: actions/checkout@v4
@@ -45,23 +45,52 @@ jobs:
4545
mkdir -p "$HOME/bin"
4646
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR="$HOME/bin" sh
4747
echo "$HOME/bin" >> "$GITHUB_PATH"
48-
- name: Install esp32 core + async libs
48+
- name: Fetch async libs (maintained ESP32Async forks)
49+
# The unmaintained me-no-dev forks don't build on the 3.x core the C5 needs.
50+
# The ESP32Async forks build on both the pinned 2.0.17 (S2/WROOM) and 3.x (C5).
51+
run: |
52+
mkdir -p esp32/libs
53+
git clone --depth 1 --branch v3.3.2 https://github.com/ESP32Async/AsyncTCP.git esp32/libs/AsyncTCP
54+
git clone --depth 1 --branch v3.6.0 https://github.com/ESP32Async/ESPAsyncWebServer.git esp32/libs/ESPAsyncWebServer
55+
- name: Install esp32 core 2.0.17 (S2/WROOM)
4956
run: |
5057
arduino-cli config init --overwrite
5158
arduino-cli config set board_manager.additional_urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
5259
arduino-cli core update-index
5360
arduino-cli core install esp32:esp32@2.0.17
54-
mkdir -p esp32/libs
55-
git clone --depth 1 https://github.com/me-no-dev/AsyncTCP.git esp32/libs/AsyncTCP
56-
git clone --depth 1 https://github.com/me-no-dev/ESPAsyncWebServer.git esp32/libs/ESPAsyncWebServer
57-
- name: Compile firmware
61+
- name: Compile S2 + WROOM (core 2.0.17)
62+
# These stay pinned to 2.0.17 (different WiFi/USB behaviour on 3.x). The C5
63+
# install below REPLACES this core, so these must build first. The S2 images
64+
# go to build/ (flat) because build-fap.sh and the fap bundle that exact path.
5865
run: |
5966
arduino-cli compile \
6067
--fqbn esp32:esp32:esp32s2:PartitionScheme=huge_app \
6168
--libraries esp32/libs \
6269
--output-dir esp32/flytrap-fw/build \
6370
esp32/flytrap-fw
71+
arduino-cli compile \
72+
--fqbn esp32:esp32:esp32 \
73+
--libraries esp32/libs \
74+
--output-dir esp32/flytrap-fw/build-wroom \
75+
esp32/flytrap-fw
76+
- name: Compile C5 (core 3.3.11)
77+
# The C5 only exists in the 3.x line. Installing it REPLACES 2.0.17, so this
78+
# runs after the S2/WROOM builds. This is the guard that keeps the firmware
79+
# 3.x-clean (see onStaIp's ESP_ARDUINO_VERSION_MAJOR branch). CDCOnBoot stays
80+
# default so Serial is UART0 -- the pins the Flipper talks to.
81+
run: |
82+
arduino-cli core install esp32:esp32@3.3.11
83+
arduino-cli compile \
84+
--fqbn esp32:esp32:esp32c5:PartitionScheme=huge_app,CDCOnBoot=default \
85+
--libraries esp32/libs \
86+
--output-dir esp32/flytrap-fw/build-c5 \
87+
esp32/flytrap-fw
6488
- uses: actions/upload-artifact@v4
89+
# Only the S2 images are consumed downstream: the flipper-app job unpacks this
90+
# artifact straight into esp32/flytrap-fw/build/ and build-fap.sh bundles the S2
91+
# images from there. The WROOM/C5 compiles above are 3.x/board build guards --
92+
# release.yml is what ships their images. Keep this S2-only so the artifact root
93+
# stays esp32/flytrap-fw/build (a multi-dir upload would nest it and break the fap).
6594
with:
6695
name: flytrap-firmware
6796
path: esp32/flytrap-fw/build/*.bin

.github/workflows/release.yml

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ jobs:
1717
- uses: actions/checkout@v4
1818

1919
# ESP build runs first, on the runner's system Python (which has pyserial
20-
# for the core's esptool). A setup-python before this would shadow it and
21-
# break esptool with "No module named 'serial'".
22-
- name: Build ESP32-S2 firmware
20+
# for the core's esptool elf2image step). A setup-python before this would
21+
# shadow it and break arduino-cli's image step with "No module named 'serial'".
22+
# tools/merge-image.py is stdlib-only, so the merges below are unaffected.
23+
- name: Build ESP32 firmware (S2, WROOM, C5)
2324
run: |
2425
mkdir -p "$HOME/bin"
2526
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR="$HOME/bin" sh
@@ -28,14 +29,53 @@ jobs:
2829
arduino-cli config set board_manager.additional_urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
2930
arduino-cli core update-index
3031
arduino-cli core install esp32:esp32@2.0.17
32+
# Maintained ESP32Async forks build on both the pinned 2.0.17 (S2/WROOM)
33+
# and the 3.x core the C5 needs; the me-no-dev forks don't build on 3.x.
3134
mkdir -p esp32/libs
32-
git clone --depth 1 https://github.com/me-no-dev/AsyncTCP.git esp32/libs/AsyncTCP
33-
git clone --depth 1 https://github.com/me-no-dev/ESPAsyncWebServer.git esp32/libs/ESPAsyncWebServer
35+
git clone --depth 1 --branch v3.3.2 https://github.com/ESP32Async/AsyncTCP.git esp32/libs/AsyncTCP
36+
git clone --depth 1 --branch v3.6.0 https://github.com/ESP32Async/ESPAsyncWebServer.git esp32/libs/ESPAsyncWebServer
37+
38+
# S2 (core 2.0.17): the fap-bundled board. Build into build/ (flat) so the
39+
# bundle step below and build-fap.sh find it, then merge into one 0x0 image.
3440
arduino-cli compile \
3541
--fqbn esp32:esp32:esp32s2:PartitionScheme=huge_app \
3642
--libraries esp32/libs \
3743
--output-dir esp32/flytrap-fw/build \
3844
esp32/flytrap-fw
45+
BOOT_APP0="$HOME/.arduino15/packages/esp32/hardware/esp32/2.0.17/tools/partitions/boot_app0.bin"
46+
python3 tools/merge-image.py esp32/flytrap-fw/build/flytrap-s2-merged.bin \
47+
0x1000 esp32/flytrap-fw/build/flytrap-fw.ino.bootloader.bin \
48+
0x8000 esp32/flytrap-fw/build/flytrap-fw.ino.partitions.bin \
49+
0xe000 "$BOOT_APP0" \
50+
0x10000 esp32/flytrap-fw/build/flytrap-fw.ino.bin
51+
52+
# WROOM (core 2.0.17, plain esp32 FQBN), merged the same way.
53+
arduino-cli compile \
54+
--fqbn esp32:esp32:esp32 \
55+
--libraries esp32/libs \
56+
--output-dir esp32/flytrap-fw/build-wroom \
57+
esp32/flytrap-fw
58+
python3 tools/merge-image.py esp32/flytrap-fw/build-wroom/flytrap-wroom-merged.bin \
59+
0x1000 esp32/flytrap-fw/build-wroom/flytrap-fw.ino.bootloader.bin \
60+
0x8000 esp32/flytrap-fw/build-wroom/flytrap-fw.ino.partitions.bin \
61+
0xe000 "$BOOT_APP0" \
62+
0x10000 esp32/flytrap-fw/build-wroom/flytrap-fw.ino.bin
63+
64+
# C5 (core 3.3.11): the chip does not exist in 2.0.17. Installing the 3.x
65+
# core REPLACES 2.0.17 (and its esptool), so this runs last. NOTE the C5
66+
# bootloader offset is 0x2000, not the 0x1000 the other boards use.
67+
arduino-cli core install esp32:esp32@3.3.11
68+
C5_BOOT_APP0="$HOME/.arduino15/packages/esp32/hardware/esp32/3.3.11/tools/partitions/boot_app0.bin"
69+
arduino-cli compile \
70+
--fqbn esp32:esp32:esp32c5:PartitionScheme=huge_app,CDCOnBoot=default \
71+
--libraries esp32/libs \
72+
--output-dir esp32/flytrap-fw/build-c5 \
73+
esp32/flytrap-fw
74+
python3 tools/merge-image.py esp32/flytrap-fw/build-c5/flytrap-c5-merged.bin \
75+
0x2000 esp32/flytrap-fw/build-c5/flytrap-fw.ino.bootloader.bin \
76+
0x8000 esp32/flytrap-fw/build-c5/flytrap-fw.ino.partitions.bin \
77+
0xe000 "$C5_BOOT_APP0" \
78+
0x10000 esp32/flytrap-fw/build-c5/flytrap-fw.ino.bin
3979
4080
- uses: actions/setup-python@v5
4181
with:
@@ -64,14 +104,19 @@ jobs:
64104
TAG: ${{ github.ref_name }}
65105
REPO: ${{ github.repository }}
66106
run: |
67-
# Two artifacts: the fap (one-step install; bundles portal + firmware)
68-
# and the firmware bundle zip (all images + boot_app0 + flash.txt
69-
# manifest) for computer/esptool flashing or manual SD flasher setup.
70-
# The loose .bin images are redundant with the zip (and incomplete —
71-
# they omit boot_app0), so they're no longer attached.
107+
# Attachments:
108+
# - the fap (one-step install; bundles the portal + the S2 firmware)
109+
# - the S2 firmware bundle zip (images + boot_app0 + flash.txt manifest)
110+
# for the on-device flasher / manual SD setup
111+
# - one merged .bin per board (S2/WROOM/C5), each flashable at 0x0 with
112+
# esptool from a computer: what WROOM and C5 owners use, and what
113+
# issue #1 asked for.
72114
gh release create "$TAG" \
73115
--repo "$REPO" \
74116
--title "Flytrap $TAG" \
75117
--generate-notes \
76118
flipper/flytrap/dist/flytrap.fap \
77-
flytrap-firmware-bundle.zip
119+
flytrap-firmware-bundle.zip \
120+
esp32/flytrap-fw/build/flytrap-s2-merged.bin \
121+
esp32/flytrap-fw/build-wroom/flytrap-wroom-merged.bin \
122+
esp32/flytrap-fw/build-c5/flytrap-c5-merged.bin

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ build/
1313
*.o
1414
*.a
1515
esp32/**/build/
16+
# per-board release build dirs (build-wroom, build-c5)
17+
esp32/**/build-*/
1618
# ...but the firmware-bundle boot_app0 is a shipped asset, not a build artifact
1719
!esp32/flytrap-fw/boot_app0.bin
1820

CHANGELOG.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,51 @@
22

33
All notable changes to Flytrap are documented here.
44

5+
## [0.6.0] — 2026-09-11
6+
7+
Board detection now keys off a firmware-identifying beacon, and the flasher UI is
8+
simplified around the embedded firmware.
9+
10+
### Protocol
11+
- The liveness beacon is now **`PING FTRP <ver>`** (was a bare `PING`). The `FTRP`
12+
magic identifies *Flytrap* firmware so the app won't adopt a board flashed with
13+
something else, and `<ver>` is the wire-protocol version. Detection now **parses**
14+
the beacon (magic-matched) instead of treating "any bytes received" as a board —
15+
the latter let foreign firmware slip through. **Requires reflashing the ESP**
16+
(Start Portal will prompt for it automatically).
17+
18+
### Flipper app
19+
- **Version-aware install/update.** Start Portal has three outcomes: no magic beacon
20+
*"Firmware needed"* (install); magic but an older `<ver>`*"Update firmware?"*;
21+
current → it proceeds. The prompt is phrased around the **firmware**, not the
22+
board's presence (an off/absent/foreign board are indistinguishable).
23+
- **Handshake watchdog.** A start that detects the board but never reaches
24+
broadcasting within ~8 s drops back to the install prompt instead of hanging on
25+
"Starting portal…".
26+
- **"Reinstall firmware"** replaces the old **Flash Firmware** menu item — it flashes
27+
the firmware bundled in the fap directly (no SD file picker, so no stale-folder
28+
clutter). Start Portal's auto-install/update uses the same bundled image.
29+
- `deploy-to-flipper.py` no longer pushes a firmware bundle to the SD (it rides
30+
inside the fap and extracts to `apps_assets`).
31+
- **Flasher tells you to reset.** The "Flashed!" screen now says *"Tap RESET on the
32+
board to run it, then Continue"* — the board stays in the download bootloader
33+
after flashing (the app can't drive the S2's reset line), so it needs a manual
34+
RESET to boot the new firmware. (Was mislabeled "Board rebooting…".)
35+
36+
### Boards
37+
- **WROOM and C5 builds** alongside the S2. Releases now attach one merged image per
38+
board (`flytrap-s2-merged.bin`, `flytrap-wroom-merged.bin`, `flytrap-c5-merged.bin`),
39+
each flashable at `0x0` with `esptool` from a computer, so nothing has to be compiled
40+
to get running. The fap still bundles the S2 image alone, so the on-device
41+
Install/Update path stays S2-only.
42+
- The firmware is **3.x-core clean**. `onStaIp()` resolved a station's MAC through
43+
`esp_netif_get_sta_list()`, which esp-idf 5 removed, so the sketch would not compile
44+
on the 3.x core at all. On 3.x the assign event carries the MAC directly, so the two
45+
paths now sit behind an `ESP_ARDUINO_VERSION_MAJOR` check. The C5 needs 3.x (the chip
46+
does not exist in 2.0.17); S2 and WROOM stay pinned to 2.0.17. Fixes #1.
47+
- Async libraries moved to the maintained **ESP32Async** forks (AsyncTCP v3.3.2,
48+
ESPAsyncWebServer v3.6.0). The unmaintained me-no-dev forks do not build on 3.x.
49+
550
## [0.5.0] — 2026-07-17
651

752
Flash the ESP firmware from the Flipper — no computer.

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ If that's not your use case, this isn't the project for you.
4646
everything also logged to `capture_<N>.txt` on the SD card.
4747
- **Live clients** list → detail (MAC, IP, joined time). Joins and leaves update the
4848
count in real time, so a device that disconnects drops off instead of lingering.
49-
- **Flash the ESP from the Flipper** — no computer. **Flash Firmware** picks a
50-
firmware bundle off the SD, auto-detects the board in download mode, and writes it
51-
over the GPIO UART (vendored [esp-serial-flasher](https://github.com/espressif/esp-serial-flasher)).
49+
- **Flash the ESP from the Flipper** — no computer. The firmware is bundled in the
50+
fap; **Start Portal** auto-detects the board and offers to **Install** (or
51+
**Update**, when it's behind) and continues once flashed, and a **Reinstall
52+
firmware** menu item reflashes on demand. It auto-detects the board in download
53+
mode and writes over the GPIO UART (vendored [esp-serial-flasher](https://github.com/espressif/esp-serial-flasher)).
5254
- **Capture alerts** (haptic / beep / LED) with a **Settings** screen to toggle them.
5355
- A **Console** view (from the menu during a session) showing the raw serial protocol live.
5456
- Lightweight enough to run reliably on the SD-less ESP32-S2 dev board.
@@ -59,6 +61,10 @@ If that's not your use case, this isn't the project for you.
5961
`ufbt` SDK).
6062
- **Official Flipper WiFi Dev Board (ESP32-S2)** — or any generic ESP32-S2. It mounts on the
6163
Flipper's GPIO header, which wires the two together over UART.
64+
- **ESP32-WROOM and ESP32-C5** also run the firmware; releases attach a ready-made image
65+
for each. Only the S2 image is bundled in the fap, so those two are flashed once from a
66+
computer (see [tools/README.md](tools/README.md)), after which the Flipper drives them
67+
the same way.
6268

6369
## Install
6470

docs/PROTOCOL.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ All line-oriented. The Flipper parser matches on the leading token.
3737
| `BYE mac=<AA:BB:...>` | A station left the AP — the Flipper drops it from the live client list. |
3838
| `IP mac=<AA:BB:...> ip=<ip>` | DHCP assigned a station its IP (MAC resolved from the soft-AP table). Falls back to `IP ip=<ip>` when the MAC can't be resolved; the Flipper then pairs it to the most recent client without an IP. |
3939
| `CRED ip=<ip>&<field>=<val>&...` | A form was submitted — the client IP plus every submitted field, url-encoded. One line per submission. |
40-
| `PING` | Liveness beacon, emitted ~every 2s. The Flipper uses it to detect an unplugged board (no `PING`/traffic for 5s ⇒ link lost); it's dropped from the console so it doesn't spam. |
40+
| `PING FTRP <ver>` | Liveness + identity beacon, emitted ~every 2s. The magic `FTRP` marks the board as running Flytrap firmware (detection keys off *this*, not "any bytes", so a board flashed with something else isn't adopted), and `<ver>` is the wire-protocol version — the Flipper prompts an update when it's behind `FLYTRAP_FW_VERSION`. Also drives unplug detection (no beacon/traffic for 5s ⇒ link lost). Dropped from the console so it doesn't spam. |
4141

4242
## Handshake
4343

@@ -57,15 +57,20 @@ Flipper ESP
5757
| <---- IP mac=... ip=...(DHCP leases it an address)
5858
| <---- CRED ip=...&... (a form is submitted)
5959
| <---- BYE mac=... (the phone leaves)
60-
| <---- PING (~every 2s, all the while)
60+
| <---- PING FTRP <ver> (~every 2s, all the while)
6161
| |
6262
| stop\n / reset\n ----> | (tear down / reboot)
6363
```
6464

65-
If the ESP emits `STATUS boot` mid-session (it rebooted), the Flipper re-sends
66-
`sethtml` automatically to recover. If `PING` (and all other traffic) stops for
67-
5s, the Flipper flags the link as lost and the dashboard shows **Board
68-
disconnected** until the board returns.
65+
Before the handshake the Flipper first **detects** the board by waiting for a
66+
magic `PING FTRP` beacon: none ⇒ *"Firmware needed"* (install prompt); magic but
67+
`<ver>` behind ⇒ *"Update firmware?"*; current ⇒ it proceeds. If the ESP emits
68+
`STATUS boot` mid-session (it rebooted), the Flipper re-sends `sethtml`
69+
automatically to recover. If the beacon (and all other traffic) stops for 5s, the
70+
Flipper flags the link as lost and the dashboard shows **Board disconnected**
71+
until the board returns. A start that detects the board but never reaches
72+
`portal_up` within ~8s is treated as a stalled handshake and drops back to the
73+
install prompt.
6974

7075
## Notes
7176

esp32/flytrap-fw/flytrap-fw.ino

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
// BYE mac=<mac> (a station left the AP)
1212
// IP mac=<mac> ip=<ip> (DHCP assigned a station its IP)
1313
// CRED <urlencoded> (all submitted form fields, one line per submission)
14-
// PING (~every 2s liveness beacon so the Flipper detects unplug)
14+
// PING FTRP <ver> (~every 2s liveness beacon; the magic "FTRP" identifies THIS
15+
// firmware to the Flipper and <ver> drives its update prompt)
1516
//
1617
// Authorized testing only.
1718

@@ -25,6 +26,12 @@
2526
#define MAX_HTML_SIZE 48000
2627
#define MAX_SSID 32
2728

29+
// Beacon identity: the magic marks a PING as coming from THIS firmware (so the
30+
// Flipper won't adopt some other board), and the version drives its update
31+
// prompt. KEEP IN SYNC with flipper/flytrap/flytrap_i.h.
32+
#define FW_MAGIC "FTRP"
33+
#define FW_VERSION 2
34+
2835
static char index_html[MAX_HTML_SIZE + 1] =
2936
"<html><body><h1>Flytrap</h1><p>Set a portal from the Flipper.</p></body></html>";
3037
static size_t index_html_len = 0;
@@ -129,15 +136,26 @@ static void onStaDisconnect(WiFiEvent_t event, WiFiEventInfo_t info) {
129136
emitLine(String("BYE mac=") + mac); // a station left the AP
130137
}
131138

132-
// DHCP handed a station an IP. The event only carries the IP (no MAC on this
133-
// IDF), so look the MAC up in the soft-AP station table by matching the IP, and
134-
// report the pair so the Flipper can attach the IP to the right client. Falls
135-
// back to an IP-only line if the table lookup can't resolve it.
139+
// DHCP handed a station an IP. Report the IP, and the MAC when we can resolve it,
140+
// so the Flipper can attach the IP to the right client. How the MAC is obtained
141+
// differs by core version (see the #if below), so this stays portable across the
142+
// 2.0.x core the S2/WROOM build against and the 3.x core the C5 needs.
136143
static void onStaIp(WiFiEvent_t event, WiFiEventInfo_t info) {
137144
(void)event;
138145
uint32_t evip = info.wifi_ap_staipassigned.ip.addr;
139146
IPAddress ip(evip);
140147

148+
#if ESP_ARDUINO_VERSION_MAJOR >= 3
149+
// esp-idf 5+ (Arduino core 3.x, e.g. the C5): the assign event carries the
150+
// station's MAC directly, so report the pair with no table lookup. The old
151+
// esp_netif_get_sta_list() path this used on 2.0.x was removed in the 3.x core.
152+
char mac[18];
153+
formatMac(info.wifi_ap_staipassigned.mac, mac);
154+
emitLine(String("IP mac=") + mac + " ip=" + ip.toString());
155+
#else
156+
// esp-idf 4.x (Arduino core 2.0.x, the S2/WROOM): the staipassigned event has
157+
// no MAC field, so look the MAC up in the soft-AP station table by matching the
158+
// IP. Falls back to an IP-only line if the table lookup can't resolve it.
141159
wifi_sta_list_t wifi_list;
142160
esp_netif_sta_list_t netif_list;
143161
if(esp_wifi_ap_get_sta_list(&wifi_list) == ESP_OK &&
@@ -152,6 +170,7 @@ static void onStaIp(WiFiEvent_t event, WiFiEventInfo_t info) {
152170
}
153171
}
154172
emitLine(String("IP ip=") + ip.toString()); // MAC unknown; Flipper pairs by recency
173+
#endif
155174
}
156175

157176
static void startPortal() {
@@ -261,6 +280,6 @@ void loop() {
261280
uint32_t now = millis();
262281
if(now - lastPing >= 2000) {
263282
lastPing = now;
264-
emitLine("PING");
283+
emitLine(String("PING " FW_MAGIC " ") + FW_VERSION);
265284
}
266285
}

0 commit comments

Comments
 (0)