Skip to content

feat(captive-portal): full setup wizard, REST API migration, and WiFi CRUD overhaul#426

Merged
hhvrc merged 21 commits intodevelopfrom
feat/wifi-crud-fixes-and-advanced-mode
Mar 24, 2026
Merged

feat(captive-portal): full setup wizard, REST API migration, and WiFi CRUD overhaul#426
hhvrc merged 21 commits intodevelopfrom
feat/wifi-crud-fixes-and-advanced-mode

Conversation

@hhvrc
Copy link
Contributor

@hhvrc hhvrc commented Mar 3, 2026

Summary

Captive Portal REST API Migration

  • Migrated all LocalToHub WebSocket commands to HTTP REST endpoints (WiFi, Account, EStop, RF pin, OTA settings)
  • Removed 19 obsolete WS handler files and cleaned up the FlatBuffers dispatcher
  • Made AccountLinkResultCode and SetGPIOResultCode standalone enums (no longer depend on FlatBuffers-generated types)
  • Extracted ShockerCommandList handler into a shared function used by both gateway and local WS dispatchers
  • Added HTTP::ContentType constants header for reuse across the codebase
  • JSON error responses use {"error":"..."} format — success returns 200 with no body

Setup Wizard (Guided Mode)

  • Landing page with Guided Setup / Advanced Setup selection
  • Multi-step stepper wizard: Pins (DIY only) → Test Shocker → WiFi → Account
  • Shocker test step sends vibrate commands over WebSocket using ShockerCommandList FlatBuffers
  • Account step shows WiFi connection status, linked state with re-link option
  • Portal close is now a soft signal (SetUserDone) — portal stays open until device is fully online
  • 5-minute auto-close timer when no WebSocket clients are connected and gateway is up

Advanced Mode

  • Settings-app style navigation with vertical section list (WiFi, Shocker, Hardware, Account, Updates)
  • Each section opens full-width with back navigation
  • Reuses same components as guided mode where applicable

WiFi Improvements

  • WiFi.begin(ssid, password) — removed all BSSID-based connection logic, enabling hidden network support
  • Auth mode pinning: saved on credential creation, validated before connecting (rejects weaker security)
  • BSSID pinning support in config (opt-in via serial for advanced users)
  • WifiNetworkEvent::Saved/Removed now fires for hidden/out-of-range networks too
  • WifiNetworkEvent::Disconnected always fires (even after forget) so the UI stays in sync
  • WiFiManager task stack increased to 4096 bytes
  • Immediate scan status broadcast on REST scan request for responsive UI

FlatBuffers Schema Updates

  • Added MacAddress struct and auth_mode/bssid fields to WiFiCredentials
  • Added AccountLinkStatusEvent to HubToLocalMessage — broadcast when gateway validates auth token
  • Moved ShockerCommand to Common namespace, shared between gateway and local messages

Frontend

  • Svelte 5 reactivity fix: Map mutations in HubStateStore now trigger re-renders
  • Split App.svelte into views/Landing, views/Guided, views/Advanced, views/Success
  • savedOnlySSIDs derived from config for networks not in scan range
  • WiFiEntry component handles both scanned and config-only networks
  • Hidden network dialog includes security type selector
  • Removed light mode confirmation dialog and footer

Test plan

  • Flash firmware + filesystem, verify captive portal opens
  • Guided wizard: complete all steps (test shocker, connect WiFi, link account)
  • Advanced mode: navigate all sections, verify settings persist
  • Hidden network: add via dialog with security type, verify connect works
  • Forget connected network: verify WiFi disconnects and UI updates
  • Account already linked on boot: verify status shown on account step
  • Portal close: verify soft close waits for gateway, doesn't persist across reboots
  • Auto-close: verify 5-minute timer with no clients connected
  • All board variants build: pio run

fixes #421
fixes #411
fixes #400
fixes #145
fixes #45
fixes #27
fixes #26

Firmware: WiFiManager::Save() and Forget() no longer require the network
to be in scan results, enabling hidden network support and forgetting
out-of-range networks. The connect field from WifiNetworkSaveCommand is
now passed through to the handler.

Frontend: Replace the flat config page with a stepper wizard (WiFi ->
Hardware -> Account) as the default view. Add an Advanced mode toggle in
the header that shows a flat page with all config sections including new
OTA, Backend, and Captive Portal settings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Mar 3, 2026

⚠️ No Changeset found

Latest commit: 1959c0e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Cpp-Linter Report ⚠️

Some files did not pass the configured checks!

clang-format (v21.1.8) reports: 15 file(s) not formatted
  • include/config/WiFiCredentials.h
  • include/serialization/_fbs/GatewayToHubMessage_generated.h
  • include/serialization/_fbs/HubConfig_generated.h
  • include/serialization/_fbs/HubToLocalMessage_generated.h
  • include/serialization/_fbs/LocalToHubMessage_generated.h
  • include/serialization/_fbs/ShockerCommand_generated.h
  • src/GatewayConnectionManager.cpp
  • src/captiveportal/CaptivePortalInstance.cpp
  • src/captiveportal/Manager.cpp
  • src/config/Config.cpp
  • src/config/WiFiCredentials.cpp
  • src/message_handlers/ShockerCommandList.cpp
  • src/serialization/WSLocal.cpp
  • src/wifi/WiFiManager.cpp
  • src/wifi/WiFiScanManager.cpp
