📦 Moves setting to folder
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#ifndef CameraSettingsService_h
|
||||
#define CameraSettingsService_h
|
||||
|
||||
#include <settings/camera_settings.h>
|
||||
|
||||
namespace Camera {
|
||||
|
||||
#include <CameraService.h>
|
||||
@@ -17,107 +19,6 @@ namespace Camera {
|
||||
#define EVENT_CAMERA_SETTINGS "CameraSettings"
|
||||
#define CAMERA_SETTINGS_PATH "/api/camera/settings"
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
class CameraSettingsService : public StatefulService<CameraSettings> {
|
||||
public:
|
||||
CameraSettingsService(PsychicHttpServer *server, FS *fs)
|
||||
|
||||
@@ -1,43 +1,31 @@
|
||||
#ifndef JsonUtils_h
|
||||
#define JsonUtils_h
|
||||
|
||||
/**
|
||||
* ESP32 SvelteKit
|
||||
*
|
||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
||||
* https://github.com/theelims/ESP32-sveltekit
|
||||
*
|
||||
* Copyright (C) 2018 - 2023 rjwats
|
||||
* Copyright (C) 2023 theelims
|
||||
*
|
||||
* All Rights Reserved. This software may be modified and distributed under
|
||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
||||
**/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <IPUtils.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
class JsonUtils {
|
||||
public:
|
||||
static void readIP(JsonObject &root, const String &key, IPAddress &ip, const String &def) {
|
||||
static void readIP(const JsonObject &root, const String &key, IPAddress &ip, const String &def) {
|
||||
IPAddress defaultIp = {};
|
||||
if (!defaultIp.fromString(def)) {
|
||||
defaultIp = INADDR_NONE;
|
||||
}
|
||||
readIP(root, key, ip, defaultIp);
|
||||
}
|
||||
static void readIP(JsonObject &root, const String &key, IPAddress &ip, const IPAddress &defaultIp = INADDR_NONE) {
|
||||
|
||||
static void readIP(const JsonObject &root, const String &key, IPAddress &ip,
|
||||
const IPAddress &defaultIp = INADDR_NONE) {
|
||||
if (!root[key].is<String>() || !ip.fromString(root[key].as<String>())) {
|
||||
ip = defaultIp;
|
||||
}
|
||||
}
|
||||
|
||||
static void writeIP(JsonObject &root, const String &key, const IPAddress &ip) {
|
||||
if (IPUtils::isSet(ip)) {
|
||||
root[key] = ip.toString();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // end JsonUtils
|
||||
#endif // end JsonUtils
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <Timing.h>
|
||||
#include <filesystem.h>
|
||||
#include <Features.h>
|
||||
#include <settings/peripherals_settings.h>
|
||||
|
||||
#include <list>
|
||||
#include <SPI.h>
|
||||
@@ -55,50 +56,6 @@
|
||||
*/
|
||||
#define MAX_DISTANCE 200
|
||||
|
||||
/*
|
||||
* 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 100000UL
|
||||
#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;
|
||||
};
|
||||
};
|
||||
|
||||
class Peripherals : public StatefulService<PeripheralsConfiguration> {
|
||||
public:
|
||||
Peripherals(PsychicHttpServer *server, FS *fs)
|
||||
|
||||
@@ -10,63 +10,11 @@
|
||||
#include <stateful_service_endpoint.h>
|
||||
#include <MathUtils.h>
|
||||
#include <Timing.h>
|
||||
#include <settings/servo_settings.h>
|
||||
|
||||
#define EVENT_SERVO_CONFIGURATION_SETTINGS "servoPWM"
|
||||
#define EVENT_SERVO_STATE "servoState"
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
class ServoController : public StatefulService<ServoSettings> {
|
||||
public:
|
||||
ServoController(PsychicHttpServer *server, FS *fs, Peripherals *peripherals)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <StatefulService.h>
|
||||
#include <stateful_service_endpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
#include <ap_settings.h>
|
||||
#include <settings/ap_settings.h>
|
||||
#include <Timing.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <FSPersistence.h>
|
||||
#include <WiFi.h>
|
||||
#include <stateful_service_endpoint.h>
|
||||
#include <domain/ntp_settings.h>
|
||||
#include <settings/ntp_settings.h>
|
||||
|
||||
#include <lwip/apps/sntp.h>
|
||||
#include <time.h>
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
|
||||
namespace Camera {
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <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,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <ArduinoJson.h>
|
||||
#include <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 100000UL
|
||||
#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 <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,135 @@
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <IPAddress.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <JsonUtils.h>
|
||||
#include <IPUtils.h>
|
||||
#include <string_utilities.h>
|
||||
#include <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) {
|
||||
settings.wifiSettings.push_back(createDefaultWiFiSettings());
|
||||
}
|
||||
ESP_LOGV("WiFiSettings", "WiFi Settings updated");
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
};
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <StatefulService.h>
|
||||
#include <FSPersistence.h>
|
||||
#include <stateful_service_endpoint.h>
|
||||
#include <wifi_settings.h>
|
||||
#include <settings/wifi_settings.h>
|
||||
|
||||
class WiFiService : public StatefulService<WiFiSettings> {
|
||||
private:
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <IPAddress.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <JsonUtils.h>
|
||||
#include <IPUtils.h>
|
||||
#include <string_utilities.h>
|
||||
#include <state_result.h>
|
||||
|
||||
#ifndef FACTORY_WIFI_RSSI_THRESHOLD
|
||||
#define FACTORY_WIFI_RSSI_THRESHOLD -80
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
String ssid;
|
||||
String password;
|
||||
bool staticIPConfig;
|
||||
IPAddress localIP;
|
||||
IPAddress gatewayIP;
|
||||
IPAddress subnetMask;
|
||||
IPAddress dnsIP1;
|
||||
IPAddress dnsIP2;
|
||||
bool available;
|
||||
} wifi_settings_t;
|
||||
|
||||
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;
|
||||
|
||||
// create JSON array from root
|
||||
JsonArray wifiNetworks = root["wifi_networks"].to<JsonArray>();
|
||||
|
||||
// iterate over the wifiSettings
|
||||
for (auto &wifi : settings.wifiSettings) {
|
||||
// create JSON object for each wifi network
|
||||
JsonObject wifiNetwork = wifiNetworks.add<JsonObject>();
|
||||
|
||||
// add the ssid and password to the JSON object
|
||||
wifiNetwork["ssid"] = wifi.ssid;
|
||||
wifiNetwork["password"] = wifi.password;
|
||||
wifiNetwork["static_ip_config"] = wifi.staticIPConfig;
|
||||
|
||||
// extended settings
|
||||
JsonUtils::writeIP(root, "local_ip", wifi.localIP);
|
||||
JsonUtils::writeIP(root, "gateway_ip", wifi.gatewayIP);
|
||||
JsonUtils::writeIP(root, "subnet_mask", wifi.subnetMask);
|
||||
JsonUtils::writeIP(root, "dns_ip_1", wifi.dnsIP1);
|
||||
JsonUtils::writeIP(root, "dns_ip_2", wifi.dnsIP2);
|
||||
}
|
||||
|
||||
ESP_LOGV("WiFiSettings", "WiFi Settings read");
|
||||
}
|
||||
|
||||
static StateUpdateResult update(JsonObject &root, WiFiSettings &settings) {
|
||||
settings.hostname = root["hostname"] | format(FACTORY_WIFI_HOSTNAME);
|
||||
settings.priorityBySignalStrength = root["priority_RSSI"] | true;
|
||||
|
||||
settings.wifiSettings.clear();
|
||||
|
||||
// create JSON array from root
|
||||
JsonArray wifiNetworks = root["wifi_networks"];
|
||||
if (root["wifi_networks"].is<JsonArray>()) {
|
||||
// iterate over the wifiSettings
|
||||
int i = 0;
|
||||
for (auto wifiNetwork : wifiNetworks) {
|
||||
// max 5 wifi networks
|
||||
if (i++ >= 5) {
|
||||
ESP_LOGE("WiFiSettings", "Too many wifi networks");
|
||||
break;
|
||||
}
|
||||
|
||||
// create JSON object for each wifi network
|
||||
JsonObject wifi = wifiNetwork.as<JsonObject>();
|
||||
|
||||
// Check if SSID length is between 1 and 31 characters and password between 0 and 64 characters
|
||||
if (wifi["ssid"].as<String>().length() < 1 || wifi["ssid"].as<String>().length() > 31 ||
|
||||
wifi["password"].as<String>().length() > 64) {
|
||||
ESP_LOGE("WiFiSettings", "SSID or password length is invalid");
|
||||
} else {
|
||||
// add the ssid and password to the JSON object
|
||||
wifi_settings_t wifiSettings;
|
||||
|
||||
wifiSettings.ssid = wifi["ssid"].as<String>();
|
||||
wifiSettings.password = wifi["password"].as<String>();
|
||||
wifiSettings.staticIPConfig = wifi["static_ip_config"];
|
||||
|
||||
// extended settings
|
||||
JsonUtils::readIP(wifi, "local_ip", wifiSettings.localIP);
|
||||
JsonUtils::readIP(wifi, "gateway_ip", wifiSettings.gatewayIP);
|
||||
JsonUtils::readIP(wifi, "subnet_mask", wifiSettings.subnetMask);
|
||||
JsonUtils::readIP(wifi, "dns_ip_1", wifiSettings.dnsIP1);
|
||||
JsonUtils::readIP(wifi, "dns_ip_2", wifiSettings.dnsIP2);
|
||||
|
||||
// Swap around the dns servers if 2 is populated but 1 is not
|
||||
if (IPUtils::isNotSet(wifiSettings.dnsIP1) && IPUtils::isSet(wifiSettings.dnsIP2)) {
|
||||
wifiSettings.dnsIP1 = wifiSettings.dnsIP2;
|
||||
wifiSettings.dnsIP2 = INADDR_NONE;
|
||||
}
|
||||
|
||||
// Turning off static ip config if we don't meet the minimum requirements
|
||||
// of ipAddress, gateway and subnet. This may change to static ip only
|
||||
// as sensible defaults can be assumed for gateway and subnet
|
||||
if (wifiSettings.staticIPConfig &&
|
||||
(IPUtils::isNotSet(wifiSettings.localIP) || IPUtils::isNotSet(wifiSettings.gatewayIP) ||
|
||||
IPUtils::isNotSet(wifiSettings.subnetMask))) {
|
||||
wifiSettings.staticIPConfig = false;
|
||||
}
|
||||
|
||||
// reset scan result
|
||||
wifiSettings.available = false;
|
||||
settings.wifiSettings.push_back(wifiSettings);
|
||||
|
||||
// increment the wifi network index
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// populate with factory defaults if they are present
|
||||
if (String(FACTORY_WIFI_SSID).length() > 0) {
|
||||
settings.wifiSettings.push_back(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,
|
||||
});
|
||||
}
|
||||
}
|
||||
ESP_LOGV("WiFiSettings", "WiFi Settings updated");
|
||||
|
||||
return StateUpdateResult::CHANGED;
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user