Make Indicator WiFi display authoritative

This commit is contained in:
mikecarper committed 2026-08-31 18:45:44 -07:00
1 parent b562af845a
commit bf2d4e4b93
5 files changed
+86 -3

No files matched your search

+15
View File
@@ -1,5 +1,6 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#ifndef UI_WIFI_SETUP_HOME_PAGE
@@ -49,6 +50,20 @@ bool isCompanionWiFiEnabled();
// live. Unlike localIP(), the driver record is cleared on a real disconnect.
bool isCompanionWiFiConnected();
enum class CompanionWiFiDisplayState : uint8_t {
NotRendered,
Setup,
Off,
Ready,
Connecting,
};
// Record the branch that was actually drawn. This is exposed through the
// read-only `get display.wifi` terminal diagnostic so a headless test host can
// distinguish network state from a stale or incorrect LCD frame.
void noteCompanionWiFiDisplayState(CompanionWiFiDisplayState state);
void formatCompanionWiFiDisplayStatus(char* reply, size_t reply_size);
// Reload saved credentials after a text-terminal update. The reconnect is
// deferred so the command reply can leave USB/TCP before WiFi is restarted.
void scheduleCompanionWiFiCredentialReload();
+5
View File
@@ -2294,6 +2294,11 @@ bool MyMesh::handleLocalControlCommand(const char* command, char* reply,
#endif
#if defined(ESP32) && defined(WIFI_SSID)
if (strcmp(command, "get display.wifi") == 0) {
formatCompanionWiFiDisplayStatus(reply, reply_size);
return true;
}
#if defined(COMPANION_EXCLUSIVE_WIFI_BLE)
if (strcmp(command, "get companion.transport") == 0) {
snprintf(reply, reply_size, "%s",
+32 -1
View File
@@ -822,6 +822,9 @@ void halt() {
static unsigned long companion_wifi_credential_reload_at = 0;
static bool companion_wifi_power_save_loaded = false;
static uint8_t companion_wifi_power_save = mesh::wifi::kDefaultPowerSave;
static CompanionWiFiDisplayState companion_wifi_display_state =
CompanionWiFiDisplayState::NotRendered;
static uint32_t companion_wifi_display_frames = 0;
#if defined(COMPANION_EXCLUSIVE_WIFI_BLE)
static CompanionTransportMode companion_transport_boot_mode =
@@ -1145,12 +1148,40 @@ void halt() {
}
bool isCompanionWiFiConnected() {
if (!companion_wifi_requested || !companion_wifi_active) return false;
// The display describes the station link, not the lifecycle of the
// Companion TCP services. A valid station association remains the source
// of truth even if service bookkeeping is delayed or being recovered.
if (!companion_wifi_requested) return false;
if (WiFi.status() == WL_CONNECTED) return true;
wifi_ap_record_t access_point = {};
return esp_wifi_sta_get_ap_info(&access_point) == ESP_OK;
}
void noteCompanionWiFiDisplayState(CompanionWiFiDisplayState state) {
companion_wifi_display_state = state;
companion_wifi_display_frames++;
}
void formatCompanionWiFiDisplayStatus(char* reply, size_t reply_size) {
if (reply == nullptr || reply_size == 0) return;
static const char* const names[] = {
"not-rendered", "setup", "off", "ready", "connecting",
};
uint8_t state = static_cast<uint8_t>(companion_wifi_display_state);
if (state >= sizeof(names) / sizeof(names[0])) state = 0;
wifi_ap_record_t access_point = {};
const bool idf_associated =
esp_wifi_sta_get_ap_info(&access_point) == ESP_OK;
snprintf(reply, reply_size,
"> state=%s, frames=%lu, requested=%u, services=%u, "
"wl=%d, idf=%u, IP=%s",
names[state], (unsigned long)companion_wifi_display_frames,
companion_wifi_requested ? 1U : 0U,
companion_wifi_active ? 1U : 0U, (int)WiFi.status(),
idf_associated ? 1U : 0U,
WiFi.localIP().toString().c_str());
}
bool toggleCompanionWiFi() {
#if defined(COMPANION_EXCLUSIVE_WIFI_BLE)
const CompanionTransportMode current = getCompanionTransportMode();
+22 -2
View File
@@ -123,6 +123,26 @@ static void drawCompanionWiFiSetupPage(DisplayDriver& display) {
char setup_ip[16] = {0};
const bool setup_active = WebConfigServer::getSetupInfo(
setup_ssid, sizeof(setup_ssid), setup_ip, sizeof(setup_ip));
const bool wifi_enabled = isCompanionWiFiEnabled();
const bool wifi_connected = isCompanionWiFiConnected();
const CompanionWiFiDisplayState state = setup_active
? CompanionWiFiDisplayState::Setup
: !wifi_enabled
? CompanionWiFiDisplayState::Off
: wifi_connected
? CompanionWiFiDisplayState::Ready
: CompanionWiFiDisplayState::Connecting;
static CompanionWiFiDisplayState previous_state =
CompanionWiFiDisplayState::NotRendered;
// Frame hashing normally suppresses identical LCD transfers. Explicitly
// invalidate that cache on a network-state transition so a retained
// CONNECTING frame can never survive a READY render.
if (state != previous_state) {
display.clear();
previous_state = state;
}
noteCompanionWiFiDisplayState(state);
// Keep the setup content below the shared title bar and page dots. Compact
// text makes its physical size identical on the 480 canvas and the
@@ -155,14 +175,14 @@ static void drawCompanionWiFiSetupPage(DisplayDriver& display) {
display.drawTextCentered(display.width() / 2, 70, "QR UNAVAILABLE");
display.setColor(UIColor::secondary_txt);
display.drawTextCentered(display.width() / 2, 100, setup_ip);
} else if (!isCompanionWiFiEnabled()) {
} else if (!wifi_enabled) {
display.setTextSize(3);
display.drawTextCentered(display.width() / 2, 45, "WIFI OFF");
display.setTextSize(2);
display.setColor(UIColor::secondary_txt);
display.drawTextCentered(display.width() / 2, 90, "SELECT WIFI");
display.drawTextCentered(display.width() / 2, 112, "THEN REBOOT");
} else if (isCompanionWiFiConnected()) {
} else if (wifi_connected) {
display.setTextSize(2);
display.drawTextCentered(display.width() / 2, 25, "WIFI READY");
const String ssid = WiFi.SSID();
+12
View File
@@ -178,6 +178,18 @@ int main() {
self.assertIn("wifi_setup_active && !_wifi_setup_was_active", ui)
self.assertIn("isCompanionWiFiConnected()", page)
self.assertIn("wifi_connected != _wifi_was_connected", ui)
self.assertIn("CompanionWiFiDisplayState::Ready", page)
self.assertIn("display.clear()", page)
self.assertIn("noteCompanionWiFiDisplayState(state)", page)
main = (ROOT / "examples/companion_radio/main.cpp").read_text()
helper = main[main.index("bool isCompanionWiFiConnected()"):
main.index("bool toggleCompanionWiFi()")]
self.assertNotIn("!companion_wifi_active", helper)
self.assertIn("esp_wifi_sta_get_ap_info", helper)
mesh = (ROOT / "examples/companion_radio/MyMesh.cpp").read_text()
self.assertIn('strcmp(command, "get display.wifi")', mesh)
self.assertIn("_task->gotoHomeScreen();", ui)
main = MAIN.read_text(encoding="utf-8")