Improve radar polling reliability and clean up unused variables#3
Open
daniel-frenkel wants to merge 11 commits intomainfrom
Open
Improve radar polling reliability and clean up unused variables#3daniel-frenkel wants to merge 11 commits intomainfrom
daniel-frenkel wants to merge 11 commits intomainfrom
Conversation
- api.h: reserve() was called on the wrong String (httpsRequestData instead of httpsRequestSend), forcing many reallocations during the ~100KB photo upload payload build. - api.h: release photo_base64 after upload so the buffer doesn't sit on the heap until the next capture. - api.h: round maxSpeed -> speed_actual to keep the wire format integer now that maxSpeed is float. - api.h: wifiResetButton() now stores "NOT_SET" sentinels (matches buttonClearNetworkCall) rather than literal "ssid"/"pass". - radar.h: fix get_speed() race - the original checked available() before the STM32 could reply, so each cycle returned the previous query's data (or "NO DATA"). Drain stale bytes, send the command, then parseFloat() with a bounded Serial1 timeout. - variables.h: speed and maxSpeed were int, truncating the radar's 0.1 resolution; now float. - esp32_firmware_1-2.ino: Serial1.setTimeout(50) so parseFloat() can't stall the polling loop for a full second. - esp32_firmware_1-2.ino: post-boot grace was 10s despite the comment promising 120s; restore 120000. - esp32_firmware_1-2.ino: log lines now reflect what actually happens (WiFi off, not light sleep, since esp_light_sleep_start is commented out). - espui_settings.h: rename locals in buttonSaveNetworkCall so they no longer shadow the globals from variables.h. https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
Dropped twelve unused globals from variables.h (API_photo, photo_finished, sleep_idle_time, send_alert, lastTime, labelWifi, display_wifi, button1, switchOne, status, apIP, DNS_PORT) and the write-only send_API (along with its sole assignment in the main sketch). The DNS_PORT/apIP pair was apparently intended for a captive-portal dnsServer.start() that is never called; the processNextRequest() loop is therefore a no-op, but that is left for a separate fix. https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
dnsServer.processNextRequest() was being called every loop iteration but dnsServer.start() had never been invoked, so the captive portal silently did nothing - users had to type 192.168.4.1 by hand. connectWifiAP() now starts a wildcard DNS responder pointing at the soft-AP IP whenever it falls into AP mode, so any DNS lookup from a connected client lands on the ESPUI page (and most OSes detect this as a captive portal and surface the configuration UI automatically). The DNSServer global moved to variables.h so both the .ino (for processNextRequest) and api.h (for start) can see it. https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
Five high-impact items from the firmware review: - AP-aware idle teardown. The grace-window and 5s-idle paths in taskCore1 unconditionally called WiFi.disconnect/WIFI_OFF, which killed the soft-AP while a user might still be configuring WiFi via the captive portal. Both paths now skip the teardown when WiFi.getMode() == WIFI_AP. - Task watchdog. Both pinned tasks (Core 0 / Core 1) are now subscribed to the task WDT with a 30s timeout (covers the 5s HTTPS connect/read budgets and the 3s wifiResetButton blocking poll). The inner while(speed >= min_speed) tracking loop also heartbeats so a long pass can't trip the watchdog. - WiFi password no longer logged to Serial in connectWifi. - Soft-AP WPA2 + ESPUI basic auth. Both use a per-device password derived from the last 4 bytes of the WiFi MAC (8 hex chars, meets WPA2 minimum length), printed to Serial at boot. Closes the open-AP / unauthenticated-portal hole that let anyone in radio range overwrite stored credentials. - takePhoto() now returns bool and clears photo_filename and photo_base64 on capture failure, and the caller in taskCore1 only sets send_data / send_photo when a real frame was captured. Previously a failed capture mid-run could cause the next upload to re-send a stale image from a prior pass. The non_speeding endpoint still never receives data (send_data is only raised when photo_speed is reached, so under-threshold passes are dropped) - that's a separate bug, left for a follow-up. https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
send_data was only being raised inside the photo-capture branch, so passes that crossed min_speed but never reached photo_speed - and passes where takePhoto() failed - never triggered Core 0's upload. The non_speeding endpoint was effectively dead. Drop the inline send_data assignment and raise send_data once at the end of the tracking run. send_photo (already gated on photo_captured) still selects between the speeding and non_speeding endpoints, so photo passes upload to /speeding_capture and the rest upload to /non_speeding_capture with just the speed. https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
issue_cdm324_reset() previously spun forever waiting for a newline from the STM32. Because it runs from setup() before either pinned task subscribes to the watchdog, a dead or unprogrammed STM32 wedged the boot with no recovery. Add a 1000ms millis-based bound and log the timeout instead of hanging. Also wire up ArduinoOTA so the firmware can be updated without USB. setupOTA() runs after sendLocalIP() and only enables OTA in STA mode - the AP fallback is for first-time setup, not for OTA. The auth password is the same MAC-derived per-device password used for the soft-AP and ESPUI basic auth, so a LAN attacker can't push arbitrary firmware. taskCore0 services ArduinoOTA.handle() each loop iteration; the onProgress callback resets the task WDT so a slow upload can't trip the 30s timeout. OTA is reachable while WiFi is up - i.e., during the 120s post-boot grace window and any active radar period. The mDNS service won't re-register itself after the idle teardown, so reliable OTA in the field means: reboot the device, then push within the grace window. https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
The minispeedcam.com Bubble.io workflow token was hardcoded in api.h (twice), so rotating it required reflashing every fielded device. Token is now loaded from NVS in setup() with the original baked-in value as the default fallback, so existing deployments keep working without manual configuration. A new "API Token" text input on the WiFi Settings tab lets the operator rotate it from the portal; on Save we persist to NVS and reboot, picking up the new value via sendLocalIP() and sendPhoto(). https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
The portal previously had no read-only surface, so debugging a device in the field meant USB serial. The new Status tab (added as the first tab so it's the landing page) shows live telemetry that covers the most common questions: - Current Speed - radar reading per polling cycle, in the configured unit (mph/kph). - Last Run Max - peak speed of the most recent tracking pass. - Last Upload - "OK (200)", "Failed (-1)", "Uploading...", or "No uploads yet". Reads httpsResponseCode and sending_data. - WiFi - SSID and RSSI when STA-connected, "AP mode" during initial setup, "Radio off" when the idle path has powered the radio down. - Uptime - h/m/s since boot. updateStatusUI() lives in espui_settings.h; taskCore1 calls it on a 1Hz cadence (the radar loop runs at 10Hz, which is too fast for the ESPUI WebSocket). https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
esp_task_wdt_init's signature changed between Arduino-ESP32 2.x
(IDF 4: timeout_seconds + bool panic) and 3.x (IDF 5: const
esp_task_wdt_config_t*). The previous commit used the 2.x form,
which fails to compile on IDF 5.x toolchains:
error: too many arguments to function
'esp_err_t esp_task_wdt_init(const esp_task_wdt_config_t*)'
Switch to a #if ESP_IDF_VERSION_MAJOR >= 5 guard so both core
versions build. The 5.x branch fills out the config struct with
timeout_ms = 30000, idle_core_mask = 0 (we manually subscribe our
two pinned tasks), trigger_panic = true.
https://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR improves the reliability of speed data collection from the STM32 radar sensor and performs significant cleanup of unused variables and reserved flags throughout the codebase.
Key Changes
Radar Polling Improvements:
get_speed()to drain stale bytes from the serial buffer before issuing new commands, preventing data lag where responses were always one cycle behindavailable()check to blockingparseFloat()with a 50ms timeout, ensuring complete responses are receivedspeedvariable type frominttofloatto preserve the 0.1 resolution provided by the STM32Variable Cleanup:
API_photo,send_API,photo_finished,send_alert,sleep_idle_timelabelWifi,button1,switchOne,statuslastTime,display_wifi,apIP,DNS_PORTconstantsmaxSpeedfrominttofloatto match STM32's 0.1 resolution and updated documentationdnsServerdeclaration from.inotovariables.hfor better organizationCode Quality Improvements:
sendPhoto()(was reservinghttpsRequestDatabut usinghttpsRequestSend)buttonSaveNetworkCall()by renaming local variablessendPhoto()to keep wire format clean (e.g., "25" instead of "25.70")Notable Implementation Details
get_speed()is critical for maintaining synchronization with the STM32's response streamhttps://claude.ai/code/session_01AfFtNmP3SFYS9HwhkkhR54