Sensor3/lib/patrix/wifi.cpp

221 lines
4.5 KiB
C++

#include "wifi.h"
#include "base.h"
#include "log.h"
#include "mqtt.h"
#include "console.h"
#include "config.h"
#include <ArduinoOTA.h>
#include <lwip/apps/sntp.h>
#define NTP_SERVER "pool.ntp.org"
#define TIMEZONE_OFFSET 3600
#define DST_OFFSET 3600
#define MIN_EPOCH_SECONDS 1712675973
#define BOOT_DELAY_MS (5 * 1000)
#define WIFI_TIMEOUT_MS (15 * 1000)
uint8_t otaLastLogStep = 0;
bool wifiConnected = false;
bool timeSet = false;
time_t preTimeOffset = 0;
unsigned long wifiLastConnectTry = 0;
bool otaInitialized = false;
void otaSetup();
void bootDelay();
void wifiSetup() {
WiFi.softAPdisconnect();
WiFi.setAutoReconnect(false);
wifiConnect();
otaSetup();
bootDelay();
}
void wifiConnect() {
wifiConnected = false;
wifiLastConnectTry = millis();
sntp_stop();
if (otaInitialized) {
otaInitialized = false;
}
mqttDisconnect();
yield();
WiFi.disconnect();
WiFi.enableAP(false);
WiFi.setAutoConnect(false);
WiFi.setAutoReconnect(false);
yield();
String ssid = configGetString("WIFI_SSID", WIFI_SSID, false);
String pkey = configGetString("WIFI_PKEY", WIFI_PKEY, false);
info("WIFI connecting: %s", ssid.c_str());
#ifdef ESP32
WiFiClass::hostname(HOSTNAME);
#else
WiFi.hostname(HOSTNAME);
#endif
yield();
WiFi.begin(ssid, pkey);
yield();
}
void otaSetup() {
ArduinoOTA.setPassword(OTA_PASSWORD);
ArduinoOTA.onStart([] {
info("OTA start...");
otaLastLogStep = 0;
});
ArduinoOTA.onProgress([](unsigned int received, unsigned int total) {
uint8_t currentStep = 20 * received / total;
if (otaLastLogStep != currentStep) {
info("OTA Progress: %3d%%", currentStep * 5);
otaLastLogStep = currentStep;
}
});
ArduinoOTA.onEnd([] {
info("OTA Complete!");
mqttDisconnect();
});
ArduinoOTA.onError([](ota_error_t e) {
const char *name;
switch (e) {
case OTA_AUTH_ERROR:
name = "AUTH";
break;
case OTA_BEGIN_ERROR:
name = "BEGIN";
break;
case OTA_CONNECT_ERROR:
name = "CONNECT";
break;
case OTA_RECEIVE_ERROR:
name = "RECEIVE";
break;
case OTA_END_ERROR:
name = "END";
break;
default:
name = "[???]";
break;
}
error("OTA error: %s", name);
});
}
void bootDelayLoop() {
// TODO merge this into Arduino:loop
consoleLoop();
wifiLoop();
yield();
wdt_reset();
}
void bootDelay() {
#if !BOOT_DELAY
return;
#endif
info("BOOT DELAY: Waiting for WiFi...");
while ((uint32_t) WiFi.localIP() == 0) {
bootDelayLoop();
}
info("BOOT DELAY: WiFi connected!");
info("BOOT DELAY: Waiting %d milliseconds...", BOOT_DELAY_MS);
unsigned long bootDelayBegin = millis();
while (millis() - bootDelayBegin < BOOT_DELAY_MS) {
bootDelayLoop();
}
info("BOOT DELAY: Complete!");
info("BOOT DELAY: Resuming normal boot!");
}
void wifiLoop() {
const time_t epochSeconds = getTime();
if (!timeSet) {
timeSet = epochSeconds >= MIN_EPOCH_SECONDS;
if (!timeSet) {
preTimeOffset = epochSeconds;
} else {
info("Got time via NTP");
}
}
const bool hasIp = static_cast<uint32_t>(WiFi.localIP()) != 0;
if (wifiConnected) {
if (!hasIp) {
wifiConnected = false;
info("WiFi disconnected!");
wifiConnect();
} else {
ArduinoOTA.handle();
}
} else {
if (hasIp) {
wifiConnected = true;
info("WiFi connected: ip=%s", WiFi.localIP().toString().c_str());
ArduinoOTA.begin();
otaInitialized = true;
configTime(TIMEZONE_OFFSET, DST_OFFSET, WiFi.gatewayIP().toString().c_str(), NTP_SERVER);
} else if (millis() - wifiLastConnectTry > WIFI_TIMEOUT_MS) {
info("WiFi timeout!");
wifiConnect();
}
}
}
bool isWiFiConnected() {
return wifiConnected;
}
bool isTimeSet() {
return timeSet;
}
time_t getTime() {
time_t epochSeconds;
time(&epochSeconds);
return epochSeconds;
}
void correctTime(time_t& value) {
if (timeSet && value < MIN_EPOCH_SECONDS) {
value = getTime() - preTimeOffset + value;
}
}
void getDateTime(char *buffer, size_t size) {
time_t now;
time(&now);
tm time{};
localtime_r(&now, &time);
strftime(buffer, size, "%Y-%m-%d %H:%M:%S %z", &time);
}
uint64_t uptimeMillis = 0;
unsigned long uptimeLastMillis = 0;
uint64_t getUptimeMillis() {
unsigned long now = millis();
uptimeMillis += now - uptimeLastMillis;
uptimeLastMillis = now;
return uptimeMillis;
}