Configuration and code improvements
This commit is contained in:
@@ -74,7 +74,7 @@ def postbuild(source, target, env):
|
|||||||
uploadfiles = uploadparts[-6:]
|
uploadfiles = uploadparts[-6:]
|
||||||
for i in range(1, len(uploadfiles), 2):
|
for i in range(1, len(uploadfiles), 2):
|
||||||
if not os.path.isfile(uploadfiles[i]):
|
if not os.path.isfile(uploadfiles[i]):
|
||||||
print("file %s for combine not found"%uploadfiles[i])
|
print("file {} for combine not found".format(uploadfiles[i]))
|
||||||
return
|
return
|
||||||
offset = uploadfiles[0]
|
offset = uploadfiles[0]
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,95 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Preferences.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <variant>
|
||||||
|
#include <map>
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
enum class ConfigType {
|
||||||
|
BYTE,
|
||||||
|
SHORT,
|
||||||
|
INT,
|
||||||
|
BOOL,
|
||||||
|
FLOAT,
|
||||||
|
CHAR,
|
||||||
|
STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
using ConfigValue = std::variant<
|
||||||
|
uint8_t, // BYTE unsigned
|
||||||
|
int16_t, // SHORT
|
||||||
|
int32_t, // INT
|
||||||
|
bool, // BOOL
|
||||||
|
float, // FLOAT
|
||||||
|
char, // CHAR
|
||||||
|
String // STRING
|
||||||
|
>;
|
||||||
|
|
||||||
|
struct ConfigDef {
|
||||||
|
const char* key;
|
||||||
|
ConfigType type;
|
||||||
|
ConfigValue defval;
|
||||||
|
};
|
||||||
|
|
||||||
|
// keys have to match names in config.json
|
||||||
|
static const ConfigDef configdefs[] = {
|
||||||
|
{"systemName", ConfigType::STRING, String("OBPkp61")},
|
||||||
|
{"systemMode", ConfigType::CHAR, 'K'},
|
||||||
|
{"logLevel", ConfigType::BYTE, uint8_t(0)},
|
||||||
|
{"adminPassword", ConfigType::STRING, String("obpkp61")},
|
||||||
|
{"useAdminPass", ConfigType::BOOL, true},
|
||||||
|
{"apEnable", ConfigType::BOOL, true},
|
||||||
|
{"apPassword", ConfigType::STRING, String("obpkp61")},
|
||||||
|
{"apIp", ConfigType::STRING, String("192.168.15.1")},
|
||||||
|
{"apMask", ConfigType::STRING, String("255.255.255.0")},
|
||||||
|
{"stopApTime", ConfigType::SHORT, int16_t(0)},
|
||||||
|
{"cpuSpeed", ConfigType::SHORT, int16_t(160)},
|
||||||
|
{"ledBrightness", ConfigType::BYTE, uint8_t(96)},
|
||||||
|
{"ledRgbBrightness", ConfigType::BYTE, uint8_t(96)},
|
||||||
|
{"tempFormat", ConfigType::CHAR, 'C'},
|
||||||
|
{"switchBank", ConfigType::BYTE, uint8_t(0)},
|
||||||
|
{"key1", ConfigType::BYTE, uint8_t(1)},
|
||||||
|
{"key1long", ConfigType::BYTE, uint8_t(11)},
|
||||||
|
{"key2", ConfigType::BYTE, uint8_t(2)},
|
||||||
|
{"key2long", ConfigType::BYTE, uint8_t(12)},
|
||||||
|
{"key3", ConfigType::BYTE, uint8_t(3)},
|
||||||
|
{"key3long", ConfigType::BYTE, uint8_t(13)},
|
||||||
|
{"key4", ConfigType::BYTE, uint8_t(4)},
|
||||||
|
{"key4long", ConfigType::BYTE, uint8_t(14)},
|
||||||
|
{"key5", ConfigType::BYTE, uint8_t(5)},
|
||||||
|
{"key5long", ConfigType::BYTE, uint8_t(15)},
|
||||||
|
{"key6", ConfigType::BYTE, uint8_t(6)},
|
||||||
|
{"key6long", ConfigType::BYTE, uint8_t(16)},
|
||||||
|
{"n2kDestA", ConfigType::STRING, String("")},
|
||||||
|
{"n2kDestB", ConfigType::STRING, String("")},
|
||||||
|
{"n2kDestC", ConfigType::STRING, String("")},
|
||||||
|
{"envInterval", ConfigType::SHORT, int16_t(5000)},
|
||||||
|
|
||||||
|
// no user access
|
||||||
|
{"LastNodeId", ConfigType::BYTE, uint8_t(N2K_DEFAULT_NODEID)}
|
||||||
|
};
|
||||||
|
constexpr size_t configdefsCount = sizeof(configdefs) / sizeof(configdefs[0]);
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
private:
|
private:
|
||||||
Preferences *prefs;
|
Preferences& prefs;
|
||||||
|
std::map<String, ConfigValue> values;
|
||||||
|
std::map<String, const ConfigDef*> defs;
|
||||||
public:
|
public:
|
||||||
Config();
|
explicit Config(Preferences& prefs);
|
||||||
bool loadConfig();
|
void load();
|
||||||
|
bool save(JsonObject json);
|
||||||
|
void dump();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T get(const char* key) const;
|
||||||
|
|
||||||
|
uint8_t getByte(const char* key) const;
|
||||||
|
int16_t getShort(const char* key) const;
|
||||||
|
int32_t getInt(const char* key) const;
|
||||||
|
bool getBool(const char* key) const;
|
||||||
|
float getFloat(const char* key) const;
|
||||||
|
char getChar(const char* key) const;
|
||||||
|
const String& getString(const char* key) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
#define STRINGIFY_IMPL(x) #x
|
#define STRINGIFY_IMPL(x) #x
|
||||||
#define STRINGIFY(x) STRINGIFY_IMPL(x)
|
#define STRINGIFY(x) STRINGIFY_IMPL(x)
|
||||||
@@ -87,14 +88,24 @@
|
|||||||
#define BUTTON_6 5
|
#define BUTTON_6 5
|
||||||
#define BUTTON_DST 6
|
#define BUTTON_DST 6
|
||||||
|
|
||||||
enum class ButtonPressType : uint8_t
|
enum class ButtonPressType : uint8_t {
|
||||||
{
|
|
||||||
SHORT, // < 1 second
|
SHORT, // < 1 second
|
||||||
MEDIUM, // >= 1 second and < 3 seconds
|
MEDIUM, // >= 1 second and < 3 seconds
|
||||||
LONG // >= 3 seconds
|
LONG // >= 3 seconds
|
||||||
};
|
};
|
||||||
struct ButtonEvent
|
|
||||||
{
|
struct ButtonEvent {
|
||||||
uint8_t buttonId;
|
uint8_t buttonId;
|
||||||
ButtonPressType pressType;
|
ButtonPressType pressType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern uint64_t chipid;
|
||||||
|
extern uint8_t led_brightness;
|
||||||
|
extern uint8_t rgb_brightness;
|
||||||
|
extern uint8_t keycode[6];
|
||||||
|
extern uint8_t longcode[6];
|
||||||
|
|
||||||
|
extern float temp;
|
||||||
|
extern float hum;
|
||||||
|
|
||||||
|
String uptime_with_unit();
|
||||||
|
|||||||
11
include/webserver.h
Normal file
11
include/webserver.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
extern AsyncWebServer server;
|
||||||
|
|
||||||
|
void webserver_init();
|
||||||
|
void send_embedded_file(String name, AsyncWebServerRequest *request);
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ build_flags =
|
|||||||
-DBOARD_HAS_PSRAM
|
-DBOARD_HAS_PSRAM
|
||||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-DCORE_DEBUG_LEVEL=4 # Max. possible loglevel: 0=None, 1=Error, 2=Warning, 3=Info, 4=Debug, 5=Verbose
|
-DCORE_DEBUG_LEVEL=4 # Max. possible loglevel: 0=None, 1=Error, 2=Warning, 3=Info, 4=Debug, 5=Verbose
|
||||||
-DCONFIG_LOG_TX_BUF_SIZE=4096
|
-DCONFIG_LOG_TX_BUF_SIZE=8192
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
|
|||||||
284
src/config.cpp
284
src/config.cpp
@@ -1,12 +1,284 @@
|
|||||||
#include <Preferences.h>
|
|
||||||
#include "main.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
Config::Config() {
|
// Logging
|
||||||
|
static const char* TAG = "CFG";
|
||||||
|
|
||||||
|
Config::Config(Preferences& prefs)
|
||||||
|
: prefs(prefs) {
|
||||||
|
|
||||||
|
// init defs mapping
|
||||||
|
for (size_t i = 0; i < configdefsCount; ++i) {
|
||||||
|
defs[configdefs[i].key] = &configdefs[i];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Config::loadConfig() {
|
void Config::load() {
|
||||||
prefs->begin(PREF_NAME);
|
ESP_LOGI(TAG, "Loading configuration");
|
||||||
prefs->end();
|
prefs.begin(PREF_NAME, true);
|
||||||
|
for (const auto& def : configdefs) {
|
||||||
|
if (prefs.isKey(def.key)) {
|
||||||
|
ESP_LOGI(TAG, "Config option '%s' loaded from NVS", def.key);
|
||||||
|
switch (def.type) {
|
||||||
|
case ConfigType::BYTE:
|
||||||
|
values[def.key] = (uint8_t)prefs.getUChar(def.key, std::get<uint8_t>(def.defval));
|
||||||
|
break;
|
||||||
|
case ConfigType::SHORT:
|
||||||
|
values[def.key] = (int16_t)prefs.getShort(def.key, std::get<int16_t>(def.defval));
|
||||||
|
break;
|
||||||
|
case ConfigType::INT:
|
||||||
|
values[def.key] = prefs.getInt(def.key, std::get<int32_t>(def.defval));
|
||||||
|
break;
|
||||||
|
case ConfigType::BOOL:
|
||||||
|
values[def.key] = prefs.getBool(def.key, std::get<bool>(def.defval));
|
||||||
|
break;
|
||||||
|
case ConfigType::FLOAT:
|
||||||
|
values[def.key] = prefs.getFloat(def.key, std::get<float>(def.defval));
|
||||||
|
break;
|
||||||
|
case ConfigType::CHAR:
|
||||||
|
values[def.key] = (char)prefs.getChar(def.key, std::get<char>(def.defval));
|
||||||
|
break;
|
||||||
|
case ConfigType::STRING:
|
||||||
|
values[def.key] = prefs.getString(def.key, std::get<String>(def.defval));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Using default for '%s'", def.key);
|
||||||
|
switch (def.type) {
|
||||||
|
case ConfigType::BYTE:
|
||||||
|
values[def.key] = std::get<uint8_t>(def.defval);
|
||||||
|
break;
|
||||||
|
case ConfigType::SHORT:
|
||||||
|
values[def.key] = std::get<int16_t>(def.defval);
|
||||||
|
break;
|
||||||
|
case ConfigType::INT:
|
||||||
|
values[def.key] = std::get<int32_t>(def.defval);
|
||||||
|
break;
|
||||||
|
case ConfigType::BOOL:
|
||||||
|
values[def.key] = std::get<bool>(def.defval);
|
||||||
|
break;
|
||||||
|
case ConfigType::FLOAT:
|
||||||
|
values[def.key] = std::get<float>(def.defval);
|
||||||
|
break;
|
||||||
|
case ConfigType::CHAR:
|
||||||
|
values[def.key] = std::get<char>(def.defval);
|
||||||
|
break;
|
||||||
|
case ConfigType::STRING:
|
||||||
|
values[def.key] = std::get<String>(def.defval);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefs.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::save(JsonObject json) {
|
||||||
|
|
||||||
|
// TODO Not fail if one single value is wrong?
|
||||||
|
|
||||||
|
prefs.begin(PREF_NAME, false);
|
||||||
|
|
||||||
|
int errors = 0;
|
||||||
|
for (JsonPair kv : json) {
|
||||||
|
const char* key = kv.key().c_str();
|
||||||
|
JsonVariant v = kv.value();
|
||||||
|
|
||||||
|
auto it = values.find(key);
|
||||||
|
if (it == values.end()) {
|
||||||
|
ESP_LOGE(TAG, "Unexpected missing key: %s", key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto itdef = defs.find(key);
|
||||||
|
if (itdef == defs.end()) {
|
||||||
|
ESP_LOGE(TAG, "Unexpected missing defs key: %s", key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const ConfigDef* def = itdef->second;
|
||||||
|
|
||||||
|
switch (itdef->second->type) {
|
||||||
|
case ConfigType::BYTE: {
|
||||||
|
if (!v.is<uint8_t>()) {
|
||||||
|
errors++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint8_t newval = v.as<uint8_t>();
|
||||||
|
uint8_t *curval = std::get_if<uint8_t>(&values[key]);
|
||||||
|
if (newval != *curval) {
|
||||||
|
values[key] = newval;
|
||||||
|
//prefs.putUChar(key, newval);
|
||||||
|
ESP_LOGI(TAG, "changing %s, replacing %d with %d", key, *curval, newval);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* case ConfigType::SHORT:
|
||||||
|
if (!v.is<int16_t>()) return false;
|
||||||
|
values[key] = v.as<int16_t>();
|
||||||
|
prefs.putShort(key, v.as<int16_t>());
|
||||||
|
break;
|
||||||
|
case ConfigType::INT:
|
||||||
|
if (!v.is<int32_t>()) return false;
|
||||||
|
values[key] = v.as<int32_t>();
|
||||||
|
prefs.putInt(key, v.as<int32_t>());
|
||||||
|
break;
|
||||||
|
case ConfigType::BOOL:
|
||||||
|
if (!v.is<bool>()) return false;
|
||||||
|
values[key] = v.as<bool>();
|
||||||
|
prefs.putBool(key, v.as<bool>());
|
||||||
|
break;
|
||||||
|
case ConfigType::FLOAT:
|
||||||
|
if (!v.is<float>()) return false;
|
||||||
|
values[key] = v.as<float>();
|
||||||
|
prefs.putFloat(key, v.as<float>());
|
||||||
|
break;
|
||||||
|
case ConfigType::CHAR:
|
||||||
|
if (!v.is<const char*>()) return false;
|
||||||
|
values[key] = v.as<const char*>()[0];
|
||||||
|
prefs.putChar(key, v.as<const char*>()[0]);
|
||||||
|
break;
|
||||||
|
case ConfigType::STRING:
|
||||||
|
if (!v.is<const char*>()) return false;
|
||||||
|
values[key] = String(v.as<const char*>());
|
||||||
|
prefs.putString(key, v.as<const char*>());
|
||||||
|
break; */
|
||||||
|
default:
|
||||||
|
ESP_LOGE("CFG", "Unsupported type for key %s", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prefs.end();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Config::dump() {
|
||||||
|
// only for debugging purposes,
|
||||||
|
ESP_LOGI(TAG, "========== Config options ==========");
|
||||||
|
for (const auto& def : configdefs) {
|
||||||
|
auto it = values.find(def.key);
|
||||||
|
if (it == values.end()) {
|
||||||
|
ESP_LOGW(TAG, "%s = <missing>", def.key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const ConfigValue& value = it->second;
|
||||||
|
switch (def.type) {
|
||||||
|
case ConfigType::BYTE:
|
||||||
|
if (auto v = std::get_if<uint8_t>(&value))
|
||||||
|
ESP_LOGI(TAG, "%s = %u", def.key, *v);
|
||||||
|
break;
|
||||||
|
case ConfigType::SHORT:
|
||||||
|
if (auto v = std::get_if<int16_t>(&value))
|
||||||
|
ESP_LOGI(TAG, "%s = %d", def.key, *v);
|
||||||
|
break;
|
||||||
|
case ConfigType::INT:
|
||||||
|
if (auto v = std::get_if<int32_t>(&value))
|
||||||
|
ESP_LOGI(TAG, "%s = %d", def.key, *v);
|
||||||
|
break;
|
||||||
|
case ConfigType::BOOL:
|
||||||
|
if (auto v = std::get_if<bool>(&value))
|
||||||
|
ESP_LOGI(TAG, "%s = %s", def.key, *v ? "true" : "false");
|
||||||
|
break;
|
||||||
|
case ConfigType::FLOAT:
|
||||||
|
if (auto v = std::get_if<float>(&value))
|
||||||
|
ESP_LOGI(TAG, "%s = %.3f", def.key, *v);
|
||||||
|
break;
|
||||||
|
case ConfigType::CHAR:
|
||||||
|
if (auto v = std::get_if<char>(&value))
|
||||||
|
ESP_LOGI(TAG, "%s = '%c'", def.key, *v);
|
||||||
|
break;
|
||||||
|
case ConfigType::STRING:
|
||||||
|
if (auto v = std::get_if<String>(&value))
|
||||||
|
ESP_LOGI(TAG, "%s = \"%s\"", def.key, v->c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "====================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T Config::get(const char* key) const {
|
||||||
|
return std::get<T>(values.at(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Config::getByte(const char* key) const {
|
||||||
|
auto it = values.find(key);
|
||||||
|
if (it == values.end()) {
|
||||||
|
ESP_LOGE(TAG, "Missing config key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (auto v = std::get_if<uint8_t>(&it->second))
|
||||||
|
return *v;
|
||||||
|
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t Config::getShort(const char* key) const {
|
||||||
|
auto it = values.find(key);
|
||||||
|
if (it == values.end()) {
|
||||||
|
ESP_LOGE(TAG, "Missing config key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (auto v = std::get_if<int16_t>(&it->second))
|
||||||
|
return *v;
|
||||||
|
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Config::getInt(const char* key) const {
|
||||||
|
auto it = values.find(key);
|
||||||
|
if (it == values.end()) {
|
||||||
|
ESP_LOGE(TAG, "Missing config key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (auto v = std::get_if<int32_t>(&it->second))
|
||||||
|
return *v;
|
||||||
|
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::getBool(const char* key) const {
|
||||||
|
auto it = values.find(key);
|
||||||
|
if (it == values.end())
|
||||||
|
ESP_LOGE(TAG, "Missing config key: %s", key);
|
||||||
|
abort();
|
||||||
|
if (auto v = std::get_if<bool>(&it->second))
|
||||||
|
return *v;
|
||||||
|
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
float Config::getFloat(const char* key) const {
|
||||||
|
auto it = values.find(key);
|
||||||
|
if (it == values.end()) {
|
||||||
|
ESP_LOGE(TAG, "Missing config key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (auto v = std::get_if<float>(&it->second))
|
||||||
|
return *v;
|
||||||
|
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
char Config::getChar(const char* key) const {
|
||||||
|
auto it = values.find(key);
|
||||||
|
if (it == values.end()) {
|
||||||
|
ESP_LOGE(TAG, "Missing config key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (auto v = std::get_if<char>(&it->second))
|
||||||
|
return *v;
|
||||||
|
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
const String& Config::getString(const char* key) const {
|
||||||
|
auto it = values.find(key);
|
||||||
|
if (it == values.end()) {
|
||||||
|
ESP_LOGE(TAG, "Missing config key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (auto v = std::get_if<String>(&it->second))
|
||||||
|
return *v;
|
||||||
|
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|||||||
236
src/main.cpp
236
src/main.cpp
@@ -1,11 +1,8 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <Preferences.h>
|
#include "config.h"
|
||||||
|
#include "webserver.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
|
||||||
#include <ESPAsyncWebServer.h>
|
|
||||||
#include <Update.h>
|
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <SHT31.h> // temp. sensor
|
#include <SHT31.h> // temp. sensor
|
||||||
#include <NMEA2000.h>
|
#include <NMEA2000.h>
|
||||||
@@ -65,50 +62,17 @@ String get_sha256(String payload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
static const char* TAG = "main.cpp";
|
static const char* TAG = "MAIN";
|
||||||
|
|
||||||
Preferences preferences; // persistent storage for configuration
|
Preferences preferences; // persistent storage for configuration
|
||||||
|
Config config(preferences); // configuration object
|
||||||
class EmbeddedFile;
|
|
||||||
static std::map<String, EmbeddedFile*> embeddedFiles;
|
|
||||||
class EmbeddedFile {
|
|
||||||
public:
|
|
||||||
const uint8_t *start;
|
|
||||||
int len;
|
|
||||||
String contentType;
|
|
||||||
EmbeddedFile(String name, String contentType, const uint8_t *start, int len) {
|
|
||||||
this->start = start;
|
|
||||||
this->len = len;
|
|
||||||
this->contentType = contentType;
|
|
||||||
embeddedFiles[name] = this;
|
|
||||||
}
|
|
||||||
} ;
|
|
||||||
|
|
||||||
#define EMBED_GZ_FILE(fileName, binName, contentType) \
|
|
||||||
extern const uint8_t binName##_File[] asm("_binary_" #binName "_start"); \
|
|
||||||
extern const uint8_t binName##_FileLen[] asm("_binary_" #binName "_size"); \
|
|
||||||
const EmbeddedFile binName##_Config(fileName,contentType,(const uint8_t*)binName##_File,(int)binName##_FileLen);
|
|
||||||
#include "embeddedfiles.h"
|
|
||||||
|
|
||||||
void send_embedded_file(String name, AsyncWebServerRequest *request)
|
|
||||||
{
|
|
||||||
std::map<String, EmbeddedFile*>::iterator it = embeddedFiles.find(name);
|
|
||||||
if (it != embeddedFiles.end()) {
|
|
||||||
EmbeddedFile* found = it->second;
|
|
||||||
AsyncWebServerResponse *response = request->beginResponse(200, found->contentType, found->start, found->len);
|
|
||||||
response->addHeader(F("Content-Encoding"), F("gzip"));
|
|
||||||
request->send(response);
|
|
||||||
} else {
|
|
||||||
request->send(404, "text/plain", "Not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t chipid = ESP.getEfuseMac();
|
uint64_t chipid = ESP.getEfuseMac();
|
||||||
|
|
||||||
const char* wifi_ssid = "OBPKP61";
|
const char* wifi_ssid = "OBPKP61";
|
||||||
const char* wifi_pass = "keypad61";
|
const char* wifi_pass = "keypad61";
|
||||||
bool apEnabled = false;
|
bool apEnabled = false;
|
||||||
AsyncWebServer server(80);
|
// AsyncWebServer server(80);
|
||||||
|
|
||||||
unsigned long firstStart = 0;
|
unsigned long firstStart = 0;
|
||||||
unsigned long lastSensor = 0;
|
unsigned long lastSensor = 0;
|
||||||
@@ -316,24 +280,9 @@ void cpuFreqTimerCallback(TimerHandle_t xTimer) {
|
|||||||
void setup() {
|
void setup() {
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
// while (!Serial) delay(10); verhindert Booten ohne USB-Verbindung
|
while (!Serial) delay(10); // verhindert Booten ohne USB-Verbindung
|
||||||
delay(500);
|
delay(500);
|
||||||
|
|
||||||
preferences.begin("nvs", false);
|
|
||||||
keycode[0] = preferences.getInt("key1", 1);
|
|
||||||
keycode[1] = preferences.getInt("key2", 2);
|
|
||||||
keycode[2] = preferences.getInt("key3", 3);
|
|
||||||
keycode[3] = preferences.getInt("key4", 4);
|
|
||||||
keycode[4] = preferences.getInt("key5", 5);
|
|
||||||
keycode[5] = preferences.getInt("key6", 6);
|
|
||||||
longcode[0] = preferences.getInt("key1long", 11);
|
|
||||||
longcode[1] = preferences.getInt("key2long", 12);
|
|
||||||
longcode[2] = preferences.getInt("key3long", 13);
|
|
||||||
longcode[3] = preferences.getInt("key4long", 14);
|
|
||||||
longcode[4] = preferences.getInt("key5long", 15);
|
|
||||||
longcode[5] = preferences.getInt("key6long", 16);
|
|
||||||
preferences.end();
|
|
||||||
|
|
||||||
// Configure I/O pins
|
// Configure I/O pins
|
||||||
|
|
||||||
// internal user led (red)
|
// internal user led (red)
|
||||||
@@ -381,6 +330,22 @@ void setup() {
|
|||||||
|
|
||||||
ESP_LOGI(TAG, "Starting ...");
|
ESP_LOGI(TAG, "Starting ...");
|
||||||
|
|
||||||
|
config.load();
|
||||||
|
config.dump();
|
||||||
|
|
||||||
|
keycode[0] = config.getByte("key1");
|
||||||
|
keycode[1] = config.getByte("key2");
|
||||||
|
keycode[2] = config.getByte("key3");
|
||||||
|
keycode[3] = config.getByte("key4");
|
||||||
|
keycode[4] = config.getByte("key5");
|
||||||
|
keycode[5] = config.getByte("key6");
|
||||||
|
longcode[0] = config.getByte("key1long");
|
||||||
|
longcode[1] = config.getByte("key2long");
|
||||||
|
longcode[2] = config.getByte("key3long");
|
||||||
|
longcode[3] = config.getByte("key4long");
|
||||||
|
longcode[4] = config.getByte("key5long");
|
||||||
|
longcode[5] = config.getByte("key6long");
|
||||||
|
|
||||||
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
||||||
if (cause == ESP_SLEEP_WAKEUP_EXT0) {
|
if (cause == ESP_SLEEP_WAKEUP_EXT0) {
|
||||||
ESP_LOGI(TAG, " Wake up by key");
|
ESP_LOGI(TAG, " Wake up by key");
|
||||||
@@ -391,15 +356,21 @@ void setup() {
|
|||||||
// N2K basics
|
// N2K basics
|
||||||
nodeid = N2K_DEFAULT_NODEID;
|
nodeid = N2K_DEFAULT_NODEID;
|
||||||
ESP_LOGI(TAG, "N2K default node is %d", nodeid);
|
ESP_LOGI(TAG, "N2K default node is %d", nodeid);
|
||||||
preferences.begin("nvs", false);
|
preferences.begin(PREF_NAME, false);
|
||||||
nodeid = preferences.getInt("LastNodeId", N2K_DEFAULT_NODEID);
|
nodeid = preferences.getInt("LastNodeId", N2K_DEFAULT_NODEID);
|
||||||
cpuspeed = preferences.getInt("cpuSpeed", 160);
|
|
||||||
int apstoptime = preferences.getInt("stopApTime", 0);
|
|
||||||
String apip = preferences.getString("apIp", "192.168.15.1");
|
|
||||||
String apmask = preferences.getString("apMask", "255.255.255.0");
|
|
||||||
preferences.end();
|
preferences.end();
|
||||||
ESP_LOGI(TAG, "N2K node id set to %d from preferences", nodeid);
|
ESP_LOGI(TAG, "N2K node id set to %d from preferences", nodeid);
|
||||||
|
|
||||||
|
//cpuspeed = preferences.getInt("cpuSpeed", 160);
|
||||||
|
cpuspeed = config.getShort("cpuSpeed");
|
||||||
|
//int apstoptime = preferences.getInt("stopApTime", 0);
|
||||||
|
int16_t apstoptime = config.getShort("stopApTime");
|
||||||
|
//String apip = preferences.getString("apIp", "192.168.15.1");
|
||||||
|
//String apmask = preferences.getString("apMask", "255.255.255.0");
|
||||||
|
String apip = config.getString("apIp");
|
||||||
|
String apmask = config.getString("apMask");
|
||||||
|
//preferences.end();
|
||||||
|
|
||||||
// Setup webserver
|
// Setup webserver
|
||||||
WiFi.persistent(false);
|
WiFi.persistent(false);
|
||||||
WiFi.mode(WIFI_MODE_AP);
|
WiFi.mode(WIFI_MODE_AP);
|
||||||
@@ -423,32 +394,9 @@ void setup() {
|
|||||||
WiFi.softAPConfig(ap_addr, ap_gateway, ap_subnet);
|
WiFi.softAPConfig(ap_addr, ap_gateway, ap_subnet);
|
||||||
apEnabled = true;
|
apEnabled = true;
|
||||||
|
|
||||||
// Route for root / web page
|
// Initialize WebGUI
|
||||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
webserver_init();
|
||||||
send_embedded_file("index.html", request);
|
|
||||||
});
|
|
||||||
// Route for all other defined pages
|
|
||||||
for (auto it = embeddedFiles.begin(); it != embeddedFiles.end(); it++) {
|
|
||||||
String uri = String("/") + it->first;
|
|
||||||
server.on(uri.c_str(), HTTP_GET, [it](AsyncWebServerRequest *request) {
|
|
||||||
send_embedded_file(it->first, request);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// API fast hack
|
|
||||||
server.on("/api/capabilities", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
StaticJsonDocument<100> doc;
|
|
||||||
doc["apPwChange"] = "true";
|
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
request->send(200, "application/json", out);
|
|
||||||
});
|
|
||||||
server.on("/api/checkpass", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
StaticJsonDocument<100> doc;
|
|
||||||
doc["status"] = "FAILED";
|
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
request->send(200, "application/json", out);
|
|
||||||
});
|
|
||||||
server.on("/api/devicelist", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/api/devicelist", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
// NMEA2000 device list
|
// NMEA2000 device list
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
@@ -474,116 +422,8 @@ void setup() {
|
|||||||
response->print("]");
|
response->print("]");
|
||||||
request->send(response);
|
request->send(response);
|
||||||
});
|
});
|
||||||
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
StaticJsonDocument<512> doc;
|
|
||||||
doc["systemName"] = "Keypad1";
|
|
||||||
doc["logLevel"] = 0;
|
|
||||||
doc["version"] = VERSION;
|
|
||||||
doc["fwtype"] = "unknown";
|
|
||||||
doc["salt"] = "secret";
|
|
||||||
doc["AdminPassword"] = "********";
|
|
||||||
doc["useAdminPass"] = false;
|
|
||||||
doc["apEnable"] = true;
|
|
||||||
doc["apIp"] = "192.168.15.1";
|
|
||||||
doc["apMask"] = "255.255.255.0";
|
|
||||||
doc["apPassword"] = "********";
|
|
||||||
doc["stopApTime"] = 0;
|
|
||||||
doc["cpuSpeed"] = 160;
|
|
||||||
doc["tempFormat"] = "C";
|
|
||||||
doc["ledBrightness"] = led_brightness;
|
|
||||||
doc["ledRgbBrightness"] = rgb_brightness;
|
|
||||||
doc["tempFormat"] = "C";
|
|
||||||
doc["switchBank"] = 0;
|
|
||||||
doc["key1"] = keycode[BUTTON_1];
|
|
||||||
doc["key2"] = keycode[BUTTON_2];
|
|
||||||
doc["key3"] = keycode[BUTTON_3];
|
|
||||||
doc["key4"] = keycode[BUTTON_4];
|
|
||||||
doc["key5"] = keycode[BUTTON_5];
|
|
||||||
doc["key6"] = keycode[BUTTON_6];
|
|
||||||
doc["key1long"] = longcode[BUTTON_1];
|
|
||||||
doc["key2long"] = longcode[BUTTON_2];
|
|
||||||
doc["key3long"] = longcode[BUTTON_3];
|
|
||||||
doc["key4long"] = longcode[BUTTON_4];
|
|
||||||
doc["key5long"] = longcode[BUTTON_5];
|
|
||||||
doc["key6long"] = longcode[BUTTON_6];
|
|
||||||
doc["envInterval"] = 5;
|
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
request->send(200, "application/json", out);
|
|
||||||
});
|
|
||||||
server.on("/api/resetconfig", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
StaticJsonDocument<100> doc;
|
|
||||||
doc["status"] = "FAILED";
|
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
request->send(200, "application/json", out);
|
|
||||||
});
|
|
||||||
server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
StaticJsonDocument<200> doc;
|
|
||||||
|
|
||||||
doc["version"] = VERSION;
|
|
||||||
|
|
||||||
int cpu_freq = esp_clk_cpu_freq() / 1000000;
|
|
||||||
doc["cpuspeed"] = String(cpu_freq) + "MHz";
|
|
||||||
|
|
||||||
char ssid[13];
|
|
||||||
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
|
|
||||||
doc["chipid"] = String(ssid);
|
|
||||||
|
|
||||||
doc["uptime"] = uptime_with_unit();
|
|
||||||
doc["heap"]=(long)xPortGetFreeHeapSize();
|
|
||||||
doc["temp"] = String(temp, 1);
|
|
||||||
doc["hum"] = String(hum, 1);
|
|
||||||
doc["status"] = "OK";
|
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
request->send(200, "application/json", out);
|
|
||||||
});
|
|
||||||
server.on("/api/fwinfo", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
StaticJsonDocument<200> doc;
|
|
||||||
doc["version"] = VERSION;
|
|
||||||
doc["build_date"] = BUILD_DATE;
|
|
||||||
doc["build_time"] = BUILD_TIME;
|
|
||||||
});
|
|
||||||
server.on("/api/setconfig", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
StaticJsonDocument<100> doc;
|
|
||||||
doc["status"] = "FAILED";
|
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
request->send(200, "application/json", out);
|
|
||||||
});
|
|
||||||
server.on("/api/update", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
// the request handler is triggered after the upload has finished...
|
|
||||||
// create the response, add header, and send response
|
|
||||||
|
|
||||||
StaticJsonDocument<100> doc;
|
|
||||||
doc["status"] = "FAILED";
|
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
request->send(200, "application/json", out);
|
|
||||||
}, [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
|
|
||||||
// this is the new image upload part
|
|
||||||
Serial.print("Retrieving firmware image named: ");
|
|
||||||
Serial.println(filename);
|
|
||||||
|
|
||||||
if (index == 0) {
|
|
||||||
if (! Update.begin(UPDATE_SIZE_UNKNOWN)) {
|
|
||||||
Update.printError(Serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Update.write(data, len) != len) {
|
|
||||||
Update.printError(Serial);
|
|
||||||
}
|
|
||||||
if (final) {
|
|
||||||
if (!Update.end(true)) {
|
|
||||||
Update.printError(Serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO POST vom Client entgegennehmen
|
|
||||||
|
|
||||||
|
// Start HTTP Webserver
|
||||||
server.begin();
|
server.begin();
|
||||||
|
|
||||||
// NMEA2000 configuration
|
// NMEA2000 configuration
|
||||||
|
|||||||
190
src/webserver.cpp
Normal file
190
src/webserver.cpp
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#include "main.h"
|
||||||
|
#include "webserver.h"
|
||||||
|
#include <map>
|
||||||
|
#include <AsyncTCP.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <esp32/clk.h> // for cpu frequency
|
||||||
|
#include <Update.h>
|
||||||
|
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
class EmbeddedFile;
|
||||||
|
static std::map<String, EmbeddedFile*> embeddedFiles;
|
||||||
|
class EmbeddedFile {
|
||||||
|
public:
|
||||||
|
const uint8_t *start;
|
||||||
|
int len;
|
||||||
|
String contentType;
|
||||||
|
EmbeddedFile(String name, String contentType, const uint8_t *start, int len) {
|
||||||
|
this->start = start;
|
||||||
|
this->len = len;
|
||||||
|
this->contentType = contentType;
|
||||||
|
embeddedFiles[name] = this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EMBED_GZ_FILE(fileName, binName, contentType) \
|
||||||
|
extern const uint8_t binName##_File[] asm("_binary_" #binName "_start"); \
|
||||||
|
extern const uint8_t binName##_FileLen[] asm("_binary_" #binName "_size"); \
|
||||||
|
const EmbeddedFile binName##_Config(fileName,contentType,(const uint8_t*)binName##_File,(int)binName##_FileLen);
|
||||||
|
#include "embeddedfiles.h"
|
||||||
|
|
||||||
|
void send_embedded_file(String name, AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
std::map<String, EmbeddedFile*>::iterator it = embeddedFiles.find(name);
|
||||||
|
if (it != embeddedFiles.end()) {
|
||||||
|
EmbeddedFile* found = it->second;
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse(200, found->contentType, found->start, found->len);
|
||||||
|
response->addHeader(F("Content-Encoding"), F("gzip"));
|
||||||
|
request->send(response);
|
||||||
|
} else {
|
||||||
|
request->send(404, "text/plain", "Not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void webserver_init() {
|
||||||
|
|
||||||
|
// Route for root / web page
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
send_embedded_file("index.html", request);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route for all other defined pages
|
||||||
|
for (auto it = embeddedFiles.begin(); it != embeddedFiles.end(); it++) {
|
||||||
|
String uri = String("/") + it->first;
|
||||||
|
server.on(uri.c_str(), HTTP_GET, [it](AsyncWebServerRequest *request) {
|
||||||
|
send_embedded_file(it->first, request);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// API fast hack
|
||||||
|
server.on("/api/capabilities", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["apPwChange"] = "true";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/api/checkpass", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["status"] = "FAILED";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<512> doc;
|
||||||
|
doc["systemName"] = "Keypad1";
|
||||||
|
doc["logLevel"] = 0;
|
||||||
|
doc["version"] = VERSION;
|
||||||
|
doc["fwtype"] = "unknown";
|
||||||
|
doc["salt"] = "secret";
|
||||||
|
doc["AdminPassword"] = "********";
|
||||||
|
doc["useAdminPass"] = false;
|
||||||
|
doc["apEnable"] = true;
|
||||||
|
doc["apIp"] = "192.168.15.1";
|
||||||
|
doc["apMask"] = "255.255.255.0";
|
||||||
|
doc["apPassword"] = "********";
|
||||||
|
doc["stopApTime"] = 0;
|
||||||
|
doc["cpuSpeed"] = 160;
|
||||||
|
doc["tempFormat"] = "C";
|
||||||
|
doc["ledBrightness"] = led_brightness;
|
||||||
|
doc["ledRgbBrightness"] = rgb_brightness;
|
||||||
|
doc["tempFormat"] = "C";
|
||||||
|
doc["switchBank"] = 0;
|
||||||
|
doc["key1"] = keycode[BUTTON_1];
|
||||||
|
doc["key2"] = keycode[BUTTON_2];
|
||||||
|
doc["key3"] = keycode[BUTTON_3];
|
||||||
|
doc["key4"] = keycode[BUTTON_4];
|
||||||
|
doc["key5"] = keycode[BUTTON_5];
|
||||||
|
doc["key6"] = keycode[BUTTON_6];
|
||||||
|
doc["key1long"] = longcode[BUTTON_1];
|
||||||
|
doc["key2long"] = longcode[BUTTON_2];
|
||||||
|
doc["key3long"] = longcode[BUTTON_3];
|
||||||
|
doc["key4long"] = longcode[BUTTON_4];
|
||||||
|
doc["key5long"] = longcode[BUTTON_5];
|
||||||
|
doc["key6long"] = longcode[BUTTON_6];
|
||||||
|
doc["envInterval"] = 5;
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/api/resetconfig", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["status"] = "FAILED";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<200> doc;
|
||||||
|
|
||||||
|
doc["version"] = VERSION;
|
||||||
|
|
||||||
|
int cpu_freq = esp_clk_cpu_freq() / 1000000;
|
||||||
|
doc["cpuspeed"] = String(cpu_freq) + "MHz";
|
||||||
|
|
||||||
|
char ssid[13];
|
||||||
|
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
|
||||||
|
doc["chipid"] = String(ssid);
|
||||||
|
|
||||||
|
doc["uptime"] = uptime_with_unit();
|
||||||
|
doc["heap"]=(long)xPortGetFreeHeapSize();
|
||||||
|
doc["temp"] = String(temp, 1);
|
||||||
|
doc["hum"] = String(hum, 1);
|
||||||
|
doc["status"] = "OK";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/api/fwinfo", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<200> doc;
|
||||||
|
doc["version"] = VERSION;
|
||||||
|
doc["build_date"] = BUILD_DATE;
|
||||||
|
doc["build_time"] = BUILD_TIME;
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/api/setconfig", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["status"] = "FAILED";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/api/update", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
// the request handler is triggered after the upload has finished...
|
||||||
|
// create the response, add header, and send response
|
||||||
|
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["status"] = "FAILED";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
}, [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||||
|
// this is the new image upload part
|
||||||
|
Serial.print("Retrieving firmware image named: ");
|
||||||
|
Serial.println(filename);
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
if (! Update.begin(UPDATE_SIZE_UNKNOWN)) {
|
||||||
|
Update.printError(Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Update.write(data, len) != len) {
|
||||||
|
Update.printError(Serial);
|
||||||
|
}
|
||||||
|
if (final) {
|
||||||
|
if (!Update.end(true)) {
|
||||||
|
Update.printError(Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user