Sensor3/lib/patrix/wifi.cpp

207 lines
4.2 KiB
C++

#include "wifi.h"
#include "log.h"
#include "mqtt.h"
#include "console.h"
#include <WiFi.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 (10 * 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;
void otaSetup();
void bootDelay();
void wifiSetup() {
WiFi.softAPdisconnect();
WiFi.setAutoReconnect(false);
wifiConnect();
otaSetup();
bootDelay();
}
void wifiConnect() {
wifiConnected = false;
wifiLastConnectTry = millis();
sntp_stop();
ArduinoOTA.end();
mqttDisconnect();
WiFi.disconnect();
WiFi.enableAP(false);
WiFi.setAutoConnect(false);
WiFi.setAutoReconnect(false);
yield();
info("WIFI connecting: %s", WIFI_SSID);
WiFiClass::hostname(HOSTNAME);
yield();
WiFi.begin(WIFI_SSID, WIFI_PKEY);
yield();
}
void otaSetup() {
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!");
});
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(name);
});
}
void bootDelay() {
#if !BOOT_DELAY
return;
#endif
info("BOOT DELAY", "BOOT DELAY: Waiting for WiFi...");
while ((uint32_t) WiFi.localIP() == 0) {
consoleLoop();
wifiLoop();
}
info("BOOT DELAY", "BOOT DELAY: WiFi connected!");
info("BOOT DELAY", "BOOT DELAY: Waiting 10 seconds...");
unsigned long bootDelayBegin = millis();
while (millis() - bootDelayBegin < BOOT_DELAY_MS) {
consoleLoop();
wifiLoop();
}
info("BOOT DELAY", "BOOT DELAY: Complete!");
info("BOOT DELAY", "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();
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;
}
time_t correctTime(const time_t value) {
if (!timeSet) {
return value;
}
if (value < MIN_EPOCH_SECONDS) {
return getTime() - preTimeOffset + value;
}
return value;
}
bool isOlderThan(time_t time, time_t seconds) {
return getTime() > correctTime(time) + seconds;
}
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;
}