Public Access
The device joins a WireGuard network over whatever Wi-Fi it is on: one peer, IPv4. A client's .conf is imported from the card (/vpn/wg0.conf) and kept in the device's settings, private key included, never shown; Settings offers to delete the file. A switch brings the tunnel up until the next restart, "Start with Wi-Fi" every time; it waits for the clock, which a handshake needs. VPN shows in the Status Bar. The protocol is esphome/wireguard 0.4.8. It calls lwIP without lwIP's lock, which this framework checks: every call into it is made with the lock held. What goes through the tunnel is everything (AllowedIPs 0.0.0.0/0) or the one subnet the device's tunnel address is in: lwIP routes by an interface's subnet or by default, nothing finer. The import says how many ranges it can't reach. Checked against a test peer in both directions and against a real server, with a configuration uploaded from a phone (docs/milestones/N1.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
100 lines
4.1 KiB
C++
100 lines
4.1 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
#include "event_bus.h"
|
|
#include "saved_networks.h"
|
|
#include "scan_entry.h"
|
|
#include "service.h"
|
|
#include "services/clock_service.h"
|
|
#include "settings.h"
|
|
#include "wifi_controller.h"
|
|
|
|
namespace roro {
|
|
|
|
// Owns the Wi-Fi radio: carries out the WifiController's decisions with the ESP32 Wi-Fi stack,
|
|
// syncs the clock over NTP once Connected, and runs scans for the Settings network list.
|
|
class WifiService : public Service {
|
|
public:
|
|
WifiService(Settings& settings, SavedNetworks& saved, ClockService& clock)
|
|
: settings_(settings), saved_(saved), clock_(clock), controller_(saved) {}
|
|
const char* name() const override { return "wifi"; }
|
|
uint32_t tickIntervalMs() const override { return 250; }
|
|
void tick(uint32_t nowMs) override;
|
|
|
|
WifiController::State state() const { return controller_.state(); }
|
|
const std::string& ssid() const { return controller_.ssid(); }
|
|
int rssi() const;
|
|
std::string ip() const; // empty unless Connected
|
|
|
|
// 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();
|
|
|
|
// What the device is using and where each part came from (S1, Q113).
|
|
struct Connection {
|
|
bool connected = false;
|
|
bool fixed = false; // the address: Fixed, or from DHCP
|
|
bool dnsFromSettings = false; // DNS: from Settings, or from DHCP
|
|
std::string address, mask, gateway;
|
|
int prefix = 0;
|
|
std::string dns[2];
|
|
struct Ntp {
|
|
std::string server;
|
|
bool fromDhcp = false;
|
|
bool answered = false; // it has replied since the last (re)start
|
|
} ntp[3];
|
|
int ntpCount = 0;
|
|
};
|
|
Connection connection() const;
|
|
// A Saved Network's IP setting changed: if it's the one in use, join it again with it (Q114).
|
|
void ipSettingChanged(const std::string& ssid);
|
|
// The DNS or NTP settings changed: use them now.
|
|
void serversChanged() { applyServers(Why::SettingsChanged); }
|
|
// While a tunnel has put its own DNS servers in (issue #8), ours are not put back over them.
|
|
void holdDns(bool held);
|
|
// The noise self-test switches the radio off for a few seconds. Not saved anywhere: a restart
|
|
// during the test brings Wi-Fi back, which a changed setting wouldn't.
|
|
void debugPause(bool paused) { paused_ = paused; }
|
|
|
|
// A Saved Network was added: try it now rather than after the retry delay.
|
|
void savedNetworksChanged() { controller_.retryNow(millis()); }
|
|
|
|
void requestMonitor() { apply(controller_.requestMonitor()); }
|
|
void releaseMonitor() { apply(controller_.releaseMonitor(settings_.getBool(Setting::WifiEnabled))); }
|
|
|
|
private:
|
|
void apply(const WifiController::Step& step);
|
|
void startScan(int channel = 0);
|
|
void finishScan(uint32_t nowMs);
|
|
void startNtp();
|
|
void join(const std::string& ssid, const std::string& password);
|
|
enum class Why { Joined, SettingsChanged, Check };
|
|
void applyServers(Why why); // DNS and NTP, as Settings and the network say
|
|
|
|
Settings& settings_;
|
|
SavedNetworks& saved_;
|
|
ClockService& clock_;
|
|
WifiController controller_;
|
|
bool scanRunning_ = false;
|
|
bool listScanPending_ = false;
|
|
std::vector<ScanEntry> listScan_;
|
|
uint32_t listScanSeq_ = 0;
|
|
bool ntpWaiting_ = false;
|
|
bool sntpStarted_ = false;
|
|
bool radioInitialised_ = false;
|
|
bool paused_ = false; // Debug Builds: off for a moment, whatever the setting says
|
|
bool fixed_ = false; // the network in use has a Fixed address
|
|
bool dnsFromSettings_ = false;
|
|
bool dnsHeld_ = false;
|
|
std::string ntpNames_[2]; // lwIP keeps the pointers, so the names live here
|
|
uint32_t serversCheckedMs_ = 0;
|
|
};
|
|
|
|
} // namespace roro
|