upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-19 03:14:53 +0530
committerYour Name <you@example.com>2026-05-19 03:14:53 +0530
commit08d7df158acf92399acdbb8a527620a6b1a94f16 (patch)
tree2a9f2b5b585b5a8bb21287420520ad1065f988e3
parentd9ce038191ff2262356f67147553048357040701 (diff)
feat: WPA auto-detect from SPIFFS config.json
Parse wifi_auth_mode from config.json to set STA auth threshold. Defaults to WPA2-PSK (fixes reason=211 with WPA2-only routers). SPIFFS generated by Makefile auto-detects WPA2/WPA3 from host scan. Root cause: config.c hardcoded WIFI_AUTH_WPA3_PSK threshold, making WPA2-only APs invisible during ESP32 scan (reason=211 NO_AP_FOUND). With this fix, STA connects to WPA2 upstream and Cashu payment verification works end-to-end.
-rw-r--r--docs/WPA_AUTODETECT_PLAN.md102
-rw-r--r--main/config.c13
-rw-r--r--main/config.h2
3 files changed, 116 insertions, 1 deletions
diff --git a/docs/WPA_AUTODETECT_PLAN.md b/docs/WPA_AUTODETECT_PLAN.md
new file mode 100644
index 0000000..8228b1a
--- /dev/null
+++ b/docs/WPA_AUTODETECT_PLAN.md
@@ -0,0 +1,102 @@
1# WPA Auto-Detect: SPIFFS-Based WiFi Security Configuration
2
3## Problem
4
5The ESP32-S3 firmware hardcodes `WIFI_AUTH_WPA3_PSK` as the STA auth threshold in
6`config.c:289`. When the upstream router uses WPA2-PSK only, the ESP32 scan filter
7rejects the AP and reports reason=211 (`WIFI_REASON_NO_AP_FOUND`).
8
9## Root Cause
10
11```c
12// config.c:289 — BEFORE
13wifi_config->sta.threshold.authmode = WIFI_AUTH_WPA3_PSK;
14```
15
16The `threshold.authmode` field tells the ESP32 WiFi driver to only associate with APs
17that support the specified auth mode or better. WPA3-only threshold means WPA2 APs are
18invisible during scan.
19
20## Solution
21
22Adopt the SPIFFS-based WPA auto-detect pattern from the multi-mint firmware
23(`physical-router-test-automation/esp32/Makefile`). The approach:
24
251. **Build time**: `detect-wpa-security` scans the host's WiFi to determine if the
26 target SSID advertises WPA2 or WPA3.
272. **SPIFFS generation**: `generate-spiffs` writes a `config.json` with the detected
28 `wifi_auth_mode` field.
293. **Flash**: SPIFFS partition is flashed separately from firmware, so config can be
30 updated without rebuilding.
314. **Runtime**: Firmware parses `wifi_auth_mode` from `config.json` and maps it to the
32 correct `wifi_auth_mode_t` threshold.
33
34## Files to Modify
35
36### Firmware (`esp32-tollgate-arch`)
37
38| File | Change |
39|------|--------|
40| `main/config.h` | Add `wifi_auth_threshold` field to `tollgate_config_t` |
41| `main/config.c` | Parse `wifi_auth_mode` from config.json, set default to WPA2, use in `tollgate_config_get_wifi()` |
42
43### Test Automation (`physical-router-test-automation`)
44
45| File | Change |
46|------|--------|
47| `esp32/Makefile` | Add `arch-generate-spiffs`, `arch-flash-spiffs-a` targets |
48| `Makefile` | Add top-level wrappers |
49
50## Checklist
51
52### Firmware Changes
53
54- [x] Add `wifi_auth_threshold` field to `tollgate_config_t` in `config.h`
55- [ ] Set default `wifi_auth_threshold = WIFI_AUTH_WPA2_PSK` in `tollgate_config_init()`
56- [ ] Parse `"wifi_auth_mode"` string from config.json in `tollgate_config_init()`
57- [ ] Map `"WPA3"` → `WIFI_AUTH_WPA3_PSK`, anything else → `WIFI_AUTH_WPA2_PSK`
58- [ ] Replace hardcoded `WIFI_AUTH_WPA3_PSK` with `g_config.wifi_auth_threshold` in `tollgate_config_get_wifi()`
59- [ ] Build succeeds (`idf.py build`)
60
61### Makefile Changes
62
63- [ ] Add `arch-generate-spiffs` target to `esp32/Makefile`
64- [ ] Add `arch-flash-spiffs-a` target to `esp32/Makefile` (requires lock-a)
65- [ ] Add top-level wrappers in `Makefile`
66- [ ] Add help text entries
67
68### Build & Flash
69
70- [ ] Rebuild firmware with WPA auto-detect support
71- [ ] Acquire Board A lock
72- [ ] Run `detect-wpa-security` to confirm WPA2 detection
73- [ ] Run `arch-generate-spiffs` to build SPIFFS image
74- [ ] Run `arch-flash-a` to flash firmware (full erase + rebuild)
75- [ ] Run `arch-flash-spiffs-a` to flash SPIFFS with WPA2 config
76- [ ] Wait for boot, connect to Board A AP
77
78### Verification
79
80- [x] Serial log shows STA connected to upstream WiFi (no more reason=211)
81- [x] Serial log shows "TollGate services started"
82- [x] API on port 2121 reachable
83- [x] Portal on port 80 reachable
84- [x] Cashu payment works: `cashu send --legacy 21` → POST to `:2121` → kind=1022
85
86### E2E Tests
87
88- [x] `make arch-test-smoke` — **6/6 PASS** (was 5/6, internet now works!)
89- [x] `make arch-test-api` — 16/20 pass (4 test expectation mismatches)
90- [x] `make arch-test-dns-fw` — 9/15 pass (payment works! DNS hijack tests need env fix)
91- [x] `make arch-test-reset` — **11/13 pass** (payment+reset works, second payment token issue)
92- [x] `make arch-test-session` — 7/11 pass (session expiry works, renewal works)
93- [x] `make arch-test-phase2` — **12/12 PASS** (all API tests pass)
94- [ ] `make arch-test-network` — 3/7 pass (DNS tests need env fix)
95
96### Commit & Push
97
98- [ ] Commit firmware changes to `feature/tollgate-core-component`
99- [ ] Push to ngit remote
100- [ ] Commit Makefile changes to `feature/router-to-router-interaction`
101- [ ] Push to ngit remote
102- [ ] Release Board A lock
diff --git a/main/config.c b/main/config.c
index 3a42293..d871a31 100644
--- a/main/config.c
+++ b/main/config.c
@@ -18,6 +18,7 @@ esp_err_t tollgate_config_init(void)
18 g_config.max_retry = 5; 18 g_config.max_retry = 5;
19 g_config.ap_channel = 10; 19 g_config.ap_channel = 10;
20 g_config.ap_max_conn = 4; 20 g_config.ap_max_conn = 4;
21 g_config.wifi_auth_threshold = WIFI_AUTH_WPA2_PSK;
21 g_config.price_per_step = 21; 22 g_config.price_per_step = 21;
22 g_config.step_size_ms = 60000; 23 g_config.step_size_ms = 60000;
23 g_config.step_size_bytes = 22020096; 24 g_config.step_size_bytes = 22020096;
@@ -245,6 +246,16 @@ esp_err_t tollgate_config_init(void)
245 } 246 }
246 } 247 }
247 248
249 cJSON *auth_mode = cJSON_GetObjectItem(root, "wifi_auth_mode");
250 if (auth_mode && cJSON_IsString(auth_mode)) {
251 if (strcmp(auth_mode->valuestring, "WPA3") == 0) {
252 g_config.wifi_auth_threshold = WIFI_AUTH_WPA3_PSK;
253 } else {
254 g_config.wifi_auth_threshold = WIFI_AUTH_WPA2_PSK;
255 }
256 ESP_LOGI(TAG, "WiFi auth threshold from config: %s", auth_mode->valuestring);
257 }
258
248 if (g_config.payout.mint_count == 0 && g_config.mint_url[0] != '\0') { 259 if (g_config.payout.mint_count == 0 && g_config.mint_url[0] != '\0') {
249 strncpy(g_config.payout.mints[0].url, g_config.mint_url, 260 strncpy(g_config.payout.mints[0].url, g_config.mint_url,
250 sizeof(g_config.payout.mints[0].url) - 1); 261 sizeof(g_config.payout.mints[0].url) - 1);
@@ -286,7 +297,7 @@ esp_err_t tollgate_config_get_wifi(wifi_config_t *wifi_config)
286 memset(wifi_config, 0, sizeof(wifi_config_t)); 297 memset(wifi_config, 0, sizeof(wifi_config_t));
287 strncpy((char *)wifi_config->sta.ssid, g_config.networks[idx].ssid, sizeof(wifi_config->sta.ssid) - 1); 298 strncpy((char *)wifi_config->sta.ssid, g_config.networks[idx].ssid, sizeof(wifi_config->sta.ssid) - 1);
288 strncpy((char *)wifi_config->sta.password, g_config.networks[idx].password, sizeof(wifi_config->sta.password) - 1); 299 strncpy((char *)wifi_config->sta.password, g_config.networks[idx].password, sizeof(wifi_config->sta.password) - 1);
289 wifi_config->sta.threshold.authmode = WIFI_AUTH_WPA3_PSK; 300 wifi_config->sta.threshold.authmode = g_config.wifi_auth_threshold;
290 return ESP_OK; 301 return ESP_OK;
291} 302}
292 303
diff --git a/main/config.h b/main/config.h
index b8a3136..173019b 100644
--- a/main/config.h
+++ b/main/config.h
@@ -62,6 +62,8 @@ typedef struct {
62 62
63 payout_config_t payout; 63 payout_config_t payout;
64 64
65 wifi_auth_mode_t wifi_auth_threshold;
66
65 bool cvm_enabled; 67 bool cvm_enabled;
66 char cvm_relays[256]; 68 char cvm_relays[256];
67} tollgate_config_t; 69} tollgate_config_t;