🎨 Moving project to use event bus
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <IPAddress.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <utils/json_utils.h>
|
||||
#include <utils/string_utils.h>
|
||||
#include <utils/ip_utils.h>
|
||||
#include <template/state_result.h>
|
||||
|
||||
#include <DNSServer.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
#ifndef FACTORY_AP_PROVISION_MODE
|
||||
#define FACTORY_AP_PROVISION_MODE AP_MODE_DISCONNECTED
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_SSID
|
||||
#define FACTORY_AP_SSID "ESP32-SvelteKit-#{unique_id}"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_PASSWORD
|
||||
#define FACTORY_AP_PASSWORD "esp-sveltekit"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_LOCAL_IP
|
||||
#define FACTORY_AP_LOCAL_IP "192.168.4.1"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_GATEWAY_IP
|
||||
#define FACTORY_AP_GATEWAY_IP "192.168.4.1"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_SUBNET_MASK
|
||||
#define FACTORY_AP_SUBNET_MASK "255.255.255.0"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_CHANNEL
|
||||
#define FACTORY_AP_CHANNEL 1
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_SSID_HIDDEN
|
||||
#define FACTORY_AP_SSID_HIDDEN false
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_AP_MAX_CLIENTS
|
||||
#define FACTORY_AP_MAX_CLIENTS 4
|
||||
#endif
|
||||
|
||||
#define AP_MODE_ALWAYS 0
|
||||
#define AP_MODE_DISCONNECTED 1
|
||||
#define AP_MODE_NEVER 2
|
||||
|
||||
#define MANAGE_NETWORK_DELAY 10000
|
||||
#define DNS_PORT 53
|
||||
|
||||
enum APNetworkStatus { ACTIVE = 0, INACTIVE, LINGERING };
|
||||
|
||||
class APSettings {
|
||||
public:
|
||||
uint8_t provisionMode;
|
||||
String ssid;
|
||||
String password;
|
||||
uint8_t channel;
|
||||
bool ssidHidden;
|
||||
uint8_t maxClients;
|
||||
|
||||
IPAddress localIP;
|
||||
IPAddress gatewayIP;
|
||||
IPAddress subnetMask;
|
||||
|
||||
bool operator==(const APSettings &settings) const {
|
||||
return provisionMode == settings.provisionMode && ssid == settings.ssid && password == settings.password &&
|
||||
channel == settings.channel && ssidHidden == settings.ssidHidden && maxClients == settings.maxClients &&
|
||||
localIP == settings.localIP && gatewayIP == settings.gatewayIP && subnetMask == settings.subnetMask;
|
||||
}
|
||||
|
||||
static void read(APSettings &settings, JsonObject &root) {
|
||||
root["provision_mode"] = settings.provisionMode;
|
||||
root["ssid"] = settings.ssid;
|
||||
root["password"] = settings.password;
|
||||
root["channel"] = settings.channel;
|
||||
root["ssid_hidden"] = settings.ssidHidden;
|
||||
root["max_clients"] = settings.maxClients;
|
||||
root["local_ip"] = settings.localIP.toString();
|
||||
root["gateway_ip"] = settings.gatewayIP.toString();
|
||||
root["subnet_mask"] = settings.subnetMask.toString();
|
||||
}
|
||||
|
||||
static StateUpdateResult update(JsonObject &root, APSettings &settings) {
|
||||
APSettings newSettings = {};
|
||||
newSettings.provisionMode = root["provision_mode"] | FACTORY_AP_PROVISION_MODE;
|
||||
switch (settings.provisionMode) {
|
||||
case AP_MODE_ALWAYS:
|
||||
case AP_MODE_DISCONNECTED:
|
||||
case AP_MODE_NEVER: break;
|
||||
default: newSettings.provisionMode = AP_MODE_DISCONNECTED;
|
||||
}
|
||||
newSettings.ssid = root["ssid"] | format(FACTORY_AP_SSID);
|
||||
newSettings.password = root["password"] | FACTORY_AP_PASSWORD;
|
||||
newSettings.channel = root["channel"] | FACTORY_AP_CHANNEL;
|
||||
newSettings.ssidHidden = root["ssid_hidden"] | FACTORY_AP_SSID_HIDDEN;
|
||||
newSettings.maxClients = root["max_clients"] | FACTORY_AP_MAX_CLIENTS;
|
||||
|
||||
JsonUtils::readIP(root, "local_ip", newSettings.localIP, FACTORY_AP_LOCAL_IP);
|
||||
JsonUtils::readIP(root, "gateway_ip", newSettings.gatewayIP, FACTORY_AP_GATEWAY_IP);
|
||||
JsonUtils::readIP(root, "subnet_mask", newSettings.subnetMask, FACTORY_AP_SUBNET_MASK);
|
||||
|
||||
if (newSettings == settings) {
|
||||
return StateUpdateResult::UNCHANGED;
|
||||
}
|
||||
settings = newSettings;
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
|
||||
namespace Camera {
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <template/state_result.h>
|
||||
#include <esp_camera.h>
|
||||
|
||||
class CameraSettings {
|
||||
public:
|
||||
pixformat_t pixformat;
|
||||
framesize_t framesize; // 0 - 10
|
||||
uint8_t quality; // 0 - 63
|
||||
int8_t brightness; //-2 - 2
|
||||
int8_t contrast; //-2 - 2
|
||||
int8_t saturation; //-2 - 2
|
||||
int8_t sharpness; //-2 - 2
|
||||
uint8_t denoise;
|
||||
gainceiling_t gainceiling;
|
||||
uint8_t whitebal;
|
||||
uint8_t special_effect; // 0 - 6
|
||||
uint8_t wb_mode; // 0 - 4
|
||||
uint8_t awb;
|
||||
uint8_t exposure_ctrl;
|
||||
uint8_t awb_gain;
|
||||
uint8_t gain_ctrl;
|
||||
uint8_t aec;
|
||||
uint8_t aec2;
|
||||
int8_t ae_level; //-2 - 2
|
||||
uint16_t aec_value; // 0 - 1200
|
||||
uint8_t agc;
|
||||
uint8_t agc_gain; // 0 - 30
|
||||
uint8_t bpc;
|
||||
uint8_t wpc;
|
||||
uint8_t raw_gma;
|
||||
uint8_t lenc;
|
||||
uint8_t hmirror;
|
||||
uint8_t vflip;
|
||||
uint8_t dcw;
|
||||
uint8_t colorbar;
|
||||
|
||||
static void read(CameraSettings &settings, JsonObject &root) {
|
||||
root["pixformat"] = settings.pixformat;
|
||||
root["framesize"] = settings.framesize;
|
||||
root["quality"] = settings.quality;
|
||||
root["brightness"] = settings.brightness;
|
||||
root["contrast"] = settings.contrast;
|
||||
root["saturation"] = settings.saturation;
|
||||
root["sharpness"] = settings.sharpness;
|
||||
root["denoise"] = settings.denoise;
|
||||
root["special_effect"] = settings.special_effect;
|
||||
root["wb_mode"] = settings.wb_mode;
|
||||
root["exposure_ctrl"] = settings.exposure_ctrl;
|
||||
root["gain_ctrl"] = settings.gain_ctrl;
|
||||
root["awb"] = settings.awb;
|
||||
root["awb_gain"] = settings.awb_gain;
|
||||
root["aec"] = settings.aec;
|
||||
root["aec2"] = settings.aec2;
|
||||
root["ae_level"] = settings.ae_level;
|
||||
root["aec_value"] = settings.aec_value;
|
||||
root["agc"] = settings.agc;
|
||||
root["agc_gain"] = settings.agc_gain;
|
||||
root["gainceiling"] = settings.gainceiling;
|
||||
root["bpc"] = settings.bpc;
|
||||
root["wpc"] = settings.wpc;
|
||||
root["raw_gma"] = settings.raw_gma;
|
||||
root["lenc"] = settings.lenc;
|
||||
root["hmirror"] = settings.hmirror;
|
||||
root["vflip"] = settings.vflip;
|
||||
root["dcw"] = settings.dcw;
|
||||
root["colorbar"] = settings.colorbar;
|
||||
}
|
||||
|
||||
static StateUpdateResult update(JsonObject &root, CameraSettings &settings) {
|
||||
settings.pixformat = root["pixformat"];
|
||||
settings.framesize = root["framesize"];
|
||||
settings.brightness = root["brightness"];
|
||||
settings.contrast = root["contrast"];
|
||||
settings.quality = root["quality"];
|
||||
settings.contrast = root["contrast"];
|
||||
settings.saturation = root["saturation"];
|
||||
settings.sharpness = root["sharpness"];
|
||||
settings.denoise = root["denoise"];
|
||||
settings.exposure_ctrl = root["exposure_ctrl"];
|
||||
settings.gain_ctrl = root["gain_ctrl"];
|
||||
settings.special_effect = root["special_effect"];
|
||||
settings.wb_mode = root["wb_mode"];
|
||||
settings.awb = root["awb"];
|
||||
settings.awb_gain = root["awb_gain"];
|
||||
settings.aec = root["aec"];
|
||||
settings.aec2 = root["aec2"];
|
||||
settings.ae_level = root["ae_level"];
|
||||
settings.aec_value = root["aec_value"];
|
||||
settings.agc = root["agc"];
|
||||
settings.agc_gain = root["agc_gain"];
|
||||
settings.gainceiling = root["gainceiling"];
|
||||
settings.bpc = root["bpc"];
|
||||
settings.wpc = root["wpc"];
|
||||
settings.raw_gma = root["raw_gma"];
|
||||
settings.lenc = root["lenc"];
|
||||
settings.hmirror = root["hmirror"];
|
||||
settings.vflip = root["vflip"];
|
||||
settings.dcw = root["dcw"];
|
||||
settings.colorbar = root["colorbar"];
|
||||
|
||||
return StateUpdateResult::CHANGED;
|
||||
};
|
||||
};
|
||||
} // namespace Camera
|
||||
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <utils/json_utils.h>
|
||||
#include <utils/string_utils.h>
|
||||
#include <template/state_result.h>
|
||||
#include <filesystem.h>
|
||||
|
||||
#ifndef FACTORY_MDNS_HOSTNAME
|
||||
#define FACTORY_MDNS_HOSTNAME "esp32"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_MDNS_INSTANCE
|
||||
#define FACTORY_MDNS_INSTANCE "ESP32 Device"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
String key;
|
||||
String value;
|
||||
|
||||
void serialize(JsonObject &json) const {
|
||||
json["key"] = key;
|
||||
json["value"] = value;
|
||||
}
|
||||
|
||||
bool deserialize(const JsonObject &json) {
|
||||
key = json["key"].as<String>();
|
||||
value = json["value"].as<String>();
|
||||
|
||||
return key.length() > 0;
|
||||
}
|
||||
} mdns_txt_record_t;
|
||||
|
||||
typedef struct {
|
||||
String service;
|
||||
String protocol;
|
||||
uint16_t port;
|
||||
std::vector<mdns_txt_record_t> txtRecords;
|
||||
|
||||
void serialize(JsonObject &json) const {
|
||||
json["service"] = service;
|
||||
json["protocol"] = protocol;
|
||||
json["port"] = port;
|
||||
|
||||
if (txtRecords.size() > 0) {
|
||||
JsonArray txtArray = json["txt_records"].to<JsonArray>();
|
||||
for (const auto &txt : txtRecords) {
|
||||
JsonObject txtObj = txtArray.add<JsonObject>();
|
||||
txt.serialize(txtObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool deserialize(const JsonObject &json) {
|
||||
service = json["service"].as<String>();
|
||||
protocol = json["protocol"].as<String>();
|
||||
port = json["port"] | 0;
|
||||
|
||||
txtRecords.clear();
|
||||
if (json["txt_records"].is<JsonArray>()) {
|
||||
JsonArray txtArray = json["txt_records"];
|
||||
for (JsonObject txtObj : txtArray) {
|
||||
mdns_txt_record_t txt;
|
||||
if (txt.deserialize(txtObj)) {
|
||||
txtRecords.push_back(txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return service.length() > 0 && protocol.length() > 0 && port > 0;
|
||||
}
|
||||
} mdns_service_t;
|
||||
|
||||
class MDNSSettings {
|
||||
public:
|
||||
String hostname;
|
||||
String instance;
|
||||
std::vector<mdns_service_t> services;
|
||||
std::vector<mdns_txt_record_t> globalTxtRecords;
|
||||
|
||||
static void read(MDNSSettings &settings, JsonObject &root) {
|
||||
root["hostname"] = settings.hostname;
|
||||
root["instance"] = settings.instance;
|
||||
|
||||
JsonArray servicesArray = root["services"].to<JsonArray>();
|
||||
for (const auto &service : settings.services) {
|
||||
JsonObject serviceObj = servicesArray.add<JsonObject>();
|
||||
service.serialize(serviceObj);
|
||||
}
|
||||
|
||||
JsonArray txtArray = root["global_txt_records"].to<JsonArray>();
|
||||
for (const auto &txt : settings.globalTxtRecords) {
|
||||
JsonObject txtObj = txtArray.add<JsonObject>();
|
||||
txt.serialize(txtObj);
|
||||
}
|
||||
}
|
||||
|
||||
static StateUpdateResult update(JsonObject &root, MDNSSettings &settings) {
|
||||
settings.hostname = root["hostname"] | FACTORY_MDNS_HOSTNAME;
|
||||
settings.instance = root["instance"] | FACTORY_MDNS_INSTANCE;
|
||||
|
||||
settings.services.clear();
|
||||
if (root["services"].is<JsonArray>()) {
|
||||
JsonArray servicesArray = root["services"];
|
||||
for (JsonObject serviceObj : servicesArray) {
|
||||
mdns_service_t service;
|
||||
if (service.deserialize(serviceObj)) {
|
||||
settings.services.push_back(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.services.empty()) {
|
||||
mdns_service_t httpService = {.service = "http", .protocol = "tcp", .port = 80};
|
||||
settings.services.push_back(httpService);
|
||||
|
||||
mdns_service_t wsService = {.service = "ws", .protocol = "tcp", .port = 80};
|
||||
settings.services.push_back(wsService);
|
||||
}
|
||||
|
||||
settings.globalTxtRecords.clear();
|
||||
if (root["global_txt_records"].is<JsonArray>()) {
|
||||
JsonArray txtArray = root["global_txt_records"];
|
||||
for (JsonObject txtObj : txtArray) {
|
||||
mdns_txt_record_t txt;
|
||||
if (txt.deserialize(txtObj)) {
|
||||
settings.globalTxtRecords.push_back(txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.globalTxtRecords.empty()) {
|
||||
mdns_txt_record_t firmwareVersion = {.key = "Firmware Version", .value = APP_VERSION};
|
||||
settings.globalTxtRecords.push_back(firmwareVersion);
|
||||
}
|
||||
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <Arduino.h>
|
||||
#include <template/state_result.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#ifndef FACTORY_NTP_ENABLED
|
||||
#define FACTORY_NTP_ENABLED true
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_NTP_TIME_ZONE_LABEL
|
||||
#define FACTORY_NTP_TIME_ZONE_LABEL "Europe/London"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_NTP_TIME_ZONE_FORMAT
|
||||
#define FACTORY_NTP_TIME_ZONE_FORMAT "GMT0BST,M3.5.0/1,M10.5.0"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_NTP_SERVER
|
||||
#define FACTORY_NTP_SERVER "time.google.com"
|
||||
#endif
|
||||
|
||||
class NTPSettings {
|
||||
public:
|
||||
bool enabled;
|
||||
String tzLabel;
|
||||
String tzFormat;
|
||||
String server;
|
||||
|
||||
static void read(NTPSettings &settings, JsonObject &root) {
|
||||
root["enabled"] = settings.enabled;
|
||||
root["server"] = settings.server;
|
||||
root["tz_label"] = settings.tzLabel;
|
||||
root["tz_format"] = settings.tzFormat;
|
||||
}
|
||||
|
||||
static StateUpdateResult update(JsonObject &root, NTPSettings &settings) {
|
||||
settings.enabled = root["enabled"] | FACTORY_NTP_ENABLED;
|
||||
settings.server = root["server"] | FACTORY_NTP_SERVER;
|
||||
settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL;
|
||||
settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT;
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <ArduinoJson.h>
|
||||
#include <template/state_result.h>
|
||||
|
||||
/*
|
||||
* I2C software connection
|
||||
*/
|
||||
#ifndef SDA_PIN
|
||||
#define SDA_PIN SDA
|
||||
#endif
|
||||
#ifndef SCL_PIN
|
||||
#define SCL_PIN SCL
|
||||
#endif
|
||||
#ifndef I2C_FREQUENCY
|
||||
#define I2C_FREQUENCY 1000000UL
|
||||
#endif
|
||||
|
||||
class PinConfig {
|
||||
public:
|
||||
int pin;
|
||||
String mode;
|
||||
String type;
|
||||
String role;
|
||||
|
||||
PinConfig(int p, String m, String t, String r) : pin(p), mode(m), type(t), role(r) {}
|
||||
};
|
||||
|
||||
class PeripheralsConfiguration {
|
||||
public:
|
||||
int sda = SDA_PIN;
|
||||
int scl = SCL_PIN;
|
||||
long frequency = I2C_FREQUENCY;
|
||||
std::vector<PinConfig> pins;
|
||||
|
||||
static void read(PeripheralsConfiguration &settings, JsonObject &root) {
|
||||
root["sda"] = settings.sda;
|
||||
root["scl"] = settings.scl;
|
||||
root["frequency"] = settings.frequency;
|
||||
}
|
||||
|
||||
static StateUpdateResult update(JsonObject &root, PeripheralsConfiguration &settings) {
|
||||
settings.sda = root["sda"] | SDA_PIN;
|
||||
settings.scl = root["scl"] | SCL_PIN;
|
||||
settings.frequency = root["frequency"] | I2C_FREQUENCY;
|
||||
return StateUpdateResult::CHANGED;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <template/state_result.h>
|
||||
|
||||
typedef struct {
|
||||
float centerPwm;
|
||||
float direction;
|
||||
float centerAngle;
|
||||
float conversion;
|
||||
const char *name;
|
||||
// bool enable;
|
||||
} servo_settings_t;
|
||||
|
||||
class ServoSettings {
|
||||
public:
|
||||
servo_settings_t servos[12] = {
|
||||
{306, -1, 0, 2.2, "Servo1"}, {306, 1, -45, 2.1055555, "Servo2"}, {306, 1, 90, 1.96923, "Servo3"},
|
||||
{306, -1, 0, 2.2, "Servo4"}, {306, -1, 45, 2.1055555, "Servo5"}, {306, -1, -90, 1.96923, "Servo6"},
|
||||
{306, 1, 0, 2.2, "Servo7"}, {306, 1, -45, 2.1055555, "Servo8"}, {306, 1, 90, 1.96923, "Servo9"},
|
||||
{306, 1, 0, 2.2, "Servo10"}, {306, -1, 45, 2.1055555, "Servo11"}, {306, -1, -90, 1.96923, "Servo12"}};
|
||||
static void read(ServoSettings &settings, JsonObject &root) {
|
||||
JsonArray servos = root["servos"].to<JsonArray>();
|
||||
for (auto &servo : settings.servos) {
|
||||
JsonObject newServo = servos.add<JsonObject>();
|
||||
newServo["center_pwm"] = servo.centerPwm;
|
||||
newServo["direction"] = servo.direction;
|
||||
newServo["center_angle"] = servo.centerAngle;
|
||||
newServo["conversion"] = servo.conversion;
|
||||
}
|
||||
}
|
||||
static StateUpdateResult update(JsonObject &root, ServoSettings &settings) {
|
||||
if (root["servos"].is<JsonArray>()) {
|
||||
JsonArray servosJson = root["servos"];
|
||||
int i = 0;
|
||||
for (auto servo : servosJson) {
|
||||
JsonObject servoObject = servo.as<JsonObject>();
|
||||
uint8_t servoId = i; // servoObject["id"].as<uint8_t>();
|
||||
settings.servos[servoId].centerPwm = servoObject["center_pwm"].as<float>();
|
||||
settings.servos[servoId].centerAngle = servoObject["center_angle"].as<float>();
|
||||
settings.servos[servoId].direction = servoObject["direction"].as<float>();
|
||||
settings.servos[servoId].conversion = servoObject["conversion"].as<float>();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
ESP_LOGI("ServoController", "Updating servo data");
|
||||
return StateUpdateResult::CHANGED;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <IPAddress.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <utils/json_utils.h>
|
||||
#include <utils/ip_utils.h>
|
||||
#include <utils/string_utils.h>
|
||||
#include <template/state_result.h>
|
||||
|
||||
#ifndef FACTORY_WIFI_SSID
|
||||
#define FACTORY_WIFI_SSID ""
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_WIFI_PASSWORD
|
||||
#define FACTORY_WIFI_PASSWORD ""
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_WIFI_HOSTNAME
|
||||
#define FACTORY_WIFI_HOSTNAME "#{platform}-#{unique_id}"
|
||||
#endif
|
||||
|
||||
#ifndef FACTORY_WIFI_RSSI_THRESHOLD
|
||||
#define FACTORY_WIFI_RSSI_THRESHOLD -80
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
String ssid;
|
||||
uint8_t bssid[6];
|
||||
int32_t channel;
|
||||
String password;
|
||||
bool staticIPConfig;
|
||||
IPAddress localIP;
|
||||
IPAddress gatewayIP;
|
||||
IPAddress subnetMask;
|
||||
IPAddress dnsIP1;
|
||||
IPAddress dnsIP2;
|
||||
bool available;
|
||||
|
||||
void serialize(JsonObject &json) const {
|
||||
json["ssid"] = ssid;
|
||||
json["password"] = password;
|
||||
json["static_ip_config"] = staticIPConfig;
|
||||
if (staticIPConfig) {
|
||||
JsonUtils::writeIP(json, "local_ip", localIP);
|
||||
JsonUtils::writeIP(json, "gateway_ip", gatewayIP);
|
||||
JsonUtils::writeIP(json, "subnet_mask", subnetMask);
|
||||
JsonUtils::writeIP(json, "dns_ip_1", dnsIP1);
|
||||
JsonUtils::writeIP(json, "dns_ip_2", dnsIP2);
|
||||
}
|
||||
}
|
||||
|
||||
bool deserialize(const JsonObject &json) {
|
||||
String newSsid = json["ssid"].as<String>();
|
||||
String newPassword = json["password"].as<String>();
|
||||
if (newSsid.length() < 1 || newSsid.length() > 31 || newPassword.length() > 64) {
|
||||
ESP_LOGE("WiFiSettings", "SSID or password length is invalid");
|
||||
return false;
|
||||
}
|
||||
ssid = newSsid;
|
||||
password = newPassword;
|
||||
staticIPConfig = json["static_ip_config"] | false;
|
||||
if (staticIPConfig) {
|
||||
JsonUtils::readIP(json, "local_ip", localIP);
|
||||
JsonUtils::readIP(json, "gateway_ip", gatewayIP);
|
||||
JsonUtils::readIP(json, "subnet_mask", subnetMask);
|
||||
JsonUtils::readIP(json, "dns_ip_1", dnsIP1);
|
||||
JsonUtils::readIP(json, "dns_ip_2", dnsIP2);
|
||||
if (IPUtils::isNotSet(dnsIP1) && IPUtils::isSet(dnsIP2)) {
|
||||
dnsIP1 = dnsIP2;
|
||||
dnsIP2 = INADDR_NONE;
|
||||
}
|
||||
if (IPUtils::isNotSet(localIP) || IPUtils::isNotSet(gatewayIP) || IPUtils::isNotSet(subnetMask)) {
|
||||
staticIPConfig = false;
|
||||
ESP_LOGW("WiFiSettings", "Invalid static IP configuration - falling back to DHCP");
|
||||
}
|
||||
}
|
||||
available = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} wifi_settings_t;
|
||||
|
||||
inline wifi_settings_t createDefaultWiFiSettings() {
|
||||
return wifi_settings_t {.ssid = FACTORY_WIFI_SSID,
|
||||
.password = FACTORY_WIFI_PASSWORD,
|
||||
.staticIPConfig = false,
|
||||
.localIP = INADDR_NONE,
|
||||
.gatewayIP = INADDR_NONE,
|
||||
.subnetMask = INADDR_NONE,
|
||||
.dnsIP1 = INADDR_NONE,
|
||||
.dnsIP2 = INADDR_NONE,
|
||||
.available = false};
|
||||
}
|
||||
|
||||
class WiFiSettings {
|
||||
public:
|
||||
String hostname;
|
||||
bool priorityBySignalStrength;
|
||||
std::vector<wifi_settings_t> wifiSettings;
|
||||
static void read(WiFiSettings &settings, JsonObject &root) {
|
||||
root["hostname"] = settings.hostname;
|
||||
root["priority_RSSI"] = settings.priorityBySignalStrength;
|
||||
JsonArray wifiNetworks = root["wifi_networks"].to<JsonArray>();
|
||||
for (const auto &wifi : settings.wifiSettings) {
|
||||
JsonObject wifiNetwork = wifiNetworks.add<JsonObject>();
|
||||
wifi.serialize(wifiNetwork);
|
||||
}
|
||||
ESP_LOGV("WiFiSettings", "WiFi Settings read");
|
||||
}
|
||||
static StateUpdateResult update(JsonObject &root, WiFiSettings &settings) {
|
||||
settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME;
|
||||
settings.priorityBySignalStrength = root["priority_RSSI"] | true;
|
||||
settings.wifiSettings.clear();
|
||||
if (root["wifi_networks"].is<JsonArray>()) {
|
||||
JsonArray wifiNetworks = root["wifi_networks"];
|
||||
int networkCount = 0;
|
||||
for (JsonObject wifiNetwork : wifiNetworks) {
|
||||
if (networkCount >= 5) {
|
||||
ESP_LOGE("WiFiSettings", "Too many wifi networks");
|
||||
break;
|
||||
}
|
||||
wifi_settings_t newSettings;
|
||||
if (newSettings.deserialize(wifiNetwork)) {
|
||||
settings.wifiSettings.push_back(newSettings);
|
||||
networkCount++;
|
||||
}
|
||||
}
|
||||
} else if (String(FACTORY_WIFI_SSID).length() > 0) {
|
||||
ESP_LOGI("WiFiSettings", "No WiFi config found - using factory settings");
|
||||
settings.wifiSettings.push_back(createDefaultWiFiSettings());
|
||||
}
|
||||
ESP_LOGV("WiFiSettings", "WiFi Settings updated");
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user