added espasyncota lib

This commit is contained in:
2021-08-06 15:50:44 +02:00
parent 42bac7c293
commit 76ef403bbf
19 changed files with 311 additions and 124 deletions

3
.gitmodules vendored
View File

@@ -40,3 +40,6 @@
[submodule "components/esp-nimble-cpp"]
path = components/esp-nimble-cpp
url = git@github.com:0xFEEDC0DE64/esp-nimble-cpp.git
[submodule "components/espasyncota"]
path = components/espasyncota
url = git@github.com:0xFEEDC0DE64/espasyncota.git

View File

@@ -12,6 +12,7 @@ set(headers
myconfig.h
mymdns.h
mymqtt.h
myota.h
mywifi.h
nvswrappers.h
webserver.h
@@ -29,13 +30,14 @@ set(sources
myconfig.cpp
mymdns.cpp
mymqtt.cpp
myota.cpp
mywifi.cpp
webserver.cpp
)
set(dependencies
freertos nvs_flash esp_http_server esp_https_ota mdns app_update esp_system mqtt
arduino-esp32 cpputils date esp-nimble-cpp espchrono espcpputils espwifistack expected fmt
arduino-esp32 cpputils date esp-nimble-cpp espasyncota espchrono espcpputils espwifistack expected fmt
Adafruit_BMP085_Unified Adafruit_TSL2561 DHT-sensor-library
)

View File

@@ -39,7 +39,8 @@ void init_bmp()
bmpInitialized = bmp->begin();
ESP_LOGI(TAG, "finished with %s", bmpInitialized ? "true" : "false");
if (bmpInitialized) {
if (bmpInitialized)
{
sensor_t sensor = bmp->getSensor();
ESP_LOGI(TAG, "------------------------------------");
ESP_LOGI(TAG, "Sensor: %s", sensor.name);
@@ -58,14 +59,17 @@ void update_bmp()
if (!config::enable_i2c.value() || !config::enable_bmp.value())
return;
if (bmpInitialized) {
if (bmpInitialized)
{
if (espchrono::ago(last_bmp085_readout) < 5s)
return;
last_bmp085_readout = espchrono::millis_clock::now();
if (std::optional<Adafruit_BMP085_Unified::TemperatureAndPressure> values = bmp->getTemperatureAndPressure()) {
if (values->temperature && values->pressure) {
if (std::optional<Adafruit_BMP085_Unified::TemperatureAndPressure> values = bmp->getTemperatureAndPressure())
{
if (values->temperature && values->pressure)
{
BmpValue bmpValue {
.timestamp = espchrono::millis_clock::now(),
.pressure = values->pressure,
@@ -79,35 +83,46 @@ void update_bmp()
bmpValue.altitude = bmp->pressureToAltitude(seaLevelPressure, bmpValue.pressure);
ESP_LOGI(TAG, "read bmp Altitude: %.1f m", bmpValue.altitude);
if (mqttConnected) {
if (mqttConnected)
{
if (!lastBmpValue)
mqttVerbosePub(config::topic_bmp085_availability.value(), "online", 0, 1);
if (!lastBmpValue || espchrono::ago(last_bmp085_pressure_pub) >= config::valueUpdateInterval.value()) {
if (!lastBmpValue || espchrono::ago(last_bmp085_pressure_pub) >= config::valueUpdateInterval.value())
{
if (mqttVerbosePub(config::topic_bmp085_pressure.value(), fmt::format("{:.1f}", bmpValue.pressure), 0, 1) >= 0)
last_bmp085_pressure_pub = espchrono::millis_clock::now();
}
if (!lastBmpValue || espchrono::ago(last_bmp085_temperature_pub) >= config::valueUpdateInterval.value()) {
if (!lastBmpValue || espchrono::ago(last_bmp085_temperature_pub) >= config::valueUpdateInterval.value())
{
if (mqttVerbosePub(config::topic_bmp085_temperature.value(), fmt::format("{:.1f}", bmpValue.temperature), 0, 1) >= 0)
last_bmp085_temperature_pub = espchrono::millis_clock::now();
}
if (!lastBmpValue || espchrono::ago(last_bmp085_altitude_pub) >= config::valueUpdateInterval.value()) {
if (!lastBmpValue || espchrono::ago(last_bmp085_altitude_pub) >= config::valueUpdateInterval.value())
{
if (mqttVerbosePub(config::topic_bmp085_altitude.value(), fmt::format("{:.1f}", bmpValue.altitude), 0, 1) >= 0)
last_bmp085_altitude_pub = espchrono::millis_clock::now();
}
}
lastBmpValue = bmpValue;
} else {
}
else
{
ESP_LOGW(TAG, "bmp sensor error");
goto bmpOffline;
}
} else {
}
else
{
ESP_LOGW(TAG, "bmp failed");
goto bmpOffline;
}
} else {
}
else
{
bmpOffline:
if (lastBmpValue && espchrono::ago(lastBmpValue->timestamp) >= config::availableTimeoutTime.value()) {
if (lastBmpValue && espchrono::ago(lastBmpValue->timestamp) >= config::availableTimeoutTime.value())
{
ESP_LOGW(TAG, "bmp timeouted");
if (mqttConnected)
mqttVerbosePub(config::topic_bmp085_availability.value(), "offline", 0, 1);

View File

@@ -44,13 +44,15 @@ void update_dht()
if (!config::enable_dht.value())
return;
if (dhtInitialized) {
if (dhtInitialized)
{
if (espchrono::ago(last_dht11_readout) < 5s)
return;
last_dht11_readout = espchrono::millis_clock::now();
if (const auto data = dht->read()) {
if (const auto data = dht->read())
{
DhtValue dhtValue {
.timestamp = espchrono::millis_clock::now(),
.temperature = dht->readTemperature(*data),
@@ -60,27 +62,35 @@ void update_dht()
ESP_LOGI(TAG, "read dht temperature: %.1f C", dhtValue.temperature);
ESP_LOGI(TAG, "read dht humidity: %.1f %%", dhtValue.humidity);
if (mqttConnected) {
if (mqttConnected)
{
if (!lastDhtValue)
mqttVerbosePub(config::topic_dht11_availability.value(), "online", 0, 1);
if (!lastDhtValue || espchrono::ago(last_dht11_temperature_pub) >= config::valueUpdateInterval.value()) {
if (!lastDhtValue || espchrono::ago(last_dht11_temperature_pub) >= config::valueUpdateInterval.value())
{
if (mqttVerbosePub(config::topic_dht11_temperature.value(), fmt::format("{:.1f}", dhtValue.temperature), 0, 1) >= 0)
last_dht11_temperature_pub = espchrono::millis_clock::now();
}
if (!lastDhtValue || espchrono::ago(last_dht11_humidity_pub) >= config::valueUpdateInterval.value()) {
if (!lastDhtValue || espchrono::ago(last_dht11_humidity_pub) >= config::valueUpdateInterval.value())
{
if (mqttVerbosePub(config::topic_dht11_humidity.value(), fmt::format("{:.1f}", dhtValue.humidity), 0, 1) >= 0)
last_dht11_humidity_pub = espchrono::millis_clock::now();
}
}
lastDhtValue = dhtValue;
} else {
}
else
{
ESP_LOGW(TAG, "dht failed");
goto dhtOffline;
}
} else {
}
else
{
dhtOffline:
if (lastDhtValue && espchrono::ago(lastDhtValue->timestamp) >= config::availableTimeoutTime.value()) {
if (lastDhtValue && espchrono::ago(lastDhtValue->timestamp) >= config::availableTimeoutTime.value())
{
ESP_LOGW(TAG, "dht timeouted");
if (mqttConnected)
mqttVerbosePub(config::topic_dht11_availability.value(), "offline", 0, 1);

View File

@@ -41,9 +41,11 @@ void update_switch()
const auto newState = readSwitch();
if (newState == switchState.load())
switchDebounce = 0;
else {
else
{
switchDebounce++;
if (switchDebounce >= 10) {
if (switchDebounce >= 10)
{
switchDebounce = 0;
switchState = newState;
@@ -51,7 +53,8 @@ void update_switch()
if (mqttConnected)
mqttVerbosePub(config::topic_switch_status.value(), switchState ? "ON" : "OFF", 0, 1);
if (config::enable_lamp.value()) {
if (config::enable_lamp.value())
{
lampState = !lampState;
writeLamp(lampState);

View File

@@ -37,7 +37,8 @@ void init_tsl()
tslInitialized = tsl->begin(true);
ESP_LOGI(TAG, "finished with %s", tslInitialized ? "true" : "false");
if (tslInitialized) {
if (tslInitialized)
{
sensor_t sensor = tsl->getSensor();
ESP_LOGI(TAG, "------------------------------------");
ESP_LOGI(TAG, "Sensor: %s", sensor.name);
@@ -72,44 +73,56 @@ void update_tsl()
if (!config::enable_i2c.value() || !config::enable_tsl.value())
return;
if (tslInitialized) {
if (tslInitialized)
{
if (espchrono::ago(last_tsl2561_readout) < 5s)
return;
last_tsl2561_readout = espchrono::millis_clock::now();
if (std::optional<sensors_event_t> event = tsl->getEvent()) {
if (std::optional<sensors_event_t> event = tsl->getEvent())
{
/* Display the results (light is measured in lux) */
if (event->light) {
if (event->light)
{
TslValue tslValue {
.timestamp = espchrono::millis_clock::now(),
.lux = event->light
};
ESP_LOGI(TAG, "read tsl: %.1f lux", tslValue.lux);
if (mqttConnected) {
if (mqttConnected)
{
if (!lastTslValue)
mqttVerbosePub(config::topic_tsl2561_availability.value(), "online", 0, 1);
if (!lastTslValue || espchrono::ago(last_tsl2561_lux_pub) >= config::valueUpdateInterval.value()) {
if (!lastTslValue || espchrono::ago(last_tsl2561_lux_pub) >= config::valueUpdateInterval.value())
{
if (mqttVerbosePub(config::topic_tsl2561_lux.value(), fmt::format("{:.1f}", tslValue.lux), 0, 1) >= 0)
last_tsl2561_lux_pub = espchrono::millis_clock::now();
}
}
lastTslValue = tslValue;
} else {
}
else
{
/* If event.light = 0 lux the sensor is probably saturated
* and no reliable data could be generated! */
ESP_LOGW(TAG, "tsl sensor overload %f", event->light);
goto tslOffline;
}
} else {
}
else
{
ESP_LOGW(TAG, "tsl failed");
goto tslOffline;
}
} else {
}
else
{
tslOffline:
if (lastTslValue && espchrono::ago(lastTslValue->timestamp) >= config::availableTimeoutTime.value()) {
if (lastTslValue && espchrono::ago(lastTslValue->timestamp) >= config::availableTimeoutTime.value())
{
ESP_LOGW(TAG, "tsl timeouted");
if (mqttConnected)
mqttVerbosePub(config::topic_tsl2561_availability.value(), "offline", 0, 1);

View File

@@ -23,6 +23,7 @@
#include "webserver.h"
#include "mymdns.h"
#include "mymqtt.h"
#include "myota.h"
#include "feature_lamp.h"
#include "feature_switch.h"
#include "feature_dht.h"
@@ -99,6 +100,8 @@ extern "C" void app_main()
init_mqtt();
init_ota();
init_dht();
init_tsl();
@@ -130,6 +133,9 @@ extern "C" void app_main()
update_mqtt();
vPortYield();
update_ota();
vPortYield();
update_dht();
vPortYield();

View File

@@ -102,15 +102,18 @@ namespace {
template<typename T>
void loadParam(ConfigWrapper<T> &config)
{
if (const auto len = std::strlen(config.nvsKey()); len > 15) {
if (const auto len = std::strlen(config.nvsKey()); len > 15)
{
ESP_LOGE(TAG, "%s too long %zd (%zd)", config.nvsKey(), len, len-15);
assert(false);
}
if (const auto value = config.readFromFlash()) {
if (const auto value = config.readFromFlash())
{
if (*value)
config.setValue(**value);
} else
}
else
ESP_LOGE(TAG, "error loading config %s: %.*s", config.name(), value.error().size(), value.error().data());
}
} // namespace

View File

@@ -70,7 +70,8 @@ int mqttVerbosePub(std::string_view topic, std::string_view value, int qos, int
{
ESP_LOGD(TAG, "topic=\"%.*s\" value=\"%.*s\"", topic.size(), topic.data(), value.size(), value.data());
if (!mqttClient) {
if (!mqttClient)
{
ESP_LOGE(TAG, "mqttClient not constructed!");
return -1;
}
@@ -90,7 +91,8 @@ void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int3
const esp_mqtt_event_t *data = reinterpret_cast<const esp_mqtt_event_t *>(event_data);
switch (esp_mqtt_event_id_t(event_id)) {
switch (esp_mqtt_event_id_t(event_id))
{
case MQTT_EVENT_ERROR:
ESP_LOGE(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_ERROR");
@@ -110,20 +112,24 @@ void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int3
mqttConnected = true;
if (config::enable_lamp.value()) {
if (config::enable_lamp.value())
{
mqttVerbosePub(config::topic_lamp_availability.value(), "online", 0, 1);
mqttVerbosePub(config::topic_lamp_status.value(), lampState.load() ? "ON" : "OFF", 0, 1);
mqttClient.subscribe(config::topic_lamp_set.value(), 0);
}
if (config::enable_switch.value()) {
if (config::enable_switch.value())
{
mqttVerbosePub(config::topic_switch_availability.value(), "online", 0, 1);
mqttVerbosePub(config::topic_switch_status.value(), switchState.load() ? "ON" : "OFF", 0, 1);
}
if (config::enable_dht.value()) {
if (config::enable_dht.value())
{
mqttVerbosePub(config::topic_dht11_availability.value(), lastDhtValue ? "online" : "offline", 0, 1);
if (lastDhtValue) {
if (lastDhtValue)
{
if (mqttVerbosePub(config::topic_dht11_temperature.value(), fmt::format("{:.1f}", lastDhtValue->temperature), 0, 1) >= 0)
last_dht11_temperature_pub = espchrono::millis_clock::now();
if (mqttVerbosePub(config::topic_dht11_humidity.value(), fmt::format("{:.1f}", lastDhtValue->humidity), 0, 1) >= 0)
@@ -131,17 +137,21 @@ void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int3
}
}
if (config::enable_i2c.value() && config::enable_tsl.value()) {
if (config::enable_i2c.value() && config::enable_tsl.value())
{
mqttVerbosePub(config::topic_tsl2561_availability.value(), lastTslValue ? "online" : "offline", 0, 1);
if (lastTslValue) {
if (lastTslValue)
{
if (mqttVerbosePub(config::topic_tsl2561_lux.value(), fmt::format("{:.1f}", lastTslValue->lux), 0, 1) >= 0)
last_tsl2561_lux_pub = espchrono::millis_clock::now();
}
}
if (config::enable_i2c.value() && config::enable_bmp.value()) {
if (config::enable_i2c.value() && config::enable_bmp.value())
{
mqttVerbosePub(config::topic_bmp085_availability.value(), lastBmpValue ? "online" : "offline", 0, 1);
if (lastBmpValue) {
if (lastBmpValue)
{
if (mqttVerbosePub(config::topic_bmp085_pressure.value(), fmt::format("{:.1f}", lastBmpValue->pressure), 0, 1) >= 0)
last_bmp085_pressure_pub = espchrono::millis_clock::now();
if (mqttVerbosePub(config::topic_bmp085_temperature.value(), fmt::format("{:.1f}", lastBmpValue->temperature), 0, 1) >= 0)
@@ -178,16 +188,22 @@ void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int3
ESP_LOGI(TAG, "%s event_id=%s topic=%.*s data=%.*s", event_base, "MQTT_EVENT_DATA", topic.size(), topic.data(), value.size(), value.data());
if (topic == config::topic_lamp_set.value()) {
if (config::enable_lamp.value()) {
if (topic == config::topic_lamp_set.value())
{
if (config::enable_lamp.value())
{
bool newState = (lampState = (value == "ON"));
writeLamp(newState);
if (mqttConnected)
mqttVerbosePub(config::topic_lamp_status.value(), newState ? "ON" : "OFF", 0, 1);
} else {
}
else
{
ESP_LOGW(TAG, "received lamp set without lamp support enabled!");
}
} else {
}
else
{
ESP_LOGW(TAG, "received unknown data topic=%.*s data=%.*s", topic.size(), topic.data(), value.size(), value.data());
}

49
main/myota.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "myota.h"
// esp-idf includes
#include <esp_log.h>
// local includes
#include "delayedconstruction.h"
#include "espasyncota.h"
#include "espwifistack.h"
namespace deckenlampe {
namespace {
constexpr const char * const TAG = "OTA";
cpputils::DelayedConstruction<EspAsyncOta> _asyncOta;
} // namespace
EspAsyncOta &asyncOta{_asyncOta.getUnsafe()};
void init_ota()
{
ESP_LOGI(TAG, "called");
_asyncOta.construct();
if (const auto result = _asyncOta->startTask(); !result)
{
ESP_LOGE(TAG, "starting OTA task failed: %.*s", result.error().size(), result.error().data());
return;
}
}
void update_ota()
{
_asyncOta->update();
}
tl::expected<void, std::string> triggerOta(std::string_view url)
{
ESP_LOGI(TAG, "%.*s", url.size(), url.data());
if (const auto result = _asyncOta->trigger(url, {}, {}, {}); !result)
return tl::make_unexpected(std::move(result).error());
wifi_stack::delete_scan_result();
return {};
}
} // namespace deckenlampe

19
main/myota.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
// system includes
#include <string>
#include <string_view>
// 3rdparty lib includes
#include <tl/expected.hpp>
// forward declares
class EspAsyncOta;
namespace deckenlampe {
extern EspAsyncOta &asyncOta;
void init_ota();
void update_ota();
tl::expected<void, std::string> triggerOta(std::string_view url);
} // namespace deckenlampe

View File

@@ -25,40 +25,35 @@ wifi_stack::config makeWifiConfig()
return wifi_stack::config {
.wifiEnabled = true,
.hostname = config::hostname.value(),
.wifis = std::array<wifi_stack::wifi_entry, 10> {
wifi_stack::wifi_entry { .ssid = config::sta_ssid.value(), .key = config::sta_key.value() },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} }
},
.sta_ip = {
.staticIpEnabled = false,
// .staticIp = {},
// .staticGateway = {},
// .staticSubnet = {},
// .staticDns1 = {},
// .staticDns2 = {}
.sta = {
.wifis = std::array<wifi_stack::wifi_entry, 10> {
wifi_stack::wifi_entry { .ssid = config::sta_ssid.value(), .key = config::sta_key.value() },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
wifi_stack::wifi_entry { .ssid = {}, .key = {} }
},
.min_rssi = -90
},
.ap = {
{
.ssid = config::ap_ssid.value(),
.key = config::ap_key.value()
.ssid = config::ap_ssid.value(),
.key = config::ap_key.value(),
.static_ip = {
.ip = ap_ip,
.subnet = ap_subnet,
.gateway = ap_ip
},
.channel = 1,
.authmode = WIFI_AUTH_WPA2_PSK,
.ssid_hidden = false,
.max_connection = 4,
.beacon_interval = 100,
.ip = ap_ip,
.subnet = ap_subnet
},
.min_rssi = -90
.beacon_interval = 100
}
};
}
} // namespace

View File

@@ -25,6 +25,8 @@
#include "strutils.h"
#include "espchrono.h"
#include "numberparsing.h"
#include "myota.h"
#include "espasyncota.h"
namespace deckenlampe {
httpd_handle_t httpdHandle;
@@ -98,14 +100,16 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
{
std::string query;
if (const size_t queryLength = httpd_req_get_url_query_len(req)) {
if (const size_t queryLength = httpd_req_get_url_query_len(req))
{
query.resize(queryLength);
CALL_AND_EXIT_ON_ERROR(httpd_req_get_url_query_str, req, query.data(), query.size() + 1)
}
std::string body;
if (config::enable_lamp.value()) {
if (config::enable_lamp.value())
{
body += "<a href=\"/on\">on</a><br/>\n"
"<a href=\"/off\">off</a><br/>\n"
"<a href=\"/toggle\">toggle</a><br/>\n";
@@ -146,11 +150,14 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
esp_err_t webserver_dht_display(httpd_req_t *req, std::string &body)
{
if (config::enable_dht.value()) {
if (lastDhtValue) {
if (config::enable_dht.value())
{
if (lastDhtValue)
{
body += fmt::format("DHT11 Temperature: {:.1f} C<br/>\n", lastDhtValue->temperature);
body += fmt::format("DHT11 Humidity: {:.1f} %<br/>\n", lastDhtValue->humidity);
} else
}
else
body += "DHT11 not available at the moment<br/>\n";
}
@@ -159,10 +166,13 @@ esp_err_t webserver_dht_display(httpd_req_t *req, std::string &body)
esp_err_t webserver_tsl_display(httpd_req_t *req, std::string &body)
{
if (config::enable_i2c.value() && config::enable_tsl.value()) {
if (lastTslValue) {
if (config::enable_i2c.value() && config::enable_tsl.value())
{
if (lastTslValue)
{
body += fmt::format("TSL2561 Brightness: {:.1f} lux<br/>\n", lastTslValue->lux);
} else
}
else
body += "TSL2561 not available at the moment<br/>\n";
}
@@ -171,12 +181,15 @@ esp_err_t webserver_tsl_display(httpd_req_t *req, std::string &body)
esp_err_t webserver_bmp_display(httpd_req_t *req, std::string &body)
{
if (config::enable_i2c.value() && config::enable_bmp.value()) {
if (lastBmpValue) {
if (config::enable_i2c.value() && config::enable_bmp.value())
{
if (lastBmpValue)
{
body += fmt::format("BMP085 Pressure: {:.1f} lux<br/>\n", lastBmpValue->pressure);
body += fmt::format("BMP085 Temperature: {:.1f} C<br/>\n", lastBmpValue->temperature);
body += fmt::format("BMP085 Altitude: {:.1f} m<br/>\n", lastBmpValue->altitude);
} else
}
else
body += "BMP085 not available at the moment<br/>\n";
}
@@ -192,21 +205,28 @@ esp_err_t webserver_wifi_display(httpd_req_t *req, std::string &body)
{
const auto staStatus = wifi_stack::get_sta_status();
body += fmt::format("<tr><th>STA status</th><td>{}</td></tr>\n", wifi_stack::toString(staStatus));
if (staStatus == wifi_stack::WiFiStaStatus::WL_CONNECTED) {
if (const auto result = wifi_stack::get_sta_ap_info(); result) {
if (staStatus == wifi_stack::WiFiStaStatus::WL_CONNECTED)
{
if (const auto result = wifi_stack::get_sta_ap_info(); result)
{
body += fmt::format("<tr><th>STA rssi</th><td>{}dB</td></tr>\n", result->rssi);
body += fmt::format("<tr><th>STA SSID</th><td>{}</td></tr>\n", htmlentities(result->ssid));
body += fmt::format("<tr><th>STA channel</th><td>{}</td></tr>\n", result->primary);
body += fmt::format("<tr><th>STA BSSID</th><td>{}</td></tr>\n", wifi_stack::toString(wifi_stack::mac_t{result->bssid}));
} else {
}
else
{
body += fmt::format("<tr><td colspan=\"2\">get_sta_ap_info() failed: {}</td></tr>\n", htmlentities(result.error()));
}
if (const auto result = wifi_stack::get_ip_info(TCPIP_ADAPTER_IF_STA)) {
if (const auto result = wifi_stack::get_ip_info(TCPIP_ADAPTER_IF_STA))
{
body += fmt::format("<tr><th>STA ip</th><td>{}</td></tr>\n", wifi_stack::toString(result->ip));
body += fmt::format("<tr><th>STA netmask</th><td>{}</td></tr>\n", wifi_stack::toString(result->netmask));
body += fmt::format("<tr><th>STA gw</th><td>{}</td></tr>\n", wifi_stack::toString(result->gw));
} else {
}
else
{
body += fmt::format("<tr><td colspan=\"2\">get_ip_info() failed: {}</td></tr>\n", htmlentities(result.error()));
}
}
@@ -216,7 +236,8 @@ esp_err_t webserver_wifi_display(httpd_req_t *req, std::string &body)
body += "</table>\n"
"<h3>scan result</h3>\n";
if (const auto &scanResult = wifi_stack::get_scan_result()) {
if (const auto &scanResult = wifi_stack::get_scan_result())
{
body += fmt::format("scan age: {}s<br />\n", std::chrono::round<std::chrono::seconds>(espchrono::ago(scanResult->finished)).count());
body += "<table border=\"1\">\n"
"<thead>\n"
@@ -232,7 +253,8 @@ esp_err_t webserver_wifi_display(httpd_req_t *req, std::string &body)
"</thead>\n"
"<tbody>\n";
for (const auto &entry : scanResult->entries) {
for (const auto &entry : scanResult->entries)
{
body += fmt::format(
"<tr>\n"
"<td>{}</td>\n"
@@ -254,7 +276,9 @@ esp_err_t webserver_wifi_display(httpd_req_t *req, std::string &body)
body += "</tbody>\n"
"</table>\n";
} else {
}
else
{
body += "<span style=\"color: red;\">no wifi scan result at the moment!</span><br/>\n";
}
@@ -263,13 +287,15 @@ esp_err_t webserver_wifi_display(httpd_req_t *req, std::string &body)
esp_err_t webserver_mqtt_display(httpd_req_t *req, std::string &body)
{
if (config::enable_mqtt.value()) {
if (config::enable_mqtt.value())
{
body += "<br/>\n"
"<h2>MQTT</h2>\n"
"<table border=\"1\">\n";
body += fmt::format("<tr><th>client url</th><td>{}</td></tr>\n", htmlentities(config::broker_url.value()));
body += fmt::format("<tr><th>client constructed</th><td>{}</td></tr>\n", mqttClient ? "true" : "false");
if (mqttClient) {
if (mqttClient)
{
body += fmt::format("<tr><th>client started</th><td>{}</td></tr>\n", mqttStarted ? "true" : "false");
body += fmt::format("<tr><th>client connected</th><td>{}</td></tr>\n", mqttConnected ? "true" : "false");
}
@@ -292,21 +318,27 @@ std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<bool> &con
{
char valueBufEncoded[256];
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK) {
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK)
{
char valueBuf[257];
espcpputils::urldecode(valueBuf, valueBufEncoded);
std::string_view value{valueBuf};
if (value == "true" || value == "false") {
if (value == "true" || value == "false")
{
if (const auto result = config.writeToFlash(value == "true"))
str += "<span style=\"color: green;\">Successfully saved</span>";
else
str += fmt::format("<span style=\"color: red;\">Error while saving: {}</span>", htmlentities(result.error()));
} else {
}
else
{
str += fmt::format("<span style=\"color: red;\">Error while saving: Invalid value \"{}\"</span>", htmlentities(value));
}
} else if (result != ESP_ERR_NOT_FOUND) {
}
else if (result != ESP_ERR_NOT_FOUND)
{
ESP_LOGE(TAG, "httpd_query_key_value() %s failed with %s", config.nvsKey(), esp_err_to_name(result));
str += fmt::format("<span style=\"color: red;\">Error while saving: httpd_query_key_value() failed with {}</span>", esp_err_to_name(result));
}
@@ -331,7 +363,8 @@ std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<std::strin
{
char valueBufEncoded[256];
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK) {
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK)
{
char valueBuf[257];
espcpputils::urldecode(valueBuf, valueBufEncoded);
@@ -339,7 +372,9 @@ std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<std::strin
str += "<span style=\"color: green;\">Successfully saved</span>";
else
str += fmt::format("<span style=\"color: red;\">Error while saving: {}</span>", htmlentities(result.error()));
} else if (result != ESP_ERR_NOT_FOUND) {
}
else if (result != ESP_ERR_NOT_FOUND)
{
ESP_LOGE(TAG, "httpd_query_key_value() %s failed with %s", config.nvsKey(), esp_err_to_name(result));
str += fmt::format("<span style=\"color: red;\">Error while saving: httpd_query_key_value() failed with {}</span>", esp_err_to_name(result));
}
@@ -362,21 +397,27 @@ std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<gpio_num_t
{
char valueBufEncoded[256];
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK) {
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK)
{
char valueBuf[257];
espcpputils::urldecode(valueBuf, valueBufEncoded);
std::string_view value{valueBuf};
if (auto parsed = cpputils::fromString<std::underlying_type_t<gpio_num_t>>(value)) {
if (auto parsed = cpputils::fromString<std::underlying_type_t<gpio_num_t>>(value))
{
if (const auto result = config.writeToFlash(gpio_num_t(*parsed)))
str += "<span style=\"color: green;\">Successfully saved</span>";
else
str += fmt::format("<span style=\"color: red;\">Error while saving: {}</span>", htmlentities(result.error()));
} else {
}
else
{
str += fmt::format("<span style=\"color: red;\">Error while saving: Invalid value \"{}\"</span>", htmlentities(value));
}
} else if (result != ESP_ERR_NOT_FOUND) {
}
else if (result != ESP_ERR_NOT_FOUND)
{
ESP_LOGE(TAG, "httpd_query_key_value() %s failed with %s", config.nvsKey(), esp_err_to_name(result));
}
}
@@ -398,21 +439,27 @@ std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<espchrono:
{
char valueBufEncoded[256];
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK) {
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK)
{
char valueBuf[257];
espcpputils::urldecode(valueBuf, valueBufEncoded);
std::string_view value{valueBuf};
if (auto parsed = cpputils::fromString<espchrono::seconds32::rep>(value)) {
if (auto parsed = cpputils::fromString<espchrono::seconds32::rep>(value))
{
if (const auto result = config.writeToFlash(espchrono::seconds32(*parsed)))
str += "<span style=\"color: green;\">Successfully saved</span>";
else
str += fmt::format("<span style=\"color: red;\">Error while saving: {}</span>", htmlentities(result.error()));
} else {
}
else
{
str += fmt::format("<span style=\"color: red;\">Error while saving: Invalid value \"{}\"</span>", htmlentities(value));
}
} else if (result != ESP_ERR_NOT_FOUND) {
}
else if (result != ESP_ERR_NOT_FOUND)
{
ESP_LOGE(TAG, "httpd_query_key_value() %s failed with %s", config.nvsKey(), esp_err_to_name(result));
}
}
@@ -442,7 +489,7 @@ esp_err_t webserver_config_display(httpd_req_t *req, std::string &body, std::str
"</thead>\n"
"<tbody>\n";
config::foreachConfig([&](auto &config){
config::foreachConfig([&](auto &config) {
using cpputils::toString;
using espchrono::toString;
@@ -456,12 +503,14 @@ esp_err_t webserver_config_display(httpd_req_t *req, std::string &body, std::str
//htmlentities(toString(config.value())),
webserver_form_for_config(req, config, query),
[&]() -> std::string {
if (const auto result = config.readFromFlash()) {
if (const auto result = config.readFromFlash())
{
if (*result)
return htmlentities(toString(**result));
else
return "<span style=\"color: grey;\">not set</span>";
} else
}
else
return fmt::format("<span style=\"color: red\">{}</span>", htmlentities(result.error()));
}());
});
@@ -474,7 +523,8 @@ esp_err_t webserver_config_display(httpd_req_t *req, std::string &body, std::str
esp_err_t webserver_on_handler(httpd_req_t *req)
{
if (!config::enable_lamp.value()) {
if (!config::enable_lamp.value())
{
ESP_LOGW(TAG, "lamp support not enabled!");
CALL_AND_EXIT(httpd_resp_send_err, req, HTTPD_400_BAD_REQUEST, "lamp support not enabled!")
}
@@ -492,7 +542,8 @@ esp_err_t webserver_on_handler(httpd_req_t *req)
esp_err_t webserver_off_handler(httpd_req_t *req)
{
if (!config::enable_lamp.value()) {
if (!config::enable_lamp.value())
{
ESP_LOGW(TAG, "lamp support not enabled!");
CALL_AND_EXIT(httpd_resp_send_err, req, HTTPD_400_BAD_REQUEST, "lamp support not enabled!")
}
@@ -510,7 +561,8 @@ esp_err_t webserver_off_handler(httpd_req_t *req)
esp_err_t webserver_toggle_handler(httpd_req_t *req)
{
if (!config::enable_lamp.value()) {
if (!config::enable_lamp.value())
{
ESP_LOGW(TAG, "lamp support not enabled!");
CALL_AND_EXIT(httpd_resp_send_err, req, HTTPD_400_BAD_REQUEST, "lamp support not enabled!")
}