clang-tidy (v21.1.8) reports: 1236 concern(s)
  • include/AccountLinkResultCode.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/AccountLinkResultCode.h:3:10: error: [clang-diagnostic-error]

    'cstdint' file not found

        3 | #include <cstdint>
          |          ^~~~~~~~~
  • include/AccountLinkResultCode.h:6:14: warning: [performance-enum-size]

    enum 'AccountLinkResultCode' uses a larger base type ('int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size

        6 |   enum class AccountLinkResultCode : uint8_t {
          |              ^
  • include/SetGPIOResultCode.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/SetGPIOResultCode.h:3:10: error: [clang-diagnostic-error]

    'cstdint' file not found

        3 | #include <cstdint>
          |          ^~~~~~~~~
  • include/SetGPIOResultCode.h:6:14: warning: [performance-enum-size]

    enum 'SetGPIOResultCode' uses a larger base type ('int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size

        6 |   enum class SetGPIOResultCode : uint8_t {
          |              ^
  • include/captiveportal/CaptivePortalInstance.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/captiveportal/CaptivePortalInstance.h:20:5: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       20 |     DISABLE_COPY(CaptivePortalInstance);
          |     ^
    include/Common.h:9:13: note: expanded from macro 'DISABLE_COPY'
        9 |   TypeName& operator=(const TypeName&) = delete
          |             ^
  • include/captiveportal/CaptivePortalInstance.h:21:5: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       21 |     DISABLE_MOVE(CaptivePortalInstance);
          |     ^
    include/Common.h:12:13: note: expanded from macro 'DISABLE_MOVE'
       12 |   TypeName& operator=(TypeName&&) = delete
          |             ^
  • include/captiveportal/CaptivePortalInstance.h:27:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       27 |     bool sendMessageTXT(uint8_t socketId, std::string_view data) { return m_socketServer.sendTXT(socketId, data.data(), data.length()); }
          |     ~~~~ ^
          |     auto                                                         -> bool
  • include/captiveportal/CaptivePortalInstance.h:27:25: warning: [bugprone-easily-swappable-parameters]

    2 adjacent parameters of 'sendMessageTXT' of similar type ('int') are easily swapped by mistake

       27 |     bool sendMessageTXT(uint8_t socketId, std::string_view data) { return m_socketServer.sendTXT(socketId, data.data(), data.length()); }
          |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/runner/work/Firmware/Firmware/include/captiveportal/CaptivePortalInstance.h:27:33: note: the first parameter in the range is 'socketId'
       27 |     bool sendMessageTXT(uint8_t socketId, std::string_view data) { return m_socketServer.sendTXT(socketId, data.data(), data.length()); }
          |                                 ^~~~~~~~
    /home/runner/work/Firmware/Firmware/include/captiveportal/CaptivePortalInstance.h:27:60: note: the last parameter in the range is 'data'
       27 |     bool sendMessageTXT(uint8_t socketId, std::string_view data) { return m_socketServer.sendTXT(socketId, data.data(), data.length()); }
          |                                                            ^~~~
  • include/captiveportal/CaptivePortalInstance.h:28:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       28 |     bool sendMessageBIN(uint8_t socketId, tcb::span<const uint8_t> data) { return m_socketServer.sendBIN(socketId, data.data(), data.size()); }
          |     ~~~~ ^
          |     auto                                                                 -> bool
  • include/captiveportal/CaptivePortalInstance.h:28:25: warning: [bugprone-easily-swappable-parameters]

    2 adjacent parameters of 'sendMessageBIN' of similar type ('int') are easily swapped by mistake

       28 |     bool sendMessageBIN(uint8_t socketId, tcb::span<const uint8_t> data) { return m_socketServer.sendBIN(socketId, data.data(), data.size()); }
          |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/runner/work/Firmware/Firmware/include/captiveportal/CaptivePortalInstance.h:28:33: note: the first parameter in the range is 'socketId'
       28 |     bool sendMessageBIN(uint8_t socketId, tcb::span<const uint8_t> data) { return m_socketServer.sendBIN(socketId, data.data(), data.size()); }
          |                                 ^~~~~~~~
    /home/runner/work/Firmware/Firmware/include/captiveportal/CaptivePortalInstance.h:28:68: note: the last parameter in the range is 'data'
       28 |     bool sendMessageBIN(uint8_t socketId, tcb::span<const uint8_t> data) { return m_socketServer.sendBIN(socketId, data.data(), data.size()); }
          |                                                                    ^~~~
  • include/captiveportal/CaptivePortalInstance.h:29:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       29 |     bool broadcastMessageTXT(std::string_view data) { return m_socketServer.broadcastTXT(data.data(), data.length()); }
          |     ~~~~ ^
          |     auto                                            -> bool
  • include/captiveportal/CaptivePortalInstance.h:30:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       30 |     bool broadcastMessageBIN(tcb::span<const uint8_t> data) { return m_socketServer.broadcastBIN(data.data(), data.size()); }
          |     ~~~~ ^
          |     auto                                                    -> bool
  • include/captiveportal/CaptivePortalInstance.h:31:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       31 |     bool hasClients() { return m_socketServer.connectedClients() > 0; }
          |     ~~~~ ^
          |     auto              -> bool
  • include/captiveportal/Manager.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/captiveportal/Manager.h:3:10: error: [clang-diagnostic-error]

    'cstdint' file not found

        3 | #include <cstdint>
          |          ^~~~~~~~~
  • include/captiveportal/Manager.h:9:22: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

        9 |   [[nodiscard]] bool Init();
          |                 ~~~~ ^     
          |                 auto        -> bool
  • include/captiveportal/Manager.h:12:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       12 |   bool IsAlwaysEnabled();
          |   ~~~~ ^                
          |   auto                   -> bool
  • include/captiveportal/Manager.h:17:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       17 |   bool ForceClose(uint32_t timeoutMs);
          |   ~~~~ ^                             
          |   auto                                -> bool
  • include/captiveportal/Manager.h:19:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       19 |   bool IsRunning();
          |   ~~~~ ^          
          |   auto             -> bool
  • include/captiveportal/Manager.h:21:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       21 |   bool SendMessageTXT(uint8_t socketId, std::string_view data);
          |   ~~~~ ^                                                      
          |   auto                                                         -> bool
  • include/captiveportal/Manager.h:22:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       22 |   bool SendMessageBIN(uint8_t socketId, tcb::span<const uint8_t> data);
          |   ~~~~ ^                                                              
          |   auto                                                                 -> bool
  • include/captiveportal/Manager.h:24:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       24 |   bool BroadcastMessageTXT(std::string_view data);
          |   ~~~~ ^                                         
          |   auto                                            -> bool
  • include/captiveportal/Manager.h:25:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       25 |   bool BroadcastMessageBIN(tcb::span<const uint8_t> data);
          |   ~~~~ ^                                                 
          |   auto                                                    -> bool
  • include/config/Config.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/config/Config.h:23:15: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       23 |   std::string GetAsJSON(bool withSensitiveData);
          |               ^
  • include/config/Config.h:24:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       24 |   bool SaveFromJSON(std::string_view json);
          |   ~~~~ ^                                  
          |   auto                                     -> bool
  • include/config/Config.h:27:78: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       27 |   [[nodiscard]] flatbuffers::Offset<Serialization::Configuration::HubConfig> GetAsFlatBuffer(flatbuffers::FlatBufferBuilder& builder, bool withSensitiveData);
          |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^                                                                               
          |                 auto                                                                                                                                          -> flatbuffers::Offset<Serialization::Configuration::HubConfig>
  • include/config/Config.h:28:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       28 |   bool SaveFromFlatBuffer(const Serialization::Configuration::HubConfig* config);
          |   ~~~~ ^                                                                        
          |   auto                                                                           -> bool
  • include/config/Config.h:31:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       31 |   bool GetRaw(TinyVec<uint8_t>& buffer);
          |   ~~~~ ^                               
          |   auto                                  -> bool
  • include/config/Config.h:32:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       32 |   bool SetRaw(const uint8_t* buffer, std::size_t size);
          |   ~~~~ ^                                              
          |   auto                                                 -> bool
  • include/config/Config.h:41:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       41 |   bool GetRFConfig(RFConfig& out);
          |   ~~~~ ^                         
          |   auto                            -> bool
  • include/config/Config.h:42:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       42 |   bool GetWiFiConfig(WiFiConfig& out);
          |   ~~~~ ^                             
          |   auto                                -> bool
  • include/config/Config.h:43:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       43 |   bool GetCaptivePortalConfig(CaptivePortalConfig& out);
          |   ~~~~ ^                                               
          |   auto                                                  -> bool
  • include/config/Config.h:44:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       44 |   bool GetBackendConfig(BackendConfig& out);
          |   ~~~~ ^                                   
          |   auto                                      -> bool
  • include/config/Config.h:45:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       45 |   bool GetSerialInputConfig(SerialInputConfig& out);
          |   ~~~~ ^                                           
          |   auto                                              -> bool
  • include/config/Config.h:46:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       46 |   bool GetOtaUpdateConfig(OtaUpdateConfig& out);
          |   ~~~~ ^                                       
          |   auto                                          -> bool
  • include/config/Config.h:47:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       47 |   bool GetEStop(EStopConfig& out);
          |   ~~~~ ^                         
          |   auto                            -> bool
  • include/config/Config.h:49:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       49 |   bool SetRFConfig(const RFConfig& config);
          |   ~~~~ ^                                  
          |   auto                                     -> bool
  • include/config/Config.h:50:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       50 |   bool SetWiFiConfig(const WiFiConfig& config);
          |   ~~~~ ^                                      
          |   auto                                         -> bool
  • include/config/Config.h:51:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       51 |   bool SetCaptivePortalConfig(const CaptivePortalConfig& config);
          |   ~~~~ ^                                                        
          |   auto                                                           -> bool
  • include/config/Config.h:52:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       52 |   bool SetBackendConfig(const BackendConfig& config);
          |   ~~~~ ^                                            
          |   auto                                               -> bool
  • include/config/Config.h:53:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       53 |   bool SetSerialInputConfig(const SerialInputConfig& config);
          |   ~~~~ ^                                                    
          |   auto                                                       -> bool
  • include/config/Config.h:54:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       54 |   bool SetOtaUpdateConfig(const OtaUpdateConfig& config);
          |   ~~~~ ^                                                
          |   auto                                                   -> bool
  • include/config/Config.h:55:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       55 |   bool SetEStop(const EStopConfig& config);
          |   ~~~~ ^                                  
          |   auto                                     -> bool
  • include/config/Config.h:57:8: warning: [bugprone-dynamic-static-initializers]

    static variable 'GetWiFiCredentials' may be dynamically initialized in this header file

       57 |   bool GetWiFiCredentials(std::vector<WiFiCredentials>& out);
          |        ^
  • include/config/Config.h:57:8: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'GetWiFiCredentials' is non-const and globally accessible, consider making it const

  • include/config/Config.h:58:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       58 |   bool GetWiFiCredentials(cJSON* array, bool withSensitiveData);
          |   ~~~~ ^                                                       
          |   auto                                                          -> bool
  • include/config/Config.h:59:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       59 |   bool SetWiFiCredentials(const std::vector<WiFiCredentials>& credentials);
          |   ~~~~ ^                                                                  
          |   auto                                                                     -> bool
  • include/config/Config.h:61:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       61 |   bool GetRFConfigTxPin(gpio_num_t& out);
          |   ~~~~ ^                                
          |   auto                                   -> bool
  • include/config/Config.h:62:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       62 |   bool SetRFConfigTxPin(gpio_num_t txPin);
          |   ~~~~ ^                                 
          |   auto                                    -> bool
  • include/config/Config.h:63:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       63 |   bool GetRFConfigKeepAliveEnabled(bool& out);
          |   ~~~~ ^                                     
          |   auto                                        -> bool
  • include/config/Config.h:64:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       64 |   bool SetRFConfigKeepAliveEnabled(bool enabled);
          |   ~~~~ ^                                        
          |   auto                                           -> bool
  • include/config/Config.h:66:8: warning: [bugprone-dynamic-static-initializers]

    static variable 'AnyWiFiCredentials' may be dynamically initialized in this header file

       66 |   bool AnyWiFiCredentials(std::function<bool(const Config::WiFiCredentials&)> predicate);
          |        ^
  • include/config/Config.h:66:8: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'AnyWiFiCredentials' is non-const and globally accessible, consider making it const

  • include/config/Config.h:67:11: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       67 |   uint8_t AddWiFiCredentials(std::string_view ssid, std::string_view password, wifi_auth_mode_t authMode = WIFI_AUTH_MAX);
          |           ^
  • include/config/Config.h:68:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       68 |   bool TryGetWiFiCredentialsByID(uint8_t id, WiFiCredentials& out);
          |   ~~~~ ^                                                          
          |   auto                                                             -> bool
  • include/config/Config.h:68:42: warning: [readability-identifier-length]

    parameter name 'id' is too short, expected at least 3 characters

       68 |   bool TryGetWiFiCredentialsByID(uint8_t id, WiFiCredentials& out);
          |                                          ^
  • include/config/Config.h:69:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       69 |   bool TryGetWiFiCredentialsBySSID(const char* ssid, WiFiCredentials& out);
          |   ~~~~ ^                                                                  
          |   auto                                                                     -> bool
  • include/config/Config.h:70:11: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       70 |   uint8_t GetWiFiCredentialsIDbySSID(const char* ssid);
          |           ^
  • include/config/Config.h:71:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       71 |   bool PinWiFiCredentialsBSSID(uint8_t id, const uint8_t (&bssid)[6]);
          |   ~~~~ ^                                                             
          |   auto                                                                -> bool
  • include/config/Config.h:71:40: warning: [readability-identifier-length]

    parameter name 'id' is too short, expected at least 3 characters

       71 |   bool PinWiFiCredentialsBSSID(uint8_t id, const uint8_t (&bssid)[6]);
          |                                        ^
  • include/config/Config.h:71:66: warning: [cppcoreguidelines-avoid-c-arrays]

    do not declare C-style arrays, use 'std::array' instead

       71 |   bool PinWiFiCredentialsBSSID(uint8_t id, const uint8_t (&bssid)[6]);
          |                                                                  ^
  • include/config/Config.h:71:67: warning: [cppcoreguidelines-avoid-magic-numbers]

    6 is a magic number; consider replacing it with a named constant

       71 |   bool PinWiFiCredentialsBSSID(uint8_t id, const uint8_t (&bssid)[6]);
          |                                                                   ^
  • include/config/Config.h:72:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       72 |   bool RemoveWiFiCredentials(uint8_t id);
          |   ~~~~ ^                                
          |   auto                                   -> bool
  • include/config/Config.h:72:38: warning: [readability-identifier-length]

    parameter name 'id' is too short, expected at least 3 characters

       72 |   bool RemoveWiFiCredentials(uint8_t id);
          |                                      ^
  • include/config/Config.h:73:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       73 |   bool ClearWiFiCredentials();
          |   ~~~~ ^                     
          |   auto                        -> bool
  • include/config/Config.h:74:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       74 |   bool GetWiFiHostname(std::string& out);
          |   ~~~~ ^                                
          |   auto                                   -> bool
  • include/config/Config.h:75:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       75 |   bool SetWiFiHostname(std::string hostname);
          |   ~~~~ ^                                    
          |   auto                                       -> bool
  • include/config/Config.h:77:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       77 |   bool GetBackendDomain(std::string& out);
          |   ~~~~ ^                                 
          |   auto                                    -> bool
  • include/config/Config.h:78:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       78 |   bool SetBackendDomain(std::string domain);
          |   ~~~~ ^                                   
          |   auto                                      -> bool
  • include/config/Config.h:79:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       79 |   bool HasBackendAuthToken();
          |   ~~~~ ^                    
          |   auto                       -> bool
  • include/config/Config.h:80:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       80 |   bool GetBackendAuthToken(std::string& out);
          |   ~~~~ ^                                    
          |   auto                                       -> bool
  • include/config/Config.h:81:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       81 |   bool SetBackendAuthToken(std::string token);
          |   ~~~~ ^                                     
          |   auto                                        -> bool
  • include/config/Config.h:82:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       82 |   bool ClearBackendAuthToken();
          |   ~~~~ ^                      
          |   auto                         -> bool
  • include/config/Config.h:84:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       84 |   bool GetSerialInputConfigEchoEnabled(bool& out);
          |   ~~~~ ^                                         
          |   auto                                            -> bool
  • include/config/Config.h:85:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       85 |   bool SetSerialInputConfigEchoEnabled(bool enabled);
          |   ~~~~ ^                                            
          |   auto                                               -> bool
  • include/config/Config.h:87:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       87 |   bool GetOtaUpdateId(int32_t& out);
          |   ~~~~ ^                           
          |   auto                              -> bool
  • include/config/Config.h:88:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       88 |   bool SetOtaUpdateId(int32_t updateId);
          |   ~~~~ ^                               
          |   auto                                  -> bool
  • include/config/Config.h:89:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       89 |   bool GetOtaUpdateStep(OtaUpdateStep& out);
          |   ~~~~ ^                                   
          |   auto                                      -> bool
  • include/config/Config.h:90:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       90 |   bool SetOtaUpdateStep(OtaUpdateStep updateStep);
          |   ~~~~ ^                                         
          |   auto                                            -> bool
  • include/config/Config.h:92:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       92 |   bool GetEStopEnabled(bool& out);
          |   ~~~~ ^                         
          |   auto                            -> bool
  • include/config/Config.h:93:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       93 |   bool SetEStopEnabled(bool enabled);
          |   ~~~~ ^                            
          |   auto                               -> bool
  • include/config/Config.h:94:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       94 |   bool GetEStopGpioPin(gpio_num_t& out);
          |   ~~~~ ^                               
          |   auto                                  -> bool
  • include/config/Config.h:95:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       95 |   bool SetEStopGpioPin(gpio_num_t gpioPin);
          |   ~~~~ ^                                  
          |   auto                                     -> bool
  • include/config/WiFiCredentials.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/config/WiFiCredentials.h:16:29: warning: [readability-identifier-length]

    parameter name 'id' is too short, expected at least 3 characters

       16 |     WiFiCredentials(uint8_t id, std::string_view ssid, std::string_view password, wifi_auth_mode_t authMode = WIFI_AUTH_MAX);
          |                             ^
  • include/config/WiFiCredentials.h:24:5: warning: [modernize-use-nodiscard]

    function 'HasPinnedBSSID' should be marked [[nodiscard]]

       24 |     bool HasPinnedBSSID() const;
          |     ^
          |     [[nodiscard]] 
  • include/config/WiFiCredentials.h:24:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       24 |     bool HasPinnedBSSID() const;
          |     ~~~~ ^                     
          |     auto                        -> bool
  • include/config/WiFiCredentials.h:28:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       28 |     bool FromFlatbuffers(const Serialization::Configuration::WiFiCredentials* config) override;
          |     ~~~~ ^
          |     auto                                                                              -> bool
  • include/config/WiFiCredentials.h:29:86: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       29 |     [[nodiscard]] flatbuffers::Offset<Serialization::Configuration::WiFiCredentials> ToFlatbuffers(flatbuffers::FlatBufferBuilder& builder, bool withSensitiveData) const override;
          |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
          |                   auto                                                                                                                                                    -> flatbuffers::Offset<Serialization::Configuration::WiFiCredentials>
  • include/config/WiFiCredentials.h:31:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       31 |     bool FromJSON(const cJSON* json) override;
          |     ~~~~ ^
          |     auto                             -> bool
  • include/config/WiFiCredentials.h:32:26: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       32 |     [[nodiscard]] cJSON* ToJSON(bool withSensitiveData) const override;
          |                   ~~~~~~ ^
          |                   auto                                        -> cJSON*
  • include/message_handlers/ShockerCommandList.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/message_handlers/impl/WSLocal.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/message_handlers/impl/WSLocal.h:8:9: warning: [cppcoreguidelines-macro-usage]

    function-like macro 'HANDLER_SIG' used; consider a 'constexpr' template function

        8 | #define HANDLER_SIG(NAME) void NAME(uint8_t socketId, const OpenShock::Serialization::Local::LocalToHubMessage* msg)
          |         ^
  • include/message_handlers/impl/WSLocal.h:11:46: warning: [bugprone-reserved-identifier]

    declaration uses identifier '_Private', which is a reserved identifier

       11 | namespace OpenShock::MessageHandlers::Local::_Private {
          |                                              ^~~~~~~~
          |                                              Private
  • include/message_handlers/impl/WSLocal.h:12:3: warning: [modernize-use-using]

    use 'using' instead of 'typedef'

       12 |   typedef HANDLER_SIG((*HandlerType));
          |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          |   using HandlerType = HANDLER_SIG((*HandlerType))
  • include/serialization/WSLocal.h:1:1: warning: [portability-avoid-pragma-once]

    avoid 'pragma once' directive; use include guards instead

        1 | #pragma once
          | ^
  • include/serialization/WSLocal.h:17:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       17 |   bool SerializeErrorMessage(std::string_view message, Common::SerializationCallbackFn callback);
          |   ~~~~ ^                                                                                        
          |   auto                                                                                           -> bool
  • include/serialization/WSLocal.h:18:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       18 |   bool SerializeReadyMessage(const WiFiNetwork* connectedNetwork, bool accountLinked, Common::SerializationCallbackFn callback);
          |   ~~~~ ^                                                                                                                       
          |   auto                                                                                                                          -> bool
  • include/serialization/WSLocal.h:19:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       19 |   bool SerializeWiFiScanStatusChangedEvent(OpenShock::WiFiScanStatus status, Common::SerializationCallbackFn callback);
          |   ~~~~ ^                                                                                                              
          |   auto                                                                                                                 -> bool
  • include/serialization/WSLocal.h:20:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       20 |   bool SerializeWiFiNetworkEvent(Types::WifiNetworkEventType eventType, const WiFiNetwork& network, Common::SerializationCallbackFn callback);
          |   ~~~~ ^                                                                                                                                     
          |   auto                                                                                                                                        -> bool
  • include/serialization/WSLocal.h:21:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       21 |   bool SerializeWiFiNetworksEvent(Types::WifiNetworkEventType eventType, const std::vector<WiFiNetwork>& networks, Common::SerializationCallbackFn callback);
          |   ~~~~ ^                                                                                                                                                    
          |   auto                                                                                                                                                       -> bool
  • include/serialization/WSLocal.h:22:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       22 |   bool SerializeWiFiGotIpEvent(const char* ip, Common::SerializationCallbackFn callback);
          |   ~~~~ ^                                                                                
          |   auto                                                                                   -> bool
  • include/serialization/WSLocal.h:22:44: warning: [readability-identifier-length]

    parameter name 'ip' is too short, expected at least 3 characters

       22 |   bool SerializeWiFiGotIpEvent(const char* ip, Common::SerializationCallbackFn callback);
          |                                            ^
  • include/serialization/WSLocal.h:23:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       23 |   bool SerializeAccountLinkStatusEvent(bool linked, Common::SerializationCallbackFn callback);
          |   ~~~~ ^                                                                                     
          |   auto                                                                                        -> bool
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:11:44: warning: [cppcoreguidelines-avoid-magic-numbers]

    25 is a magic number; consider replacing it with a named constant

       11 | static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
          |                                            ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:12:44: warning: [cppcoreguidelines-avoid-magic-numbers]

    12 is a magic number; consider replacing it with a named constant

       12 |               FLATBUFFERS_VERSION_MINOR == 12 &&
          |                                            ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:13:47: warning: [cppcoreguidelines-avoid-magic-numbers]

    19 is a magic number; consider replacing it with a named constant

       13 |               FLATBUFFERS_VERSION_REVISION == 19,
          |                                               ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:19:1: warning: [modernize-concat-nested-namespaces]

    nested namespaces can be concatenated

       19 | namespace OpenShock {
          | ^~~~~~~~~~~~~~~~~~~~~
       20 | namespace Serialization {
          | ~~~~~~~~~~~~~~~~~~~~~~~~~
       21 | namespace Gateway {
          | ~~~~~~~~~~~~~~~~~
          | namespace OpenShock::Serialization::Gateway
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:35:12: warning: [performance-enum-size]

    enum 'TriggerType' uses a larger base type ('int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size

       35 | enum class TriggerType : uint8_t {
          |            ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:48:14: warning: [cppcoreguidelines-avoid-c-arrays]

    do not declare C-style arrays, use 'std::array' instead

       48 | inline const TriggerType (&EnumValuesTriggerType())[4] {
          |              ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:48:28: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       48 | inline const TriggerType (&EnumValuesTriggerType())[4] {
          |                            ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:49:16: warning: [cppcoreguidelines-avoid-c-arrays]

    do not declare C-style arrays, use 'std::array' instead

       49 |   static const TriggerType values[] = {
          |                ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:58:28: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       58 | inline const char * const *EnumNamesTriggerType() {
          |        ~~~~~~~~~~~~~~~~~~~~^
          |        auto                                       -> const char * const *
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:59:16: warning: [cppcoreguidelines-avoid-c-arrays]

    do not declare C-style arrays, use 'std::array' instead

       59 |   static const char * const names[5] = {
          |                ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:66:10: warning: [cppcoreguidelines-pro-bounds-array-to-pointer-decay]

    do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead

       66 |   return names;
          |          ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:69:20: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       69 | inline const char *EnumNameTriggerType(TriggerType e) {
          |        ~~~~~~~~~~~~^
          |        auto                                           -> const char *
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:69:52: warning: [readability-identifier-length]

    parameter name 'e' is too short, expected at least 3 characters

       69 | inline const char *EnumNameTriggerType(TriggerType e) {
          |                                                    ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:70:93: warning: [readability-braces-around-statements]

    statement should be inside braces

       70 |   if (::flatbuffers::IsOutRange(e, TriggerType::Restart, TriggerType::CaptivePortalDisable)) return "";
          |                                                                                             ^          
          |                                                                                              {
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:71:9: warning: [modernize-use-auto]

    use auto when initializing with a cast to avoid duplicating the type name

       71 |   const size_t index = static_cast<size_t>(e);
          |         ^~~~~~
          |         auto
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:72:10: warning: [cppcoreguidelines-pro-bounds-pointer-arithmetic]

    do not use pointer arithmetic

       72 |   return EnumNamesTriggerType()[index];
          |          ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:75:12: warning: [performance-enum-size]

    enum 'GatewayToHubMessagePayload' uses a larger base type ('int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size

       75 | enum class GatewayToHubMessagePayload : uint8_t {
          |            ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:89:14: warning: [cppcoreguidelines-avoid-c-arrays]

    do not declare C-style arrays, use 'std::array' instead

       89 | inline const GatewayToHubMessagePayload (&EnumValuesGatewayToHubMessagePayload())[5] {
          |              ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:89:43: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       89 | inline const GatewayToHubMessagePayload (&EnumValuesGatewayToHubMessagePayload())[5] {
          |                                           ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:89:83: warning: [cppcoreguidelines-avoid-magic-numbers]

    5 is a magic number; consider replacing it with a named constant

       89 | inline const GatewayToHubMessagePayload (&EnumValuesGatewayToHubMessagePayload())[5] {
          |                                                                                   ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:90:16: warning: [cppcoreguidelines-avoid-c-arrays]

    do not declare C-style arrays, use 'std::array' instead

       90 |   static const GatewayToHubMessagePayload values[] = {
          |                ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:100:28: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      100 | inline const char * const *EnumNamesGatewayToHubMessagePayload() {
          |        ~~~~~~~~~~~~~~~~~~~~^
          |        auto                                                      -> const char * const *
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:101:16: warning: [cppcoreguidelines-avoid-c-arrays]

    do not declare C-style arrays, use 'std::array' instead

      101 |   static const char * const names[6] = {
          |                ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:109:10: warning: [cppcoreguidelines-pro-bounds-array-to-pointer-decay]

    do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead

      109 |   return names;
          |          ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:112:20: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      112 | inline const char *EnumNameGatewayToHubMessagePayload(GatewayToHubMessagePayload e) {
          |        ~~~~~~~~~~~~^
          |        auto                                                                         -> const char *
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:112:82: warning: [readability-identifier-length]

    parameter name 'e' is too short, expected at least 3 characters

      112 | inline const char *EnumNameGatewayToHubMessagePayload(GatewayToHubMessagePayload e) {
          |                                                                                  ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:113:116: warning: [readability-braces-around-statements]

    statement should be inside braces

      113 |   if (::flatbuffers::IsOutRange(e, GatewayToHubMessagePayload::NONE, GatewayToHubMessagePayload::OtaUpdateRequest)) return "";
          |                                                                                                                    ^          
          |                                                                                                                     {
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:114:9: warning: [modernize-use-auto]

    use auto when initializing with a cast to avoid duplicating the type name

      114 |   const size_t index = static_cast<size_t>(e);
          |         ^~~~~~
          |         auto
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:115:10: warning: [cppcoreguidelines-pro-bounds-pointer-arithmetic]

    do not use pointer arithmetic

      115 |   return EnumNamesGatewayToHubMessagePayload()[index];
          |          ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:139:6: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      139 | bool VerifyGatewayToHubMessagePayload(::flatbuffers::VerifierTemplate<B> &verifier, const void *obj, GatewayToHubMessagePayload type);
          | ~~~~ ^                                                                                                                               
          | auto                                                                                                                                  -> bool
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:141:6: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      141 | bool VerifyGatewayToHubMessagePayloadVector(::flatbuffers::VerifierTemplate<B> &verifier, const ::flatbuffers::Vector<::flatbuffers::Offset<void>> *values, const ::flatbuffers::Vector<GatewayToHubMessagePayload> *types);
          | ~~~~ ^                                                                                                                                                                                                                     
          | auto                                                                                                                                                                                                                        -> bool
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:144:3: warning: [modernize-use-using]

    use 'using' instead of 'typedef'

      144 |   typedef PingBuilder Builder;
          |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
          |   using Builder = PingBuilder
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:146:50: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      146 |   static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() {
          |                                      ~~~~~~~~~~~~^
          |                                      auto                                -> const char *
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:149:8: warning: [cppcoreguidelines-use-enum-class]

    enum 'FlatBuffersVTableOffset' is unscoped, use 'enum class' instead

      149 |   enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
          |        ^
  • include/serialization/_fbs/GatewayToHubMessage_generated.h:149:8: warning: [performance-enum-size]

    enum 'FlatBuffersVTableOffset' uses a larger base type ('::flatbuffers::voffset_t' (aka 'int'), size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size

  • include/serialization/_fbs/GatewayToHubMessage_generated.h:152:3: warning: [modernize-use-nodiscard]

    function 'unix_utc_time' should be marked [[nodiscard]]

      152 |   uint64_t unix_utc_time() const {
          |   ^
          |   [[nodiscard]] 
  • src/wifi/WiFiScanManager.cpp:77:9: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

Have any feedback or feature suggestions? Share it here.

hhvrc and others added 6 commits March 6, 2026 13:26
…es-and-advanced-mode

# Conflicts:
#	frontend/eslint.config.js
#	frontend/src/lib/components/Layout/Header.svelte
#	frontend/src/lib/components/WiFiEntry.svelte
#	frontend/src/lib/stores/index.ts
#	frontend/src/routes/+page.svelte
#	src/wifi/WiFiManager.cpp
Replace FlatBuffers WebSocket round-trips with simple HTTP calls for:
- WiFi scan start/stop (POST /api/wifi/scan)
- WiFi network forget (DELETE /api/wifi/networks)
- Account link/unlink (POST /api/account/link, DELETE /api/account)
- RF TX pin config (PUT /api/config/rf/pin)
- EStop pin config (PUT /api/config/estop/pin)
- EStop enabled toggle (PUT /api/config/estop/enabled)

Commands that require async push events (WiFi connect/save/disconnect, OTA)
remain on WebSocket. Real-time push (scan results, WiFi events) also stays WS.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Leftover from merge conflict resolution — variable was renamed during
the develop merge but the reference wasn't updated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All frontend→firmware commands now use HTTP endpoints. The WebSocket
channel in the captive portal is now receive-only (firmware→frontend push):
- WiFi network save (POST /api/wifi/networks)
- WiFi network connect (POST /api/wifi/connect)
- WiFi network disconnect (POST /api/wifi/disconnect)
- OTA config endpoints (PUT /api/ota/*)
- OTA check for updates (POST /api/ota/check)

LocalToHubMessage FlatBuffers union is now empty — schema cleanup
documented in FLATBUFFERS_CHANGES.md.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
@hhvrc hhvrc marked this pull request as draft March 6, 2026 23:05
@hhvrc hhvrc changed the title Fix WiFi CRUD for hidden networks, add stepper wizard and advanced mode feat(captive-portal): full setup wizard, REST API migration, and WiFi CRUD overhaul Mar 23, 2026
@hhvrc hhvrc marked this pull request as ready for review March 23, 2026 23:27
@hhvrc hhvrc self-assigned this Mar 23, 2026
@hhvrc hhvrc moved this from Todo to In Review in Roadmap Mar 23, 2026
@hhvrc hhvrc added this to the 1.6.0 Release milestone Mar 23, 2026
hhvrc added 2 commits March 24, 2026 00:32
…S_CHANGES.md

CLAUDE.md: added captive portal REST API architecture, frontend structure,
FlatBuffers schema workflow, WS-to-REST migration goal, and conventions
for REST responses, cJSON usage, and Svelte 5 patterns.

FLATBUFFERS_CHANGES.md: updated to reflect applied changes rather than
planned changes.
@hhvrc hhvrc requested a review from Copilot March 23, 2026 23:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR delivers a major captive portal upgrade by migrating most Local↔Hub commands from WebSocket to REST, adding a guided setup wizard + advanced settings UI, and overhauling WiFi credential handling (auth-mode pinning, optional BSSID pinning, hidden networks).

Changes:

  • Migrates WiFi/Account/GPIO/OTA captive-portal operations from WS commands to REST, removing many local WS handlers and updating FlatBuffers payloads/unions.
  • Adds guided + advanced setup views in the frontend (stepper wizard, new sections, local-dev redirect helpers, “success” close flow).
  • Extends WiFi credentials (authMode + optional BSSID pin), adds new Hub→Local events (WiFiGotIp, AccountLinkStatus), and adjusts captive portal lifecycle (soft close, auto-close timer, startup grace).

Reviewed changes

Copilot reviewed 146 out of 161 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/wifi/WiFiScanManager.cpp Adjusts scan status notifications timing for more responsive UI updates.
src/serialization/WSLocal.cpp Adds serializers for new Hub→Local events (WiFiGotIp, AccountLinkStatus).
src/message_handlers/websocket/local/WiFiScanCommand.cpp Removes obsolete local WS WiFi scan command handler (migrated to REST).
src/message_handlers/websocket/local/WiFiNetworkSaveCommand.cpp Removes obsolete local WS WiFi save handler (migrated to REST).
src/message_handlers/websocket/local/WiFiNetworkForgetCommand.cpp Removes obsolete local WS WiFi forget handler (migrated to REST).
src/message_handlers/websocket/local/WiFiNetworkDisconnectCommand.cpp Removes obsolete local WS WiFi disconnect handler (migrated to REST).
src/message_handlers/websocket/local/WiFiNetworkConnectCommand.cpp Removes obsolete local WS WiFi connect handler (migrated to REST).
src/message_handlers/websocket/local/SetRfTxPinCommand.cpp Removes obsolete local WS RF pin handler (migrated to REST).
src/message_handlers/websocket/local/SetEStopPinCommand.cpp Removes obsolete local WS EStop pin handler (migrated to REST).
src/message_handlers/websocket/local/SetEStopEnabledCommand.cpp Removes obsolete local WS EStop enable handler (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateStartUpdateCommand.cpp Removes obsolete local WS OTA command handler stub (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateSetUpdateChannelCommand.cpp Removes obsolete local WS OTA channel handler stub (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateSetRequireManualApprovalCommand.cpp Removes obsolete local WS OTA manual-approval handler stub (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateSetIsEnabledCommand.cpp Removes obsolete local WS OTA enable handler stub (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateSetDomainCommand.cpp Removes obsolete local WS OTA domain handler stub (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateSetCheckIntervalCommand.cpp Removes obsolete local WS OTA interval handler stub (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateSetAllowBackendManagementCommand.cpp Removes obsolete local WS OTA backend-management handler stub (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateHandleUpdateRequestCommand.cpp Removes obsolete local WS OTA update-request handler stub (migrated to REST).
src/message_handlers/websocket/local/OtaUpdateCheckForUpdatesCommand.cpp Removes obsolete local WS OTA check handler stub (migrated to REST).
src/message_handlers/websocket/local/Common_ShockerCommandList.cpp Adds local WS handler for shared Common_ShockerCommandList payload.
src/message_handlers/websocket/local/AccountUnlinkCommand.cpp Removes obsolete local WS account unlink handler (migrated to REST).
src/message_handlers/websocket/local/AccountLinkCommand.cpp Removes obsolete local WS account link handler (migrated to REST).
src/message_handlers/websocket/gateway/ShockerCommandList.cpp Refactors gateway shocker command list handling into shared function.
src/message_handlers/websocket/Local.cpp Updates local WS dispatcher to only handle Common_ShockerCommandList.
src/message_handlers/websocket/Gateway.cpp Updates gateway WS dispatcher to use Common_ShockerCommandList payload key.
src/message_handlers/ShockerCommandList.cpp Adds shared shocker command list handler implementation.
src/config/WiFiCredentials.cpp Adds authMode + optional pinned BSSID to WiFi credentials (FlatBuffers + JSON).
src/config/Config.cpp Updates WiFi credential add flow to persist authMode and adds BSSID pin method.
src/captiveportal/RFC8908Handler.cpp Uses shared HTTP content-type constants for responses.
src/captiveportal/Manager.cpp Implements soft-close, startup grace, and auto-close timer behavior for portal.
src/GatewayConnectionManager.cpp Broadcasts AccountLinkStatusEvent upon auth token verification.
scripts/generate_schemas.py Improves flatc binary discovery across platforms (win32 vs others).
schemas Updates FlatBuffers schema submodule pointer.
include/wifi/WiFiManager.h Extends WiFiManager::Save signature (connect + authMode) and removes BSSID connect.
include/serialization/WSLocal.h Declares new Hub→Local serializers (WiFiGotIp, AccountLinkStatus).
include/message_handlers/impl/WSLocal.h Reduces local WS handler list to Common_ShockerCommandList only.
include/message_handlers/ShockerCommandList.h Declares shared shocker command list handler.
include/http/ContentTypes.h Adds reusable HTTP content-type string constants.
include/config/WiFiCredentials.h Extends WiFiCredentials struct with authMode and pinned BSSID.
include/config/Config.h Updates AddWiFiCredentials signature and adds PinWiFiCredentialsBSSID API.
include/captiveportal/Manager.h Adds SetUserDone API for soft portal close.
include/captiveportal/CaptivePortalInstance.h Adds hasClients() helper for auto-close logic.
include/SetGPIOResultCode.h Makes SetGPIOResultCode a standalone enum (no FlatBuffers dependency).
include/AccountLinkResultCode.h Makes AccountLinkResultCode a standalone enum (no FlatBuffers dependency).
frontend/src/vite-env.d.ts Declares VITE_LOCAL_DEVICE_HOST env var typing for Vite.
frontend/src/lib/views/Success.svelte Adds “Setup Complete” overlay that triggers portal close after delay.
frontend/src/lib/views/Landing.svelte Adds landing page with guided vs advanced setup selection.
frontend/src/lib/views/Guided.svelte Adds guided setup wizard stepper flow (pins/test/wifi/account).
frontend/src/lib/utils/localRedirect.ts Adds helpers to redirect API/WS host when running UI locally.
frontend/src/lib/stores/index.ts Exports new ViewModeStore from store index.
frontend/src/lib/stores/ViewModeStore.ts Adds store controlling portal UI view mode (landing/wizard/advanced).
frontend/src/lib/stores/HubStateStore.svelte.ts Fixes Svelte 5 reactivity by replacing Map mutations; adds savedOnlySSIDs derived.
frontend/src/lib/portalClose.ts Adds REST call helper to soft-close captive portal.
frontend/src/lib/components/ui/stepper/types.ts Adds stepper component type definitions.
frontend/src/lib/components/ui/stepper/stepper.svelte.ts Implements stepper state + context helpers.
frontend/src/lib/components/ui/stepper/stepper.svelte Adds Stepper root component.
frontend/src/lib/components/ui/stepper/stepper-trigger.svelte Adds step trigger (clickable tab) component.
frontend/src/lib/components/ui/stepper/stepper-title.svelte Adds step title component.
frontend/src/lib/components/ui/stepper/stepper-separator.svelte Adds separator component for stepper UI.
frontend/src/lib/components/ui/stepper/stepper-previous.svelte Adds “Back” stepper navigation control.
frontend/src/lib/components/ui/stepper/stepper-next.svelte Adds “Next” stepper navigation control.
frontend/src/lib/components/ui/stepper/stepper-nav.svelte Adds stepper navigation container component.
frontend/src/lib/components/ui/stepper/stepper-item.svelte Adds step item wrapper with state/context and total step tracking.
frontend/src/lib/components/ui/stepper/stepper-indicator.svelte Adds step number/check indicator component.
frontend/src/lib/components/ui/stepper/stepper-description.svelte Adds step description component.
frontend/src/lib/components/ui/stepper/index.ts Exports stepper component API.
frontend/src/lib/components/steps/WiFiStep.svelte Adds wizard WiFi step wrapper around WiFiManager.
frontend/src/lib/components/steps/TestStep.svelte Adds wizard shocker “test vibrate” step using FlatBuffers over WS.
frontend/src/lib/components/steps/HardwareStep.svelte Adds wizard hardware pin configuration step (REST setters).
frontend/src/lib/components/steps/AccountStep.svelte Adds wizard account linking step with status + re-link flow.
frontend/src/lib/components/sections/OtaSection.svelte Adds advanced OTA settings section (REST actions).
frontend/src/lib/components/sections/CaptivePortalSection.svelte Adds advanced portal settings section (read-only toggle).
frontend/src/lib/components/sections/BackendSection.svelte Adds advanced backend domain section (read-only).
frontend/src/lib/components/WiFiManager.svelte Adds WiFi manager UI (scan, saved/available groups, hidden networks).
frontend/src/lib/components/WiFiList.svelte Updates WiFi list to use REST scan start/stop rather than WS command.
frontend/src/lib/components/LightSwitch.svelte Simplifies theme switcher (removes light-mode confirmation dialog).
frontend/src/lib/components/Layout/Header.svelte Updates header logo to navigate back to landing view.
frontend/src/lib/components/GpioPinSelector.svelte Migrates GPIO pin setter from WS serializer to REST setter function.
frontend/src/lib/components/AddHiddenNetworkDialog.svelte Adds dialog to save/connect hidden networks including security type.
frontend/src/lib/_fbs/open-shock/serialization/types/sem-ver.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-scan-status-message.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-scan-command.ts Removes obsolete local WS scan command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-network-save-command.ts Removes obsolete local WS save command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-network-forget-command.ts Removes obsolete local WS forget command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-network-event.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-network-disconnect-command.ts Removes obsolete local WS disconnect command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-network-connect-command.ts Removes obsolete local WS connect command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-lost-ip-event.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/local/wifi-got-ip-event.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/local/set-rf-tx-pin-command.ts Removes obsolete local WS GPIO command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/set-rf-tx-pin-command-result.ts Removes obsolete local WS GPIO result type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/set-gpioresult-code.ts Updates generated local exports after schema changes.
frontend/src/lib/_fbs/open-shock/serialization/local/set-estop-pin-command.ts Removes obsolete local WS GPIO command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/set-estop-pin-command-result.ts Removes obsolete local WS GPIO result type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/set-estop-enabled-command.ts Removes obsolete local WS EStop command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/set-estop-enabled-command-result.ts Removes obsolete local WS EStop result type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-start-update-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-set-update-channel-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-set-require-manual-approval-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-set-is-enabled-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-set-domain-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-set-check-interval-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-set-allow-backend-management-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-handle-update-request-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/ota-update-check-for-updates-command.ts Removes obsolete local WS OTA command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/hub-to-local-message-payload.ts Updates Hub→Local payload union for new events + removed result types.
frontend/src/lib/_fbs/open-shock/serialization/local/error-message.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/local/account-unlink-command.ts Removes obsolete local WS unlink command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/account-link-status-event.ts Adds new Hub→Local AccountLinkStatusEvent type.
frontend/src/lib/_fbs/open-shock/serialization/local/account-link-result-code.ts Removes obsolete local WS link result enum (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/account-link-command.ts Removes obsolete local WS link command type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local/account-link-command-result.ts Removes obsolete local WS link result type (schema update).
frontend/src/lib/_fbs/open-shock/serialization/local.ts Updates local FlatBuffers TS exports after schema changes.
frontend/src/lib/_fbs/open-shock/serialization/gateway/shocker-command.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/gateway/shocker-command-list.ts Updates gateway to reference common shocker command list schema.
frontend/src/lib/_fbs/open-shock/serialization/gateway/gateway-to-hub-message-payload.ts Renames payload discriminator to Common_ShockerCommandList.
frontend/src/lib/_fbs/open-shock/serialization/gateway/boot-status.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/configuration/serial-input-config.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/configuration/rfconfig.ts FlatBuffers TS regen & default value change for keepaliveEnabled.
frontend/src/lib/_fbs/open-shock/serialization/configuration/ota-update-channel.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/configuration/mac-address.ts Adds MacAddress struct type for pinned BSSID.
frontend/src/lib/_fbs/open-shock/serialization/configuration/lan-config.ts Adds LanConfig schema TS type.
frontend/src/lib/_fbs/open-shock/serialization/configuration/hub-config.ts Adds LAN config field to hub config TS type.
frontend/src/lib/_fbs/open-shock/serialization/configuration/captive-portal-config.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/configuration/backend-config.ts FlatBuffers TS regen/format normalization.
frontend/src/lib/_fbs/open-shock/serialization/configuration.ts Updates configuration TS exports (LanConfig, MacAddress).
frontend/src/lib/WebSocketClient.ts Uses localRedirect helper for local-dev WS host selection.
frontend/src/lib/Serializers/WifiScanCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/Serializers/WifiNetworkSaveCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/Serializers/WifiNetworkForgetCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/Serializers/WifiNetworkDisconnectCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/Serializers/WifiNetworkConnectCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/Serializers/SetRfTxPinCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/Serializers/SetEstopPinCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/Serializers/SetEstopEnabledCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/Serializers/AccountLinkCommand.ts Removes obsolete WS serializer (migrated to REST).
frontend/src/lib/MessageHandlers/index.ts Updates WS handlers to new events + removes command-result handlers.
frontend/src/lib/MessageHandlers/WifiNetworkEventHandler.ts Keeps config-driven UI in sync for hidden/out-of-range saved networks.
frontend/src/App.svelte Replaces single-page UI with landing/guided/advanced flows + success close.
frontend/eslint.config.js Changes ESLint config to add Svelte-specific parser settings (but alters ignore behavior).
frontend/.env.example Adds local-dev device host env var example.
FLATBUFFERS_CHANGES.md Documents schema changes and breaking payload updates.
.gitmodules Pins schemas submodule to a named branch for this migration.
Comments suppressed due to low confidence (6)

frontend/src/lib/components/ui/stepper/stepper-trigger.svelte:1

  • The trigger computes isDisabled, but the actual disabled attribute is bound to the incoming disabled prop ({disabled}) rather than isDisabled. This makes the control appear/behave disabled via click handler + styling, but it can remain focusable/operable for keyboard/screen readers. Set the real disabled attribute from isDisabled (and avoid forwarding the raw disabled prop separately) so native semantics match the UI state.
    frontend/src/lib/components/AddHiddenNetworkDialog.svelte:1
  • bind:open={() => dialogOpen, handleOpenChange} uses the JavaScript comma operator, which evaluates to handleOpenChange and does not bind to dialogOpen as intended. This likely breaks dialog open/close state syncing. Bind directly to dialogOpen (e.g., bind:open={dialogOpen}) and pass the change handler using the dialog component’s expected callback/event API (e.g., onOpenChange={handleOpenChange} / on:openChange={...} depending on your Dialog implementation).
    src/wifi/WiFiScanManager.cpp:1
  • WiFiScanStatus::InProgress is now emitted on every loop iteration (i.e., repeatedly during a scan), whereas previously it was emitted once when the scan entered the in-progress state. If UI listeners treat status notifications as state transitions, this can cause unnecessary redraws/log spam and extra work per channel. Consider emitting InProgress only once per scan (or only on transition) and keeping periodic progress reporting as a separate event if needed.
    src/wifi/WiFiScanManager.cpp:1
  • WiFiScanStatus::InProgress is now emitted on every loop iteration (i.e., repeatedly during a scan), whereas previously it was emitted once when the scan entered the in-progress state. If UI listeners treat status notifications as state transitions, this can cause unnecessary redraws/log spam and extra work per channel. Consider emitting InProgress only once per scan (or only on transition) and keeping periodic progress reporting as a separate event if needed.
    src/captiveportal/Manager.cpp:1
  • isDeviceFullyConfigured() allocates a std::vector and reads config state; calling it from the periodic timer loop when the portal isn’t running can create repeated heap churn and lock contention over time (especially if the portal is usually closed). A more efficient approach is to cache “fully configured” state (updated by config change events) or add a cheap Config::HasAnyWiFiCredentials()-style query that avoids copying the credential list.
    frontend/src/lib/views/Success.svelte:1
  • The setTimeout isn’t cleared on unmount. If the view is dismissed early (navigation, reload, etc.), this can call onClose after the component is gone. Store the timeout id and return a cleanup function from onMount to clearTimeout.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Restores ignore patterns for src/lib/_fbs (generated FlatBuffers) and
src/lib/components/ui (vendored shadcn) that were accidentally dropped.
@hhvrc hhvrc requested a review from Copilot March 24, 2026 00:01
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 146 out of 161 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (7)

frontend/src/lib/components/ui/stepper/stepper-item.svelte:1

  • StepperRootState.totalSteps is only ever increased, never decreased. In Guided mode the number of steps can shrink when isDIY flips after board/config loads, which can leave totalSteps stuck at 4 even when only 3 steps exist, causing incorrect isLastStep and navigation bounds. Consider tracking registered steps in a Set and recomputing max on register/unregister (effect cleanup), or explicitly passing totalSteps from the parent and clamping the current step when it decreases.
    frontend/src/lib/components/ui/stepper/stepper-trigger.svelte:1
  • The button’s actual disabled attribute is bound to the incoming disabled prop ({disabled}), not the computed isDisabled. This means triggers that should be disabled (e.g., linear future steps) remain focusable/clickable and rely on JS early-returns. Bind disabled={isDisabled} (and optionally set aria-disabled) so keyboard/mouse interaction and accessibility semantics match the visual/logic state.
    frontend/src/lib/components/AddHiddenNetworkDialog.svelte:1
  • This bind:open expression uses the comma operator and evaluates to handleOpenChange, which is not an assignable binding target. As written, it’s unlikely the dialog open state will two-way bind correctly. Use a real bind target (e.g., bind:open={dialogOpen}) and wire the change handler via the component’s supported callback/event (commonly onOpenChange={handleOpenChange}) or handle state reset in a reactive effect when dialogOpen becomes false.
    src/config/WiFiCredentials.cpp:1
  • The construction flatbuffers::span<const uint8_t, 6>(bssid.data(), 6) is likely ill-formed if flatbuffers::span is std::span-compatible: the (ptr, len) constructor is only available for dynamic extent spans, not fixed extent 6. Prefer constructing a fixed-extent span from a pointer-only overload (if available) or use a dynamic-extent span (e.g., flatbuffers::span<const uint8_t>(bssid.data(), bssid.size())) matching the MacAddress ctor.
    include/captiveportal/CaptivePortalInstance.h:1
  • This accessor doesn’t mutate state and should be const so it can be called from const contexts and better communicates intent. Consider bool hasClients() const (and optionally noexcept if applicable).
    include/wifi/WiFiManager.h:1
  • The Save signature now includes authMode, but the parameter is not documented. Add a /// @param authMode ... line explaining expected values and what WIFI_AUTH_MAX means (e.g., unknown/unpinned).
    frontend/src/lib/views/Success.svelte:1
  • The timeout is not cleared if the component unmounts before 3s elapses (e.g., route/view change). Store the timeout handle and clear it in an onDestroy handler to avoid calling onClose after unmount.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

hhvrc added 3 commits March 24, 2026 01:08
…turn check

- Add null check after cJSON_PrintUnformatted() in all REST error
  response builders to prevent crash on OOM
- Add res.ok checks in saveWifiNetwork, connectWifiNetwork, and
  disconnectWifiNetwork frontend API functions
- Check RemoveWiFiCredentials return value in WiFiManager::Forget
  for networks not in scan results
5 attempts per minute, 10 per 5 minutes. Returns 429 with
{"error":"RateLimited"} when exceeded. Prevents local brute-force
of link codes.
Copy link
Member

@LucHeart LucHeart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Like idk, need to just test this in develop i guess, and make a beta

@hhvrc hhvrc merged commit df220dc into develop Mar 24, 2026
38 checks passed
@github-project-automation github-project-automation bot moved this from In Review to Done in Roadmap Mar 24, 2026
@hhvrc hhvrc deleted the feat/wifi-crud-fixes-and-advanced-mode branch March 24, 2026 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment