Public Access
M1 step 6: Wi-Fi Tools from ordinary scans
- lib/wifi (host-tested): channel occupancy (neighbour spill, signal weighting, quietest of 1/6/11) and a signal tracker (history, lost detection, click interval) - WifiService: scan results carry BSSID, channel and security; a scan can target one channel for quick tracker refreshes; endListScans() turns the radio back off when Wi-Fi is disabled - Wi-Fi Tools App: networks nearby, channel occupancy bars, signal tracker with clicks (m to mute) - M1 plan: Monitoring-mode views and captures deferred Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
@@ -11,7 +11,7 @@ int WifiService::rssi() const {
|
||||
return controller_.state() == WifiController::State::Connected ? WiFi.RSSI() : 0;
|
||||
}
|
||||
|
||||
void WifiService::startScan() {
|
||||
void WifiService::startScan(int channel) {
|
||||
if (!radioInitialised_) {
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setAutoReconnect(false); // the controller decides when to reconnect
|
||||
@@ -19,15 +19,45 @@ void WifiService::startScan() {
|
||||
radioInitialised_ = true;
|
||||
}
|
||||
if (scanRunning_) return;
|
||||
if (WiFi.scanNetworks(true /* async */, false /* no hidden */) == WIFI_SCAN_FAILED) return;
|
||||
// Hidden networks are listed too (with an empty name); the controller skips them.
|
||||
if (WiFi.scanNetworks(true /* async */, true /* hidden */, false, channel ? 120 : 300, channel) == WIFI_SCAN_FAILED)
|
||||
return;
|
||||
scanRunning_ = true;
|
||||
}
|
||||
|
||||
void WifiService::startListScan() {
|
||||
void WifiService::startListScan(int channel) {
|
||||
if (scanRunning_) {
|
||||
listScanPending_ = true; // results of the scan already running will do
|
||||
return;
|
||||
}
|
||||
listScanPending_ = true;
|
||||
startScan();
|
||||
startScan(channel);
|
||||
}
|
||||
|
||||
void WifiService::endListScans() {
|
||||
listScanPending_ = false;
|
||||
if (controller_.state() == WifiController::State::Off && radioInitialised_ && !scanRunning_) {
|
||||
WiFi.mode(WIFI_OFF);
|
||||
radioInitialised_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
const char* security(wifi_auth_mode_t auth) {
|
||||
switch (auth) {
|
||||
case WIFI_AUTH_OPEN: return "open";
|
||||
case WIFI_AUTH_WEP: return "WEP";
|
||||
case WIFI_AUTH_WPA_PSK: return "WPA";
|
||||
case WIFI_AUTH_WPA2_PSK:
|
||||
case WIFI_AUTH_WPA_WPA2_PSK: return "WPA2";
|
||||
case WIFI_AUTH_WPA2_ENTERPRISE: return "WPA2-E";
|
||||
case WIFI_AUTH_WPA3_PSK:
|
||||
case WIFI_AUTH_WPA2_WPA3_PSK: return "WPA3";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void WifiService::finishScan(uint32_t nowMs) {
|
||||
int n = WiFi.scanComplete();
|
||||
if (n == WIFI_SCAN_RUNNING) return;
|
||||
@@ -37,14 +67,16 @@ void WifiService::finishScan(uint32_t nowMs) {
|
||||
std::vector<ScanEntry> entries;
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::string ssid = WiFi.SSID(i).c_str();
|
||||
if (ssid.empty()) continue;
|
||||
results.push_back({ssid, WiFi.RSSI(i)});
|
||||
entries.push_back({ssid, WiFi.RSSI(i), WiFi.encryptionType(i) == WIFI_AUTH_OPEN});
|
||||
wifi_auth_mode_t auth = WiFi.encryptionType(i);
|
||||
entries.push_back({ssid, WiFi.BSSIDstr(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), auth == WIFI_AUTH_OPEN,
|
||||
security(auth)});
|
||||
if (!ssid.empty()) results.push_back({ssid, WiFi.RSSI(i)});
|
||||
}
|
||||
WiFi.scanDelete();
|
||||
if (listScanPending_) {
|
||||
listScan_ = entries;
|
||||
listScanPending_ = false;
|
||||
listScanSeq_++;
|
||||
}
|
||||
apply(controller_.scanDone(results, nowMs));
|
||||
}
|
||||
|
||||
@@ -12,9 +12,12 @@
|
||||
namespace roro {
|
||||
|
||||
struct ScanEntry {
|
||||
std::string ssid;
|
||||
std::string ssid; // empty for a hidden network
|
||||
std::string bssid;
|
||||
int channel;
|
||||
int rssi;
|
||||
bool open;
|
||||
std::string security; // "open", "WPA2", "WPA3"...
|
||||
};
|
||||
|
||||
// Owns the Wi-Fi radio: carries out the WifiController's decisions with the ESP32 Wi-Fi stack,
|
||||
@@ -31,10 +34,14 @@ class WifiService : public Service {
|
||||
const std::string& ssid() const { return controller_.ssid(); }
|
||||
int rssi() const;
|
||||
|
||||
// Scan for the "add a network" list; results arrive in listScan() when listScanDone().
|
||||
void startListScan();
|
||||
// Scans for a list of nearby networks (all channels, or just one for a quick refresh); results
|
||||
// arrive in listScan() when listScanDone(), and listScanSeq() counts completed scans.
|
||||
void startListScan(int channel = 0);
|
||||
bool listScanDone() const { return !listScanPending_; }
|
||||
const std::vector<ScanEntry>& listScan() const { return listScan_; }
|
||||
uint32_t listScanSeq() const { return listScanSeq_; }
|
||||
// Done with list scans: switch the radio back off if Wi-Fi itself is off.
|
||||
void endListScans();
|
||||
|
||||
// A Saved Network was added: try it now rather than after the retry delay.
|
||||
void savedNetworksChanged() { controller_.retryNow(millis()); }
|
||||
@@ -44,7 +51,7 @@ class WifiService : public Service {
|
||||
|
||||
private:
|
||||
void apply(const WifiController::Step& step);
|
||||
void startScan();
|
||||
void startScan(int channel = 0);
|
||||
void finishScan(uint32_t nowMs);
|
||||
void startNtp();
|
||||
|
||||
@@ -55,6 +62,7 @@ class WifiService : public Service {
|
||||
bool scanRunning_ = false;
|
||||
bool listScanPending_ = false;
|
||||
std::vector<ScanEntry> listScan_;
|
||||
uint32_t listScanSeq_ = 0;
|
||||
bool ntpWaiting_ = false;
|
||||
bool radioInitialised_ = false;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user