diff --git a/include/menu.h b/include/menu.h index 7da62bb..04a7664 100644 --- a/include/menu.h +++ b/include/menu.h @@ -10,6 +10,7 @@ bool b_showAbout = false; bool b_showLogo = false; bool b_showNumber = false; bool b_showWifiData = false; +bool b_showStatusData = false; String actionMessage = "Default"; String actionMessage2 = "Default"; unsigned long t_actionMessage = 0; @@ -41,6 +42,7 @@ void heartbeatOff(); void calibrate(); void drawButton(); void wifiUpdate(); +void showStatus(); void showAbout(); void showMenu(); void showLogo(); @@ -73,6 +75,7 @@ Menu menuBuzzer = { "Buzzer", NULL, NULL, NULL }; #endif Menu menuCalibration = { "Calibration", NULL, NULL, NULL }; Menu menuWifi = { "WiFi Settings", NULL, NULL, NULL }; +Menu menuStatus = { "Status", showStatus, NULL, NULL }; // Menu menuWiFiUpdate = {"WiFi Update", NULL, NULL, NULL}; Menu menuAbout = { "About", showAbout, NULL, NULL }; Menu menuLogo = { "Show Logo", showLogo, NULL, NULL }; @@ -180,7 +183,7 @@ Menu *mainMenu[] = { #ifdef BUZZER &menuBuzzer, #endif - &menuCalibration, &menuWifi, + &menuCalibration, &menuWifi, &menuStatus, // &menuWiFiUpdate, &menuAbout, &menuLogo, &menuHeartbeat, &menuFlipScreen, &menuTimeOnTop, &menuBtnFuncWhileConnected, &menuAutoSleep, &menuQuickBoot, &menuDriftComp, @@ -259,6 +262,7 @@ void buzzerOff() { #endif void toggleWifiOn() { + b_wifiOnBoot = true; actionMessage = "WiFi Enabled"; actionMessage2 = "Restart scale"; t_actionMessage = millis(); @@ -269,7 +273,7 @@ void toggleWifiOn() { } void toggleWifiOff() { - bool wifiEnabled = false; + b_wifiOnBoot = false; actionMessage = "WiFi Disabled"; actionMessage2 = "Restart scale"; t_actionMessage = millis(); @@ -310,6 +314,56 @@ void showWifiStatus() { } } +void showStatus() { + b_showStatusData = true; + + const char *wifiRunState = "Idle"; + if (b_wifiEnabled) { + if (WiFi.getMode() == WIFI_AP) { + wifiRunState = "AP"; + } else if (WiFi.status() == WL_CONNECTED) { + wifiRunState = "Conn"; + } else { + wifiRunState = "Wait"; + } + } + + char wifiLine[32]; + char bleLine[32]; + char sleepLine[32]; + char driftLine[32]; + snprintf(wifiLine, sizeof(wifiLine), "WiFi:%s %s %s", + b_wifiOnBoot ? "On" : "Off", + wifiCredentialsSaved() ? "Saved" : "NoCred", + wifiRunState); + snprintf(bleLine, sizeof(bleLine), "BLE:%s Btn:%s HB:%s", + b_ble_enabled ? "On" : "Off", + b_btnFuncWhileConnected ? "On" : "Off", + b_requireHeartBeat ? "On" : "Off"); + snprintf(sleepLine, sizeof(sleepLine), "Sleep:%s Quick:%s", + b_autoSleep ? "On" : "Off", + b_quickBoot ? "On" : "Off"); + snprintf(driftLine, sizeof(driftLine), "T:%s Drift:%.3fg", + b_timeOnTop ? "Top" : "Bot", + f_maxDriftCompensation); + + u8g2.firstPage(); + do { + u8g2.setFont(u8g2_font_6x12_tr); + u8g2.drawStr(0, 10, "Status"); + u8g2.drawStr(0, 22, wifiLine); + u8g2.drawStr(0, 34, bleLine); + u8g2.drawStr(0, 46, sleepLine); + u8g2.drawStr(0, 58, driftLine); + } while (u8g2.nextPage()); + delay(1000); + while (b_showStatusData) { + if (digitalRead(BUTTON_SQUARE) == LOW) { + b_showStatusData = false; + } + } +} + void resetWifi() { saveCredentials("", ""); actionMessage = "WiFi Reset"; @@ -323,7 +377,7 @@ void heartbeatOn() { actionMessage = "Heartbeat On"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_requireHeartBeat, b_requireHeartBeat); + EEPROM.put(i_addr_requireHeartBeat, (bool)b_requireHeartBeat); EEPROM.commit(); Serial.println("Heartbeat detection...On"); } @@ -333,7 +387,7 @@ void heartbeatOff() { actionMessage = "Heartbeat Off"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_requireHeartBeat, b_requireHeartBeat); + EEPROM.put(i_addr_requireHeartBeat, (bool)b_requireHeartBeat); EEPROM.commit(); Serial.println("Heartbeat detection...Off"); } @@ -343,7 +397,7 @@ void flipScreenOn() { actionMessage = "Flip On"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_screenFlipped, b_screenFlipped); + EEPROM.put(i_addr_screenFlipped, (bool)b_screenFlipped); EEPROM.commit(); u8g2.setDisplayRotation(U8G2_R0); Serial.println("Screen flipped...On"); @@ -354,7 +408,7 @@ void flipScreenOff() { actionMessage = "Flip Off"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_screenFlipped, b_screenFlipped); + EEPROM.put(i_addr_screenFlipped, (bool)b_screenFlipped); EEPROM.commit(); u8g2.setDisplayRotation(U8G2_R2); Serial.println("Screen flipped...Off"); @@ -365,7 +419,7 @@ void timeOnTopOn() { actionMessage = "Time On Top"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_timeOnTop, b_timeOnTop); + EEPROM.put(i_addr_timeOnTop, (bool)b_timeOnTop); EEPROM.commit(); Serial.println("Time On Top"); } @@ -375,7 +429,7 @@ void timeOnTopOff() { actionMessage = "Weight On Top"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_timeOnTop, b_timeOnTop); + EEPROM.put(i_addr_timeOnTop, (bool)b_timeOnTop); EEPROM.commit(); Serial.println("Weight On Top"); } @@ -385,7 +439,7 @@ void btnFuncWhileConnectedOn() { actionMessage = "BLE Btns On"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_btnFuncWhileConnected, b_btnFuncWhileConnected); + EEPROM.put(i_addr_btnFuncWhileConnected, (bool)b_btnFuncWhileConnected); EEPROM.commit(); Serial.println("BLE Btns On"); } @@ -395,7 +449,7 @@ void btnFuncWhileConnectedOff() { actionMessage = "BLE Btns Off"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_btnFuncWhileConnected, b_btnFuncWhileConnected); + EEPROM.put(i_addr_btnFuncWhileConnected, (bool)b_btnFuncWhileConnected); EEPROM.commit(); Serial.println("BLE Btns Off"); } @@ -405,7 +459,7 @@ void autoSleepOn() { actionMessage = "Autosleep On"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_autoSleep, b_autoSleep); + EEPROM.put(i_addr_autoSleep, (bool)b_autoSleep); EEPROM.commit(); Serial.println("Autosleep on stored in EEPROM."); } @@ -415,7 +469,7 @@ void autoSleepOff() { actionMessage = "Autosleep Off"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_autoSleep, b_autoSleep); + EEPROM.put(i_addr_autoSleep, (bool)b_autoSleep); EEPROM.commit(); Serial.println("Autosleep off stored in EEPROM."); } @@ -425,7 +479,7 @@ void quickBootOn() { actionMessage = "Quick Boot On"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_quickBoot, b_quickBoot); + EEPROM.put(i_addr_quickBoot, (bool)b_quickBoot); EEPROM.commit(); Serial.println("Quick boot on stored in EEPROM."); } @@ -435,7 +489,7 @@ void quickBootOff() { actionMessage = "Quick Boot Off"; t_actionMessage = millis(); t_actionMessageDelay = 1000; - EEPROM.put(i_addr_quickBoot, b_quickBoot); + EEPROM.put(i_addr_quickBoot, (bool)b_quickBoot); EEPROM.commit(); Serial.println("Quick boot off stored in EEPROM."); } diff --git a/include/parameter.h b/include/parameter.h index c5e2c3b..c18ed41 100644 --- a/include/parameter.h +++ b/include/parameter.h @@ -3,7 +3,9 @@ //declaration //ble -bool b_ble_enabled = false; +// volatile: read by the AsyncTCP task in the WS status frame, written by the +// main loop during boot/charging-mode transitions. +volatile bool b_ble_enabled = false; bool b_usbweight_enabled = false; unsigned long weightBleNotifyInterval = 100; // BLE notify interval (ms). Fixed at 100ms (10Hz); not runtime-configurable over BLE. unsigned long weightUsbNotifyInterval = 100; // USB binary notify interval (ms) @@ -53,10 +55,12 @@ volatile uint32_t wsPendingMask = 0; int i_onWrite_counter = 0; unsigned long t_heartBeat = 0; unsigned long t_firstConnect = 0; -bool b_requireHeartBeat = true; -bool b_screenFlipped = false; -bool b_timeOnTop = false; -bool b_btnFuncWhileConnected = false; +// volatile: read by the AsyncTCP task in the WS status frame, written by the +// main-loop menu/EEPROM restore paths. +volatile bool b_requireHeartBeat = true; +volatile bool b_screenFlipped = false; +volatile bool b_timeOnTop = false; +volatile bool b_btnFuncWhileConnected = false; // int windowLength = 5; // default window length @@ -163,9 +167,10 @@ int i_icon = 0; //充电指示电量数字0-6 int i_setContainerWeight = 0; float f_filtered_temperature = 0; bool b_ads1115InitFail = true; //ads1115 not detected flag -bool b_wifiOnBoot = false; -bool b_autoSleep = true; -bool b_quickBoot = false; +// volatile: surfaced from AsyncTCP status while menu/setup code updates them. +volatile bool b_wifiOnBoot = false; +volatile bool b_autoSleep = true; +volatile bool b_quickBoot = false; unsigned int i_buttonBootDelay = 500; bool b_showChargingUI = false; diff --git a/include/websocket.h b/include/websocket.h index 7a1db33..d56f3c5 100644 --- a/include/websocket.h +++ b/include/websocket.h @@ -221,8 +221,22 @@ void sendWebsocketRateInfo(AsyncWebSocketClient *client, const char *status) { hz); } +const char *websocketWifiModeName() { + wifi_mode_t mode = WiFi.getMode(); + if (mode == WIFI_STA) { + return "sta"; + } + if (mode == WIFI_AP) { + return "ap"; + } + if (mode == WIFI_AP_STA) { + return "sta_ap"; + } + return "off"; +} + void sendWebsocketStatus(AsyncWebSocketClient *client, const char *status) { - client->printf("{\"type\":\"status\",\"status\":\"%s\",\"protocol_version\":1,\"firmware_version\":\"%s\",\"grams\":%.2f,\"ms\":%lu,\"battery_percent\":%d,\"battery_voltage\":%.2f,\"charging\":%s,\"timer_running\":%s,\"timer_seconds\":%lu,\"display_on\":%s,\"low_power\":%s,\"soft_sleep\":%s,\"events_enabled\":%s,\"rate_hz\":%lu,\"interval_ms\":%lu}", + client->printf("{\"type\":\"status\",\"status\":\"%s\",\"protocol_version\":1,\"firmware_version\":\"%s\",\"grams\":%.2f,\"ms\":%lu,\"battery_percent\":%d,\"battery_voltage\":%.2f,\"charging\":%s,\"timer_running\":%s,\"timer_seconds\":%lu,\"display_on\":%s,\"low_power\":%s,\"soft_sleep\":%s,\"events_enabled\":%s,\"rate_hz\":%lu,\"interval_ms\":%lu,\"wifi_on_boot\":%s,\"wifi_active\":%s,\"wifi_connected\":%s,\"wifi_mode\":\"%s\",\"wifi_credentials_saved\":%s,\"ble_enabled\":%s,\"ble_connected\":%s,\"ble_buttons_enabled\":%s,\"ble_heartbeat_required\":%s,\"auto_sleep_enabled\":%s,\"auto_sleep_minutes\":15,\"quick_boot_enabled\":%s,\"time_on_top\":%s,\"drift_compensation_max_grams\":%.3f}", status, FIRMWARE_VER, f_displayedValue, @@ -237,7 +251,20 @@ void sendWebsocketStatus(AsyncWebSocketClient *client, const char *status) { b_softSleep ? "true" : "false", b_websocketEventsEnabled ? "true" : "false", websocketRateForInterval(weightWebsocketNotifyInterval), - weightWebsocketNotifyInterval); + weightWebsocketNotifyInterval, + b_wifiOnBoot ? "true" : "false", + b_wifiEnabled ? "true" : "false", + WiFi.status() == WL_CONNECTED ? "true" : "false", + websocketWifiModeName(), + wifiCredentialsSaved() ? "true" : "false", + b_ble_enabled ? "true" : "false", + deviceConnected ? "true" : "false", + b_btnFuncWhileConnected ? "true" : "false", + b_requireHeartBeat ? "true" : "false", + b_autoSleep ? "true" : "false", + b_quickBoot ? "true" : "false", + b_timeOnTop ? "true" : "false", + f_maxDriftCompensation); } // Broadcast via printfAll(): it holds the library's client-list mutex and diff --git a/include/wifi_setup.h b/include/wifi_setup.h index 504fe29..3a919ec 100644 --- a/include/wifi_setup.h +++ b/include/wifi_setup.h @@ -7,6 +7,7 @@ void setupWifi(); void stopWifi(); void saveCredentials(String ssid, String pass); // ssid, pass +bool wifiCredentialsSaved(); // Periodic health log + STA reconnect supervisor; call once per main-loop pass // when WiFi is enabled. Recovers from a silent STA disconnect (which the old @@ -17,7 +18,7 @@ void saveCredentials(String ssid, String pass); // ssid, pass // isn't interrupted, then fires regardless once that window passes. void wifiSupervise(); -extern bool b_wifiEnabled; +extern volatile bool b_wifiEnabled; extern const char *wifiPrefsKey; extern const char *wifiSSIDKey; diff --git a/src/wifi_setup.cpp b/src/wifi_setup.cpp index 170b30b..18c117a 100644 --- a/src/wifi_setup.cpp +++ b/src/wifi_setup.cpp @@ -9,7 +9,7 @@ #include #include -bool b_wifiEnabled = false; +volatile bool b_wifiEnabled = false; // Set by the GOT_IP WiFi event; the main loop (wifiSupervise) consumes it and // (re)advertises mDNS, keeping all mDNS work off the WiFi-event task. static volatile bool g_mdnsAdvertisePending = false; @@ -27,6 +27,7 @@ class WiFiParams { String ssid = ""; String pass = ""; Preferences preferences; + bool initialized = false; public: String getSSID() { return ssid; } @@ -301,11 +302,24 @@ void saveCredentials(String ssid, String pass) { params.saveCredentials(ssid, pass); } +bool wifiCredentialsSaved() { + params.init(); + return params.hasCredentials(); +} + // ---------------------------------------------------- // ------------------ WiFiParams ---------------------- // ---------------------------------------------------- void WiFiParams::saveCredentials(String ssid, String pass) { + if (!initialized) { + init(); + } + if (!initialized) { + Serial.println("[prefs] could not save credentials -- NVS namespace unavailable"); + return; + } + if (this->ssid == ssid && this->pass == pass) return; @@ -323,10 +337,14 @@ void WiFiParams::saveCredentials(String ssid, String pass) { } void WiFiParams::init() { + if (initialized) { + return; + } if (!preferences.begin(wifiPrefsKey)) { Serial.println("[prefs] could not open NVS namespace 'wifi' -- no stored credentials"); return; } + initialized = true; if (!hasCredentials()) { this->ssid = preferences.getString(wifiSSIDKey, ""); this->pass = preferences.getString(wifiPassKey, ""); @@ -336,5 +354,10 @@ void WiFiParams::init() { void WiFiParams::reset() { ssid = ""; pass = ""; - preferences.clear(); + if (!initialized) { + init(); + } + if (initialized) { + preferences.clear(); + } } diff --git a/tools/ws_feature_test.py b/tools/ws_feature_test.py index 4d718de..2f3f518 100755 --- a/tools/ws_feature_test.py +++ b/tools/ws_feature_test.py @@ -105,9 +105,18 @@ def main(): ws.send("status") st = recv_until(ws, is_type("status")) or {} fields = ("battery_percent", "timer_running", "timer_seconds", "display_on", - "low_power", "soft_sleep", "events_enabled", "rate_hz", "interval_ms") - rec("status frame: all fields present, 'led' removed", - all(k in st for k in fields) and "led" not in st, + "low_power", "soft_sleep", "events_enabled", "rate_hz", "interval_ms", + "wifi_on_boot", "wifi_active", "wifi_connected", "wifi_mode", + "wifi_credentials_saved", "ble_enabled", "ble_connected", + "ble_buttons_enabled", "ble_heartbeat_required", + "auto_sleep_enabled", "auto_sleep_minutes", + "quick_boot_enabled", "time_on_top", "drift_compensation_max_grams") + removed_fields = ("led", "button_boot_delay_ms", "screen_flipped", + "buzzer_enabled", "mode", "mode_name", + "pourover_target_grams", "espresso_target_grams", + "calibration_factor", "battery_calibration_factor") + rec("status frame: current settings present, legacy fields removed", + all(k in st for k in fields) and not any(k in st for k in removed_fields), f"keys={sorted(st)}") rec("events on", (status_after(ws, "events on") or {}).get("events_enabled") is True) diff --git a/web_apps/index.html b/web_apps/index.html index 9e0a826..538d100 100644 --- a/web_apps/index.html +++ b/web_apps/index.html @@ -3,30 +3,149 @@ - Available Apps + Half Decent Scale -

Available Apps

- - -

Other useful links

- +
+

OpenScale

+

Half Decent Scale control surface

+
+ +
+ +
+

Weight

+
-- g
+ +
- -
-

Weight

-
-- g
- +
+

Current Settings

+

Connecting

+
+
+ WiFi + -- +
+
+ BLE Buttons + -- +
+
+ BLE Heartbeat + -- +
+
+ Auto Sleep + -- +
+
+ Quick Boot + -- +
+
+ Timer Position + -- +
+
+ Drift Comp + -- +
+
+
+
+

Available Apps

+ +
+

Setup WiFi

@@ -127,6 +445,17 @@

Setup WiFi

+
+ + +
+