230 lines
4.7 KiB
C++
230 lines
4.7 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) {
|
|
ArduinoOTA.end();
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|