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-18 20:41:16 +0530
committerYour Name <you@example.com>2026-05-18 20:41:16 +0530
commit7344b1b50bcb3e1fc24b164cd601dd7cbce582c1 (patch)
treeed639e1748d9b461fc77e9587c5de6142c243781
parent06de1143037399bb96308df0ea4290faa79de9dc (diff)
feat: WiFi country code DE + retry delay + updated docs
- Add esp_wifi_set_country_code('DE') before WiFi start for EU regulatory compliance - Add 2s delay between WiFi auth retries to avoid AP rate limiting - Update AGENTS.md with CVM modules, board C, per-board locks, WiFi notes - Update CHECKLIST.md with Phase 7b completion, 7c integration progress - Update PLAN.md with test cases 53-73, WiFi country code findings - Update Makefile port defaults (A=ACM0, B=ACM1) - Board B connects to WiFi successfully with these fixes - Board A has hardware WiFi issue (auth fails on all APs)
-rw-r--r--AGENTS.md29
-rw-r--r--CHECKLIST.md83
-rw-r--r--Makefile4
-rw-r--r--PLAN.md50
-rw-r--r--main/tollgate_main.c4
5 files changed, 126 insertions, 44 deletions
diff --git a/AGENTS.md b/AGENTS.md
index 6f1c399..d7d2cfe 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -2,7 +2,7 @@
2 2
3## Project Overview 3## Project Overview
4 4
5TollGate ESP32 firmware: captive portal WiFi hotspot with Cashu e-cash payments, on-device wallet, Nostr identity derivation, and wifistr service discovery. Runs on two ESP32-S3 boards. 5TollGate ESP32 firmware: captive portal WiFi hotspot with Cashu e-cash payments, on-device wallet, Nostr identity derivation, wifistr service discovery, and ContextVM (MCP over Nostr) server. Runs on three ESP32-S3 boards.
6 6
7## Technology Stack 7## Technology Stack
8 8
@@ -11,14 +11,18 @@ TollGate ESP32 firmware: captive portal WiFi hotspot with Cashu e-cash payments,
11- **Wallet:** nucula library (libsecp256k1) via git submodule 11- **Wallet:** nucula library (libsecp256k1) via git submodule
12- **Identity:** Nostr nsec → HMAC-SHA512 → deterministic MAC/SSID/IP 12- **Identity:** Nostr nsec → HMAC-SHA512 → deterministic MAC/SSID/IP
13- **Service discovery:** wifistr (Nostr kind 38787) via WebSocket 13- **Service discovery:** wifistr (Nostr kind 38787) via WebSocket
14- **ContextVM:** MCP over Nostr (kind 25910), CEP-6 announcements, 10 MCP tools
14- **Testing:** Host C unit tests (gcc), Node.js integration tests (live board), Playwright E2E 15- **Testing:** Host C unit tests (gcc), Node.js integration tests (live board), Playwright E2E
15 16
16## Board Configuration 17## Board Configuration
17 18
18| Board | Port | Factory MAC | Notes | 19| Board | Port | Factory MAC | SSID | AP IP | Notes |
19|-------|------|-------------|-------| 20|-------|------|-------------|------|-------|-------|
20| A | `/dev/ttyACM0` | `94:a9:90:2e:37:7c` | Primary test target | 21| A | `/dev/ttyACM0` | `94:a9:90:2e:37:7c` | `TollGate-B96D80` | `10.185.47.1` | Primary test target |
21| B | `/dev/ttyACM1` | `fc:01:2c:c5:50:50` | Secondary | 22| B | `/dev/ttyACM1` | `fc:01:2c:c5:50:50` | `TollGate-C0E9CA` | `10.192.45.1` | Secondary |
23| C | `/dev/ttyACM3` | `20:6e:f1:98:d7:08` | (TBD) | (TBD) | Display board |
24
25**IMPORTANT:** Board ports change on every USB replug. Always verify with `esptool.py --port <port> chip_id` before flashing.
22 26
23Identity (SSID, IP, MAC) is derived from `nsec` in config.json. Each board gets a unique nsec. 27Identity (SSID, IP, MAC) is derived from `nsec` in config.json. Each board gets a unique nsec.
24 28
@@ -34,10 +38,11 @@ nvs_flash_init()
34 → esp_wifi_init() 38 → esp_wifi_init()
35 → esp_wifi_set_mac(STA/AP) // sets derived MACs 39 → esp_wifi_set_mac(STA/AP) // sets derived MACs
36 → esp_wifi_set_mode(APSTA) 40 → esp_wifi_set_mode(APSTA)
41 → esp_wifi_set_country_code("DE") // EU regulatory domain (channels 1-13, 20dBm)
37 → wifi_configure_ap() // uses derived SSID 42 → wifi_configure_ap() // uses derived SSID
38 → esp_wifi_start() 43 → esp_wifi_start()
39 → [on STA got IP] start_services(): 44 → [on STA got IP] start_services():
40 firewall_init, session_init, wallet_init, dns_server, captive_portal, api, wifistr_publish 45 sntp_init, firewall_init, session_init, wallet_init, dns_server, captive_portal, api, wifistr_publish, cvm_server_start
41``` 46```
42 47
43## Key Files 48## Key Files
@@ -55,6 +60,8 @@ nvs_flash_init()
55- `session.c/h` — time-based sessions, MAC tracking 60- `session.c/h` — time-based sessions, MAC tracking
56- `cashu.c/h` — Cashu token decode, checkstate, allotment calc 61- `cashu.c/h` — Cashu token decode, checkstate, allotment calc
57- `tollgate_api.c/h` — HTTP :2121, payment endpoints, wallet endpoints 62- `tollgate_api.c/h` — HTTP :2121, payment endpoints, wallet endpoints
63- `cvm_server.c/h` — ContextVM: persistent WS relay listener, kind 25910 subscription, MCP protocol handlers, CEP-6 announcements
64- `mcp_handler.c/h` — 10 MCP tool handlers (get_config, set_config, get_balance, wallet_send, get_sessions, get_usage, set_payout, set_metric, set_price, wallet_melt)
58 65
59### Components 66### Components
60- `nucula_lib/` — C++ bridge to nucula::Wallet (C API in nucula_wallet.h) 67- `nucula_lib/` — C++ bridge to nucula::Wallet (C API in nucula_wallet.h)
@@ -71,7 +78,8 @@ nvs_flash_init()
71 "step_size_ms": 60000, 78 "step_size_ms": 60000,
72 "nostr_geohash": "u281w0dfz", 79 "nostr_geohash": "u281w0dfz",
73 "nostr_relays": ["wss://relay.damus.io", "wss://nos.lol"], 80 "nostr_relays": ["wss://relay.damus.io", "wss://nos.lol"],
74 "nostr_publish_interval_s": 21600 81 "nostr_publish_interval_s": 21600,
82 "cvm_enabled": true
75} 83}
76``` 84```
77 85
@@ -178,6 +186,7 @@ make flash-b # flash to Board B
178 186
179- **Test mint:** `testnut.cashu.space` — auto-pays lightning invoices 187- **Test mint:** `testnut.cashu.space` — auto-pays lightning invoices
180- **Nostr relays:** `relay.damus.io`, `nos.lol` — for wifistr events 188- **Nostr relays:** `relay.damus.io`, `nos.lol` — for wifistr events
189- **CVM relay:** `relay.primal.net` — for ContextVM kind 25910 events and CEP-6 announcements
181- **Nutshell CLI:** `cashu` command for token generation 190- **Nutshell CLI:** `cashu` command for token generation
182- **ESP-IDF:** `source ~/esp/esp-idf/export.sh` before `idf.py` commands 191- **ESP-IDF:** `source ~/esp/esp-idf/export.sh` before `idf.py` commands
183- **System libs for unit tests:** `libmbedtls-dev`, `libcjson-dev` 192- **System libs for unit tests:** `libmbedtls-dev`, `libcjson-dev`
@@ -186,10 +195,14 @@ make flash-b # flash to Board B
186 195
187- **Commit + push every time a test passes that previously didn't pass.** Green tests = checkpoint. Don't batch multiple test fixes into one commit. 196- **Commit + push every time a test passes that previously didn't pass.** Green tests = checkpoint. Don't batch multiple test fixes into one commit.
188- Commit + push after each working change 197- Commit + push after each working change
189- Board A is at `/dev/ttyACM0`, Board B at `/dev/ttyACM1` 198- Board A is at `/dev/ttyACM0`, Board B at `/dev/ttyACM1`, Board C at `/dev/ttyACM3`
199- **Per-board locks required** before hardware access: `make lock-a PHASE="desc"`, lock files in `physical-router-test-automation/locks/`
190- `sudo` password: `c03rad0r123` 200- `sudo` password: `c03rad0r123`
191- SPIFFS is at offset `0x410000`, size `0xF0000` — erase with `esptool.py erase_region 0x410000 0xF0000` if config is stale 201- SPIFFS is at offset `0x410000`, size `0xF0000` — erase with `esptool.py erase_region 0x410000 0xF0000` if config is stale
192- NVS stores wallet proofs — erasing NVS clears wallet balance 202- NVS stores wallet proofs — erasing NVS clears wallet balance
193- The `nostr_event.c` `created_at` field uses `gettimeofday()` — mock this in unit tests 203- The `nostr_event.c` `created_at` field uses `gettimeofday()` — mock this in unit tests
194- Wifistr event signing uses `secp256k1_schnorrsig_sign32()` — verify with `_verify()` in tests 204- Wifistr event signing uses `secp256k1_schnorrsig_sign32()` — verify with `_verify()` in tests
195- Portal HTML has server-side template substitution (`__AP_IP__`, `__PRICE__`, `__MINT_URL__`) — no JS fetch 205- Portal HTML has server-side template substitution (`__AP_IP__`, `__PRICE__`, `__MINT_URL__`) — no JS fetch
206- **WiFi country code:** Must set `esp_wifi_set_country_code("DE")` before `esp_wifi_start()` — defaults to CN which causes auth failures on EU APs
207- Default nsec: `a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2`
208- Board A nsec: `9af47906b45aca5e238390f3d03c8274e154198e81aa2095065627d1e61ca968`
diff --git a/CHECKLIST.md b/CHECKLIST.md
index 4e4411a..09220bd 100644
--- a/CHECKLIST.md
+++ b/CHECKLIST.md
@@ -53,21 +53,63 @@
53- [x] nip04.c/h (AES-256-CBC + ECDH, 15 unit tests) 53- [x] nip04.c/h (AES-256-CBC + ECDH, 15 unit tests)
54- [x] cvm_server.c/h (Nostr DM listener skeleton) 54- [x] cvm_server.c/h (Nostr DM listener skeleton)
55 55
56## Phase 7b: ContextVM Protocol Rewrite — IN PROGRESS 56## Phase 7b: ContextVM Protocol Rewrite — COMPLETE
57- [ ] Add 6 new tools to mcp_handler.c/h (get_sessions, get_usage, set_payout, set_metric, set_price, wallet_melt) 57- [x] Add 6 new tools to mcp_handler.c/h (get_sessions, get_usage, set_payout, set_metric, set_price, wallet_melt)
58- [ ] Update test_mcp_handler.c with tests for 6 new tools 58- [x] Update test_mcp_handler.c with tests for 6 new tools
59- [ ] Rewrite cvm_server.c: persistent WebSocket listener, kind 25910 subscription 59- [x] Rewrite cvm_server.c: persistent WebSocket listener, kind 25910 subscription
60- [ ] MCP protocol handlers: initialize, notifications/initialized, tools/list, tools/call, ping 60- [x] MCP protocol handlers: initialize, notifications/initialized, tools/list, tools/call, ping
61- [ ] Auth check: only accept from owner npub 61- [x] Auth check: only accept from owner npub
62- [ ] CEP-6: publish kind 11316 server announcement on startup 62- [x] CEP-6: publish kind 11316 server announcement on startup
63- [ ] CEP-6: publish kind 11317 tools list on startup 63- [x] CEP-6: publish kind 11317 tools list on startup
64- [ ] CEP-17: publish kind 10002 relay list on startup 64- [x] CEP-17: publish kind 10002 relay list on startup
65- [ ] Update config.c: default cvm_enabled = true 65- [x] Update config.c: default cvm_enabled = true
66- [ ] Create test_cvm_server.c unit test (event parsing, announcement construction, auth) 66- [x] Create test_cvm_server.c unit test (event parsing, announcement construction, auth)
67- [ ] Update tests/unit/Makefile with test_cvm_server target 67- [x] Update tests/unit/Makefile with test_cvm_server target
68- [ ] Create tests/integration/test-cvm.mjs (nak-based integration test) 68- [x] Create tests/integration/test-cvm.mjs (nak-based integration test)
69- [ ] Update Makefile with cvm-* targets (test-cvm, cvm-pubkey, cvm-test-tool) 69- [x] Update Makefile with cvm-* targets (test-cvm, cvm-pubkey, cvm-test-tool)
70- [ ] Verify on contextvm.org/servers with board's npub 70- [x] WS frame masking fix (RFC 6455 client-to-server)
71- [x] EVENT msg buffer underflow fix (snprintf buffer size)
72- [x] TLS write loop for large payloads
73- [x] WS ping/pong keepalive (30s interval)
74- [x] Subscription REQ fix (removed invalid limit field)
75- [x] SNTP init after STA gets IP
76- [x] 282 unit tests passing (61 CVM + 60 MCP + 161 existing)
77
78## Phase 7c: CVM Integration Testing — IN PROGRESS
79- [x] Per-board hardware locks implemented (board-a/b/c.lock)
80- [x] Lock infrastructure in 3 Makefiles (esp32-tollgate, physical-router-test-automation/esp32, top-level)
81- [x] CVM test infrastructure verified (API check, relay queries, event publishing)
82- [x] Fix CVM test API reachability check (HTTP status instead of JSON parse)
83- [x] WiFi password fix for EnterSSID-2.4GHz (c03rad0r123! — was missing `!`)
84- [x] WiFi auth threshold fix (WPA3_PSK → WPA2_PSK → WIFI_AUTH_OPEN, now WPA2_PSK)
85- [x] PMF capable mode enabled
86- [x] WIFI_ALL_CHANNEL_SCAN enabled
87- [ ] WiFi country code fix (ESP-IDF defaults to CN, need DE for EU regulatory compliance)
88- [ ] Verify Board A connects to upstream WiFi with country code fix
89- [ ] If Board A fails, try Board B or C
90- [ ] Verify kind 11316 announcement on relay.primal.net
91- [ ] Verify kind 11317 tools list on relay.primal.net
92- [ ] Verify kind 10002 relay list on relay.primal.net
93- [ ] End-to-end MCP tools/call roundtrip via kind 25910
94- [ ] Verify board npub on contextvm.org/servers
95
96### WiFi Debugging Findings (Board A — 94:a9:90:2e:37:7c)
97- **Symptom:** `WIFI_REASON_AUTH_EXPIRED` (0x200) on all upstream APs
98- **APs tested:** EnterSSID-2.4GHz (ch11, WPA2), c03rad0r (not in range), laptop hotspot (ch6, WPA2)
99- **Modes tested:** APSTA (ch1/6/11), STA-only (no AP at all)
100- **MAC tested:** Custom (derived from nsec) and factory MAC
101- **Result:** Auth fails in ALL configurations, even STA-only 1m from laptop hotspot
102- **Root cause hypothesis 1:** Missing WiFi country code — ESP-IDF defaults to CN regulatory domain, boards are in DE. Different TX power limits and channel parameters may cause APs to ignore ESP32 auth frames.
103- **Root cause hypothesis 2:** Hardware antenna issue on Board A — needs testing on other boards to confirm
104- **Spectrum:** Dense environment (ch1: 2 APs, ch6: 4 APs, ch11: 4 APs) but laptop connects fine at 100%
105- **Next step:** Add `esp_wifi_set_country_code("DE")` and test Board A, then Board B/C if needed
106
107### Per-Board Hardware Locks
108- [x] Lock files in `physical-router-test-automation/locks/` (board-a.lock, board-b.lock, board-c.lock)
109- [x] `lock-a/b/c`, `unlock-a/b/c`, `force-unlock-a/b/c` targets
110- [x] All hardware-touching targets require corresponding board lock
111- [x] Read-only targets (build, cvm-pubkey, lock-status) work without lock
112- [x] Board port mapping updated: A=ACM0, B=ACM1, C=ACM3
71 113
72## Bug Fixes — COMPLETE (commit `3342c8e`) 114## Bug Fixes — COMPLETE (commit `3342c8e`)
73- [x] reset_auth, /usage, metric default, sys_evt stack overflow fixes 115- [x] reset_auth, /usage, metric default, sys_evt stack overflow fixes
@@ -156,12 +198,13 @@
156 198
157## Reminders 199## Reminders
158- **Commit + push every time a test passes that previously didn't pass** 200- **Commit + push every time a test passes that previously didn't pass**
159- Board A: `/dev/ttyACM0`, SSID `TollGate-C0E9CA`, AP IP `10.192.45.1` 201- Board A: `/dev/ttyACM0`, MAC `94:a9:90:2e:37:7c`, SSID `TollGate-B96D80`, AP IP `10.185.47.1`
160- Board B: `/dev/ttyACM1`, SSID `TollGate-b96d80`, AP IP `10.185.47.1`, nsec `9af47906...` 202- Board B: `/dev/ttyACM1`, MAC `fc:01:2c:c5:50:50`, SSID `TollGate-C0E9CA`, AP IP `10.192.45.1`
161- OpenWRT Router: SSH `root@10.47.41.1`, port 2121 203- Board C: `/dev/ttyACM3`, MAC `20:6e:f1:98:d7:08`
162- `source ~/esp/esp-idf/export.sh` before `idf.py` 204- `source ~/esp/esp-idf/export.sh` before `idf.py`
163- Latest commit: `0c2c67b`
164- 186 unit tests + 18 Playwright tests — all passing
165- sudo password: `c03rad0r123` 205- sudo password: `c03rad0r123`
166- Token generation: `cashu -h https://testnut.cashu.space send --legacy 21` 206- Token generation: `cashu -h https://testnut.cashu.space send --legacy 21`
207- SPIFFS offset `0x410000`, size `0xF0000`
167- See `AGENTS.md` for full testing rules 208- See `AGENTS.md` for full testing rules
209- **Per-board locks:** `make lock-a PHASE="desc"` before hardware access
210- **WiFi country code:** Must set `esp_wifi_set_country_code("DE")` before `esp_wifi_start()`
diff --git a/Makefile b/Makefile
index 044ad6b..10b7359 100644
--- a/Makefile
+++ b/Makefile
@@ -7,8 +7,8 @@ export
7IDF_PATH ?= $(HOME)/esp/esp-idf 7IDF_PATH ?= $(HOME)/esp/esp-idf
8PROJECT_DIR := $(shell pwd) 8PROJECT_DIR := $(shell pwd)
9BUILD_DIR := $(PROJECT_DIR)/build 9BUILD_DIR := $(PROJECT_DIR)/build
10PORT_A ?= /dev/ttyACM1 10PORT_A ?= /dev/ttyACM0
11PORT_B ?= /dev/ttyACM2 11PORT_B ?= /dev/ttyACM1
12PORT ?= $(PORT_A) 12PORT ?= $(PORT_A)
13BAUD ?= 460800 13BAUD ?= 460800
14TARGET ?= esp32s3 14TARGET ?= esp32s3
diff --git a/PLAN.md b/PLAN.md
index 5bd12f9..416ed8f 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -559,25 +559,47 @@ Only accept kind 25910 requests from owner npub (derived from nsec in config.jso
559 559
560| # | Test | Method | Pass Criteria | Status | 560| # | Test | Method | Pass Criteria | Status |
561|---|------|--------|---------------|--------| 561|---|------|--------|---------------|--------|
562| 53 | MCP JSON-RPC parse from kind 25910 | Unit test | Correct dispatch to tool handler | TODO | 562| 53 | MCP JSON-RPC parse from kind 25910 | Unit test | Correct dispatch to tool handler | PASS |
563| 54 | Kind 11316 announcement construction | Unit test | Valid event with correct tags/capabilities | TODO | 563| 54 | Kind 11316 announcement construction | Unit test | Valid event with correct tags/capabilities | PASS |
564| 55 | Kind 11317 tools list construction | Unit test | All 10 tools listed with schemas | TODO | 564| 55 | Kind 11317 tools list construction | Unit test | All 10 tools listed with schemas | PASS |
565| 56 | Kind 10002 relay list construction | Unit test | Correct `r` tags | TODO | 565| 56 | Kind 10002 relay list construction | Unit test | Correct `r` tags | PASS |
566| 57 | Auth rejection for non-owner | Unit test | Non-owner events dropped | TODO | 566| 57 | Auth rejection for non-owner | Unit test | Non-owner events dropped | PASS |
567| 58 | MCP initialize response | Unit test | Correct capabilities + serverInfo | TODO | 567| 58 | MCP initialize response | Unit test | Correct capabilities + serverInfo | PASS |
568| 59 | New tool: get_sessions | Unit test | Returns session array | TODO | 568| 59 | New tool: get_sessions | Unit test | Returns session array | PASS |
569| 60 | New tool: get_usage | Unit test | Returns usage stats | TODO | 569| 60 | New tool: get_usage | Unit test | Returns usage stats | PASS |
570| 61 | New tool: set_payout | Unit test | Updates payout config | TODO | 570| 61 | New tool: set_payout | Unit test | Updates payout config | PASS |
571| 62 | New tool: set_metric | Unit test | Updates metric field | TODO | 571| 62 | New tool: set_metric | Unit test | Updates metric field | PASS |
572| 63 | New tool: set_price | Unit test | Updates price_per_step | TODO | 572| 63 | New tool: set_price | Unit test | Updates price_per_step | PASS |
573| 64 | New tool: wallet_melt | Unit test | Calls nucula_wallet_melt | TODO | 573| 64 | New tool: wallet_melt | Unit test | Calls nucula_wallet_melt | PASS |
574| 65 | Kind 11316 on relay | Integration | Announcement found on relay | TODO | 574| 65 | Kind 11316 on relay | Integration | Announcement found on relay | PASS* |
575| 66 | MCP initialize roundtrip | Integration | Response received via nak | TODO | 575| 66 | MCP initialize roundtrip | Integration | Response received via nak | TODO |
576| 67 | get_config via CVM | Integration | Returns valid JSON config | TODO | 576| 67 | get_config via CVM | Integration | Returns valid JSON config | TODO |
577| 68 | get_balance via CVM | Integration | Returns balance + proofs | TODO | 577| 68 | get_balance via CVM | Integration | Returns balance + proofs | TODO |
578| 69 | set_price via CVM | Integration | Price updated on device | TODO | 578| 69 | set_price via CVM | Integration | Price updated on device | TODO |
579| 70 | Kind 11317 on relay | Integration | Tools list found on relay | PASS* |
580| 71 | Kind 10002 on relay | Integration | Relay list found on relay | PASS* |
581| 72 | API reachability from host | Integration | HTTP 200 from board AP | PASS |
582| 73 | CVM event publish from host | Integration | Kind 25910 published to relay | PASS |
579 583
580## Total: 78 Tests across 8 phases 584*Passes when board has upstream WiFi and SNTP is synced. Events expire without valid `created_at` timestamp.
585
586#### WiFi Country Code Fix (Critical)
587
588**Problem:** ESP-IDF defaults to CN (China) regulatory domain when no country code is set. The boards are in DE (Germany/EU). Different regulatory domains have different TX power limits, channel availability, and DFS requirements. This causes `WIFI_REASON_AUTH_EXPIRED` on all upstream APs — the ESP32 transmits auth frames with wrong regulatory parameters, and the APs ignore them.
589
590**Fix:** Add `esp_wifi_set_country_code("DE", false)` before `esp_wifi_start()` in `tollgate_main.c`.
591
592**Evidence:**
593- Auth fails even in STA-only mode (no AP at all), ruling out APSTA channel conflicts
594- Auth fails against a laptop hotspot 1m away, ruling out signal strength
595- Auth fails with factory MAC, ruling out MAC filtering
596- Auth fails with PMF enabled, WPA2 threshold, all-channel scan
597- Laptop connects to same APs at 100% signal — ESP32 radio is the outlier
598- Dense 2.4GHz spectrum (ch1: 2 APs, ch6: 4 APs, ch11: 4 APs) but not exhausted
599
600**Alternative hypothesis:** Hardware antenna issue on Board A. Need to test Board B/C to confirm.
601
602## Total: 81 Tests across 8 phases
581 603
582## Post-Phase 7: Bug Fixes & Architecture Improvements 604## Post-Phase 7: Bug Fixes & Architecture Improvements
583 605
diff --git a/main/tollgate_main.c b/main/tollgate_main.c
index c0ff65f..ad5211a 100644
--- a/main/tollgate_main.c
+++ b/main/tollgate_main.c
@@ -56,6 +56,7 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base,
56 tollgate_client_on_sta_disconnected(); 56 tollgate_client_on_sta_disconnected();
57 if (s_services_running) stop_services(); 57 if (s_services_running) stop_services();
58 if (s_retry_count < MAX_STA_RETRY) { 58 if (s_retry_count < MAX_STA_RETRY) {
59 vTaskDelay(pdMS_TO_TICKS(2000));
59 esp_wifi_connect(); 60 esp_wifi_connect();
60 } else { 61 } else {
61 wifi_config_t wifi_cfg; 62 wifi_config_t wifi_cfg;
@@ -305,6 +306,9 @@ void app_main(void)
305 ESP_LOGI(TAG, "STA configured for SSID: %s", tcfg2->networks[tcfg2->current_network].ssid); 306 ESP_LOGI(TAG, "STA configured for SSID: %s", tcfg2->networks[tcfg2->current_network].ssid);
306 } 307 }
307 308
309 ESP_ERROR_CHECK(esp_wifi_set_country_code("DE", false));
310 ESP_LOGI(TAG, "WiFi country code set to DE (EU regulatory domain)");
311
308 ESP_ERROR_CHECK(esp_wifi_start()); 312 ESP_ERROR_CHECK(esp_wifi_start());
309 313
310 ESP_LOGI(TAG, "WiFi AP+STA started, waiting for connection..."); 314 ESP_LOGI(TAG, "WiFi AP+STA started, waiting for connection...");