config can now be changed from webpage
This commit is contained in:
Submodule components/cpputils updated: a33ed96bc5...89bff1a8dc
Submodule components/espcpputils updated: a504262f39...3dc1efd38d
@@ -13,6 +13,7 @@ set(headers
|
||||
mymdns.h
|
||||
mymqtt.h
|
||||
mywifi.h
|
||||
nvswrappers.h
|
||||
webserver.h
|
||||
)
|
||||
|
||||
|
@@ -2,149 +2,65 @@
|
||||
|
||||
// system includes
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
// esp-idf includes
|
||||
#include <nvs.h>
|
||||
#include <hal/gpio_types.h>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <tl/expected.hpp>
|
||||
#include <fmt/core.h>
|
||||
|
||||
// local includes
|
||||
#include "espchrono.h"
|
||||
#include "futurecpp.h"
|
||||
#include "nvswrappers.h"
|
||||
#include "refwhenneeded.h"
|
||||
|
||||
namespace deckenlampe {
|
||||
extern nvs_handle_t nvsHandle;
|
||||
|
||||
template<typename T> esp_err_t nvs_get(nvs_handle handle, const char* key, T* out_value) = delete;
|
||||
template<typename T> esp_err_t nvs_set(nvs_handle handle, const char* key, T value) = delete;
|
||||
|
||||
template<typename T>
|
||||
class ConfigWrapper
|
||||
{
|
||||
public:
|
||||
ConfigWrapper(const char *key, const T &value) : m_key{key}, m_value{value} {}
|
||||
ConfigWrapper(const char *name, const char *nvsKey, typename cpputils::RefWhenNeeded<T>::T value) :
|
||||
m_name{name},
|
||||
m_nvsKey{nvsKey},
|
||||
m_value{value}
|
||||
{}
|
||||
|
||||
const char *key() const { return m_key; }
|
||||
const T &value() const { return m_value; }
|
||||
void setValue(const T &value) { m_value = value; }
|
||||
const char *name() const { return m_name; }
|
||||
const char *nvsKey() const { return m_nvsKey; }
|
||||
typename cpputils::RefWhenNeeded<T>::T value() const { return m_value; }
|
||||
void setValue(typename cpputils::RefWhenNeeded<T>::T value) { m_value = value; }
|
||||
|
||||
tl::expected<T, std::string> readFromFlash() const;
|
||||
tl::expected<void, std::string> writeToFlash(const T &value);
|
||||
tl::expected<std::optional<T>, std::string> readFromFlash() const;
|
||||
tl::expected<void, std::string> writeToFlash(typename cpputils::RefWhenNeeded<T>::T value);
|
||||
|
||||
private:
|
||||
const char * const m_key;
|
||||
const char * const m_name;
|
||||
const char * const m_nvsKey;
|
||||
T m_value;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
tl::expected<T, std::string> ConfigWrapper<T>::readFromFlash() const
|
||||
tl::expected<std::optional<T>, std::string> ConfigWrapper<T>::readFromFlash() const
|
||||
{
|
||||
T val;
|
||||
|
||||
const auto result = nvs_get(nvsHandle, m_key, &val);
|
||||
//ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_flash_init(): %s", esp_err_to_name(result));
|
||||
const auto result = nvs_get(nvsHandle, m_nvsKey, &val);
|
||||
//ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_get() %s: %s", m_nvsKey, esp_err_to_name(result));
|
||||
if (result == ESP_OK)
|
||||
return val;
|
||||
else if (result == ESP_ERR_NVS_NOT_FOUND)
|
||||
return std::nullopt;
|
||||
else
|
||||
return tl::make_unexpected(fmt::format("nvs_get() {} failed with {}", m_key, esp_err_to_name(result)));
|
||||
return tl::make_unexpected(fmt::format("nvs_get() {} failed with {}", m_nvsKey, esp_err_to_name(result)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
tl::expected<void, std::string> ConfigWrapper<T>::writeToFlash(const T &value)
|
||||
tl::expected<void, std::string> ConfigWrapper<T>::writeToFlash(typename cpputils::RefWhenNeeded<T>::T value)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, int8_t* out_value) { return nvs_get_i8 (handle, key, out_value); }
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, uint8_t* out_value) { return nvs_get_u8 (handle, key, out_value); }
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, int16_t* out_value) { return nvs_get_i16(handle, key, out_value); }
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, uint16_t* out_value){ return nvs_get_u16(handle, key, out_value); }
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, int32_t* out_value) { return nvs_get_i32(handle, key, out_value); }
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, uint32_t* out_value){ return nvs_get_u32(handle, key, out_value); }
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, int64_t* out_value) { return nvs_get_i64(handle, key, out_value); }
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, uint64_t* out_value){ return nvs_get_u64(handle, key, out_value); }
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, bool* out_value)
|
||||
{
|
||||
uint8_t temp;
|
||||
const auto result = nvs_get(handle, key, &temp);
|
||||
if (result == ESP_OK && out_value)
|
||||
*out_value = temp;
|
||||
return result;
|
||||
}
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, gpio_num_t* out_value)
|
||||
{
|
||||
std::underlying_type_t<gpio_num_t> temp;
|
||||
const auto result = nvs_get(handle, key, &temp);
|
||||
if (result == ESP_OK && out_value)
|
||||
*out_value = gpio_num_t(temp);
|
||||
return result;
|
||||
}
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, float* out_value)
|
||||
{
|
||||
uint32_t temp;
|
||||
const auto result = nvs_get(handle, key, &temp);
|
||||
const auto result = nvs_set(nvsHandle, m_nvsKey, value);
|
||||
//ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_set() %s: %s", m_nvsKey, esp_err_to_name(result));
|
||||
if (result == ESP_OK)
|
||||
*out_value = std::bit_cast<float>(temp);
|
||||
return result;
|
||||
return {};
|
||||
else
|
||||
return tl::make_unexpected(fmt::format("nvs_set() {} failed with {}", m_nvsKey, esp_err_to_name(result)));
|
||||
}
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, double* out_value)
|
||||
{
|
||||
uint64_t temp;
|
||||
const auto result = nvs_get(handle, key, &temp);
|
||||
if (result == ESP_OK)
|
||||
*out_value = std::bit_cast<double>(temp);
|
||||
return result;
|
||||
}
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, std::string* out_value)
|
||||
{
|
||||
size_t length;
|
||||
if (const esp_err_t result = nvs_get_str(handle, key, nullptr, &length); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
char buf[length];
|
||||
if (const esp_err_t result = nvs_get_str(handle, key, buf, &length); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
*out_value = buf;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, int8_t value) { return nvs_set_i8 (handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, uint8_t value) { return nvs_set_u8 (handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, int16_t value) { return nvs_set_i16(handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, uint16_t value) { return nvs_set_u16(handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, int32_t value) { return nvs_set_i32(handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, uint32_t value) { return nvs_set_u32(handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, int64_t value) { return nvs_set_i64(handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, uint64_t value) { return nvs_set_u64(handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, bool value) { return nvs_set_u8 (handle, key, value); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, gpio_num_t value) { return nvs_set (handle, key, std::to_underlying(value)); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, float value) { return nvs_set(handle, key, std::bit_cast<uint32_t>(value)); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, double value) { return nvs_set(handle, key, std::bit_cast<uint64_t>(value)); }
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, const std::string &value) { return nvs_set_str(handle, key, value.c_str()); }
|
||||
|
||||
|
||||
#define IMPLEMENT_NVS_GET_SET_CHRONO(Name) \
|
||||
template<> inline esp_err_t nvs_get(nvs_handle handle, const char* key, Name* out_value) \
|
||||
{ \
|
||||
Name::rep temp; \
|
||||
const auto result = nvs_get(handle, key, &temp); \
|
||||
if (result == ESP_OK && out_value) \
|
||||
*out_value = Name{temp}; \
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
template<> inline esp_err_t nvs_set(nvs_handle handle, const char* key, Name value) { return nvs_set(handle, key, Name::rep(value.count())); }
|
||||
|
||||
IMPLEMENT_NVS_GET_SET_CHRONO(espchrono::milliseconds32)
|
||||
IMPLEMENT_NVS_GET_SET_CHRONO(espchrono::seconds32)
|
||||
IMPLEMENT_NVS_GET_SET_CHRONO(espchrono::minutes32)
|
||||
IMPLEMENT_NVS_GET_SET_CHRONO(espchrono::hours32)
|
||||
#undef IMPLEMENT_NVS_GET_SET_CHRONO
|
||||
} // namespace deckenlampe
|
||||
|
@@ -10,57 +10,57 @@ namespace deckenlampe {
|
||||
nvs_handle_t nvsHandle;
|
||||
|
||||
namespace config {
|
||||
ConfigWrapper<std::string> hostname{"hostname", "deckenlampe1"};
|
||||
ConfigWrapper<std::string> hostname{"hostname", "hostname", "deckenlampe1"};
|
||||
|
||||
ConfigWrapper<std::string> sta_ssid{"sta_ssid", "ScheissAP"};
|
||||
ConfigWrapper<std::string> sta_key{"sta_key", "Passwort_123"};
|
||||
ConfigWrapper<std::string> sta_ssid{"sta_ssid", "sta_ssid", "ScheissAP"};
|
||||
ConfigWrapper<std::string> sta_key{"sta_key", "sta_key", "Passwort_123"};
|
||||
|
||||
ConfigWrapper<std::string> ap_ssid{"ap_ssid", "deckenlampe1"};
|
||||
ConfigWrapper<std::string> ap_key{"ap_key", "Passwort_123"};
|
||||
ConfigWrapper<std::string> ap_ssid{"ap_ssid", "ap_ssid", "deckenlampe1"};
|
||||
ConfigWrapper<std::string> ap_key{"ap_key", "ap_key", "Passwort_123"};
|
||||
|
||||
ConfigWrapper<bool> enable_webserver{"enable_webserver", true};
|
||||
ConfigWrapper<bool> enable_webserver{"enable_webserver", "enableebserver", true};
|
||||
|
||||
ConfigWrapper<bool> enable_mdns{"enable_mdns", true};
|
||||
ConfigWrapper<bool> enable_mdns{"enable_mdns", "enable_mdns", true};
|
||||
|
||||
ConfigWrapper<bool> enable_mqtt{"enable_mqtt", true};
|
||||
ConfigWrapper<std::string> broker_url{"broker_url", "mqtt://192.168.0.2/"};
|
||||
ConfigWrapper<bool> enable_mqtt{"enable_mqtt", "enable_mqtt", true};
|
||||
ConfigWrapper<std::string> broker_url{"broker_url", "broker_url", "mqtt://192.168.0.2/"};
|
||||
|
||||
ConfigWrapper<bool> enable_lamp{"enable_lamp", true};
|
||||
ConfigWrapper<gpio_num_t> pins_lamp{"pins_lamp", GPIO_NUM_4};
|
||||
ConfigWrapper<bool> invertLamp{"invertLamp", true};
|
||||
ConfigWrapper<std::string> topic_lamp_availability{"topic_lamp_availability", "dahoam/wohnzimmer/deckenlicht1/available"};
|
||||
ConfigWrapper<std::string> topic_lamp_status{"topic_lamp_status", "dahoam/wohnzimmer/deckenlicht1/status"};
|
||||
ConfigWrapper<std::string> topic_lamp_set{"topic_lamp_set", "dahoam/wohnzimmer/deckenlicht1/set"};
|
||||
ConfigWrapper<bool> enable_lamp{"enable_lamp", "enable_lamp", true};
|
||||
ConfigWrapper<gpio_num_t> pins_lamp{"pins_lamp", "pins_lamp", GPIO_NUM_4};
|
||||
ConfigWrapper<bool> invertLamp{"invertLamp", "invertLamp", true};
|
||||
ConfigWrapper<std::string> topic_lamp_availability{"topic_lamp_availability", "topiclampavaila", "dahoam/wohnzimmer/deckenlicht1/available"};
|
||||
ConfigWrapper<std::string> topic_lamp_status{"topic_lamp_status", "topic_lamp_stat", "dahoam/wohnzimmer/deckenlicht1/status"};
|
||||
ConfigWrapper<std::string> topic_lamp_set{"topic_lamp_set", "topic_lamp_set", "dahoam/wohnzimmer/deckenlicht1/set"};
|
||||
|
||||
|
||||
ConfigWrapper<bool> enable_switch{"enable_switch", true};
|
||||
ConfigWrapper<gpio_num_t> pins_switch{"pins_switch", GPIO_NUM_35};
|
||||
ConfigWrapper<bool> invert_switch{"invert_switch", true};
|
||||
ConfigWrapper<std::string> topic_switch_availability{"topic_switch_availability", "dahoam/wohnzimmer/schalter1/available"};
|
||||
ConfigWrapper<std::string> topic_switch_status{"topic_switch_status", "dahoam/wohnzimmer/schalter1/status"};
|
||||
ConfigWrapper<bool> enable_switch{"enable_switch", "enable_switch", true};
|
||||
ConfigWrapper<gpio_num_t> pins_switch{"pins_switch", "pins_switch", GPIO_NUM_35};
|
||||
ConfigWrapper<bool> invert_switch{"invert_switch", "invert_switch", true};
|
||||
ConfigWrapper<std::string> topic_switch_availability{"topic_switch_availability", "tpcswitchavaila", "dahoam/wohnzimmer/schalter1/available"};
|
||||
ConfigWrapper<std::string> topic_switch_status{"topic_switch_status", "topicswitchstat", "dahoam/wohnzimmer/schalter1/status"};
|
||||
|
||||
ConfigWrapper<bool> enable_dht{"enable_dht", true};
|
||||
ConfigWrapper<gpio_num_t> pins_dht{"pins_dht", GPIO_NUM_33};
|
||||
ConfigWrapper<std::string> topic_dht11_availability{"topic_dht11_availability", "dahoam/wohnzimmer/dht11_1/available"};
|
||||
ConfigWrapper<std::string> topic_dht11_temperature{"topic_dht11_temperature", "dahoam/wohnzimmer/dht11_1/temperature"};
|
||||
ConfigWrapper<std::string> topic_dht11_humidity{"topic_dht11_humidity", "dahoam/wohnzimmer/dht11_1/humidity"};
|
||||
ConfigWrapper<bool> enable_dht{"enable_dht", "enable_dht", true};
|
||||
ConfigWrapper<gpio_num_t> pins_dht{"pins_dht", "pins_dht", GPIO_NUM_33};
|
||||
ConfigWrapper<std::string> topic_dht11_availability{"topic_dht11_availability", "tpcdht11availab", "dahoam/wohnzimmer/dht11_1/available"};
|
||||
ConfigWrapper<std::string> topic_dht11_temperature{"topic_dht11_temperature", "tpcdht11tempera", "dahoam/wohnzimmer/dht11_1/temperature"};
|
||||
ConfigWrapper<std::string> topic_dht11_humidity{"topic_dht11_humidity", "tpcdht11humidit", "dahoam/wohnzimmer/dht11_1/humidity"};
|
||||
|
||||
ConfigWrapper<bool> enable_i2c{"enable_i2c", true};
|
||||
ConfigWrapper<gpio_num_t> pins_sda{"pins_sda", GPIO_NUM_16};
|
||||
ConfigWrapper<gpio_num_t> pins_scl{"pins_scl", GPIO_NUM_17};
|
||||
ConfigWrapper<bool> enable_i2c{"enable_i2c", "enable_i2c", true};
|
||||
ConfigWrapper<gpio_num_t> pins_sda{"pins_sda", "pins_sda", GPIO_NUM_16};
|
||||
ConfigWrapper<gpio_num_t> pins_scl{"pins_scl", "pins_scl", GPIO_NUM_17};
|
||||
|
||||
ConfigWrapper<bool> enable_tsl{"enable_tsl", true};
|
||||
ConfigWrapper<std::string> topic_tsl2561_availability{"topic_tsl2561_availability", "dahoam/wohnzimmer/tsl2561_1/available"};
|
||||
ConfigWrapper<std::string> topic_tsl2561_lux{"topic_tsl2561_lux", "dahoam/wohnzimmer/tsl2561_1/lux"};
|
||||
ConfigWrapper<bool> enable_tsl{"enable_tsl", "enable_tsl", true};
|
||||
ConfigWrapper<std::string> topic_tsl2561_availability{"topic_tsl2561_availability", "tpctsl2561avail", "dahoam/wohnzimmer/tsl2561_1/available"};
|
||||
ConfigWrapper<std::string> topic_tsl2561_lux{"topic_tsl2561_lux", "tpc_tsl2561_lux", "dahoam/wohnzimmer/tsl2561_1/lux"};
|
||||
|
||||
ConfigWrapper<bool> enable_bmp{"enable_bmp", true};
|
||||
ConfigWrapper<std::string> topic_bmp085_availability{"topic_bmp085_availability", "dahoam/wohnzimmer/bmp085_1/available"};
|
||||
ConfigWrapper<std::string> topic_bmp085_pressure{"topic_bmp085_pressure", "dahoam/wohnzimmer/bmp085_1/pressure"};
|
||||
ConfigWrapper<std::string> topic_bmp085_temperature{"topic_bmp085_temperature", "dahoam/wohnzimmer/bmp085_1/temperature"};
|
||||
ConfigWrapper<std::string> topic_bmp085_altitude{"topic_bmp085_altitude", "dahoam/wohnzimmer/bmp085_1/altitude"};
|
||||
ConfigWrapper<bool> enable_bmp{"enable_bmp", "enable_bmp", true};
|
||||
ConfigWrapper<std::string> topic_bmp085_availability{"topic_bmp085_availability", "topicbmp085avai", "dahoam/wohnzimmer/bmp085_1/available"};
|
||||
ConfigWrapper<std::string> topic_bmp085_pressure{"topic_bmp085_pressure", "tpcbmp085pressu", "dahoam/wohnzimmer/bmp085_1/pressure"};
|
||||
ConfigWrapper<std::string> topic_bmp085_temperature{"topic_bmp085_temperature", "tpcbmp085temper", "dahoam/wohnzimmer/bmp085_1/temperature"};
|
||||
ConfigWrapper<std::string> topic_bmp085_altitude{"topic_bmp085_altitude", "tpcbmp085altitu", "dahoam/wohnzimmer/bmp085_1/altitude"};
|
||||
|
||||
ConfigWrapper<espchrono::seconds32> availableTimeoutTime{"availableTimeoutTime", 1min};
|
||||
ConfigWrapper<espchrono::seconds32> valueUpdateInterval{"valueUpdateInterval", 15s};
|
||||
ConfigWrapper<espchrono::seconds32> availableTimeoutTime{"availableTimeoutTime", "availTimeouTime", 1min};
|
||||
ConfigWrapper<espchrono::seconds32> valueUpdateInterval{"valueUpdateInterval", "valUpdaInterval", 15s};
|
||||
} // namespace config
|
||||
|
||||
namespace {
|
||||
@@ -87,44 +87,7 @@ void init_config()
|
||||
return;
|
||||
}
|
||||
|
||||
loadParam(config::hostname);
|
||||
loadParam(config::sta_ssid);
|
||||
loadParam(config::sta_key);
|
||||
loadParam(config::ap_ssid);
|
||||
loadParam(config::ap_key);
|
||||
loadParam(config::enable_webserver);
|
||||
loadParam(config::enable_mdns);
|
||||
loadParam(config::enable_mqtt);
|
||||
loadParam(config::broker_url);
|
||||
loadParam(config::enable_lamp);
|
||||
loadParam(config::pins_lamp);
|
||||
loadParam(config::invertLamp);
|
||||
loadParam(config::topic_lamp_availability);
|
||||
loadParam(config::topic_lamp_status);
|
||||
loadParam(config::topic_lamp_set);
|
||||
loadParam(config::enable_switch);
|
||||
loadParam(config::pins_switch);
|
||||
loadParam(config::invert_switch);
|
||||
loadParam(config::topic_switch_availability);
|
||||
loadParam(config::topic_switch_status);
|
||||
loadParam(config::enable_dht);
|
||||
loadParam(config::pins_dht);
|
||||
loadParam(config::topic_dht11_availability);
|
||||
loadParam(config::topic_dht11_temperature);
|
||||
loadParam(config::topic_dht11_humidity);
|
||||
loadParam(config::enable_i2c);
|
||||
loadParam(config::pins_sda);
|
||||
loadParam(config::pins_scl);
|
||||
loadParam(config::enable_tsl);
|
||||
loadParam(config::topic_tsl2561_availability);
|
||||
loadParam(config::topic_tsl2561_lux);
|
||||
loadParam(config::enable_bmp);
|
||||
loadParam(config::topic_bmp085_availability);
|
||||
loadParam(config::topic_bmp085_pressure);
|
||||
loadParam(config::topic_bmp085_temperature);
|
||||
loadParam(config::topic_bmp085_altitude);
|
||||
loadParam(config::availableTimeoutTime);
|
||||
loadParam(config::valueUpdateInterval);
|
||||
config::foreachConfig([](auto &config){ loadParam(config); });
|
||||
}
|
||||
|
||||
void update_config()
|
||||
@@ -135,10 +98,16 @@ namespace {
|
||||
template<typename T>
|
||||
void loadParam(ConfigWrapper<T> &config)
|
||||
{
|
||||
if (const auto value = config.readFromFlash())
|
||||
config.setValue(*value);
|
||||
else
|
||||
ESP_LOGE(TAG, "error loading param %s: %.*s", config.key(), value.error().size(), value.error().data());
|
||||
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 (*value)
|
||||
config.setValue(**value);
|
||||
} else
|
||||
ESP_LOGE(TAG, "error loading config %s: %.*s", config.name(), value.error().size(), value.error().data());
|
||||
}
|
||||
} // namespace
|
||||
} // namespace deckenlamp
|
||||
|
@@ -66,7 +66,50 @@ extern ConfigWrapper<std::string> topic_bmp085_altitude;
|
||||
|
||||
extern ConfigWrapper<espchrono::seconds32> availableTimeoutTime;
|
||||
extern ConfigWrapper<espchrono::seconds32> valueUpdateInterval;
|
||||
} // namespace configs
|
||||
|
||||
template<typename T>
|
||||
void foreachConfig(T &&callback)
|
||||
{
|
||||
callback(hostname);
|
||||
callback(sta_ssid);
|
||||
callback(sta_key);
|
||||
callback(ap_ssid);
|
||||
callback(ap_key);
|
||||
callback(enable_webserver);
|
||||
callback(enable_mdns);
|
||||
callback(enable_mqtt);
|
||||
callback(broker_url);
|
||||
callback(enable_lamp);
|
||||
callback(pins_lamp);
|
||||
callback(invertLamp);
|
||||
callback(topic_lamp_availability);
|
||||
callback(topic_lamp_status);
|
||||
callback(topic_lamp_set);
|
||||
callback(enable_switch);
|
||||
callback(pins_switch);
|
||||
callback(invert_switch);
|
||||
callback(topic_switch_availability);
|
||||
callback(topic_switch_status);
|
||||
callback(enable_dht);
|
||||
callback(pins_dht);
|
||||
callback(topic_dht11_availability);
|
||||
callback(topic_dht11_temperature);
|
||||
callback(topic_dht11_humidity);
|
||||
callback(enable_i2c);
|
||||
callback(pins_sda);
|
||||
callback(pins_scl);
|
||||
callback(enable_tsl);
|
||||
callback(topic_tsl2561_availability);
|
||||
callback(topic_tsl2561_lux);
|
||||
callback(enable_bmp);
|
||||
callback(topic_bmp085_availability);
|
||||
callback(topic_bmp085_pressure);
|
||||
callback(topic_bmp085_temperature);
|
||||
callback(topic_bmp085_altitude);
|
||||
callback(availableTimeoutTime);
|
||||
callback(valueUpdateInterval);
|
||||
}
|
||||
} // namespace config
|
||||
|
||||
void init_config();
|
||||
void update_config();
|
||||
|
104
main/nvswrappers.h
Normal file
104
main/nvswrappers.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
// esp-idf includes
|
||||
#include <nvs.h>
|
||||
#include <hal/gpio_types.h>
|
||||
|
||||
// local includes
|
||||
#include "futurecpp.h"
|
||||
#include "espchrono.h"
|
||||
|
||||
namespace deckenlampe {
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, int8_t* out_value) { return nvs_get_i8 (handle, key, out_value); }
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, uint8_t* out_value) { return nvs_get_u8 (handle, key, out_value); }
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, int16_t* out_value) { return nvs_get_i16(handle, key, out_value); }
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, uint16_t* out_value){ return nvs_get_u16(handle, key, out_value); }
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, int32_t* out_value) { return nvs_get_i32(handle, key, out_value); }
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, uint32_t* out_value){ return nvs_get_u32(handle, key, out_value); }
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, int64_t* out_value) { return nvs_get_i64(handle, key, out_value); }
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, uint64_t* out_value){ return nvs_get_u64(handle, key, out_value); }
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, bool* out_value)
|
||||
{
|
||||
uint8_t temp;
|
||||
const auto result = nvs_get(handle, key, &temp);
|
||||
if (result == ESP_OK && out_value)
|
||||
*out_value = temp;
|
||||
return result;
|
||||
}
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, gpio_num_t* out_value)
|
||||
{
|
||||
std::underlying_type_t<gpio_num_t> temp;
|
||||
const auto result = nvs_get(handle, key, &temp);
|
||||
if (result == ESP_OK && out_value)
|
||||
*out_value = gpio_num_t(temp);
|
||||
return result;
|
||||
}
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, float* out_value)
|
||||
{
|
||||
uint32_t temp;
|
||||
const auto result = nvs_get(handle, key, &temp);
|
||||
if (result == ESP_OK)
|
||||
*out_value = std::bit_cast<float>(temp);
|
||||
return result;
|
||||
}
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, double* out_value)
|
||||
{
|
||||
uint64_t temp;
|
||||
const auto result = nvs_get(handle, key, &temp);
|
||||
if (result == ESP_OK)
|
||||
*out_value = std::bit_cast<double>(temp);
|
||||
return result;
|
||||
}
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, std::string* out_value)
|
||||
{
|
||||
size_t length;
|
||||
if (const esp_err_t result = nvs_get_str(handle, key, nullptr, &length); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
char buf[length];
|
||||
if (const esp_err_t result = nvs_get_str(handle, key, buf, &length); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
*out_value = buf;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, int8_t value) { return nvs_set_i8 (handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, uint8_t value) { return nvs_set_u8 (handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, int16_t value) { return nvs_set_i16(handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, uint16_t value) { return nvs_set_u16(handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, int32_t value) { return nvs_set_i32(handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, uint32_t value) { return nvs_set_u32(handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, int64_t value) { return nvs_set_i64(handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, uint64_t value) { return nvs_set_u64(handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, bool value) { return nvs_set_u8 (handle, key, value); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, gpio_num_t value) { return nvs_set (handle, key, std::to_underlying(value)); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, float value) { return nvs_set(handle, key, std::bit_cast<uint32_t>(value)); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, double value) { return nvs_set(handle, key, std::bit_cast<uint64_t>(value)); }
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, const std::string &value) { return nvs_set_str(handle, key, value.c_str()); }
|
||||
|
||||
|
||||
#define IMPLEMENT_NVS_GET_SET_CHRONO(Name) \
|
||||
inline esp_err_t nvs_get(nvs_handle handle, const char* key, Name* out_value) \
|
||||
{ \
|
||||
Name::rep temp; \
|
||||
const auto result = nvs_get(handle, key, &temp); \
|
||||
if (result == ESP_OK && out_value) \
|
||||
*out_value = Name{temp}; \
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
inline esp_err_t nvs_set(nvs_handle handle, const char* key, Name value) { return nvs_set(handle, key, Name::rep(value.count())); }
|
||||
|
||||
IMPLEMENT_NVS_GET_SET_CHRONO(espchrono::milliseconds32)
|
||||
IMPLEMENT_NVS_GET_SET_CHRONO(espchrono::seconds32)
|
||||
IMPLEMENT_NVS_GET_SET_CHRONO(espchrono::minutes32)
|
||||
IMPLEMENT_NVS_GET_SET_CHRONO(espchrono::hours32)
|
||||
#undef IMPLEMENT_NVS_GET_SET_CHRONO
|
||||
} // namespace deckenlampe
|
@@ -19,6 +19,11 @@
|
||||
#include "feature_bmp.h"
|
||||
#include "mymqtt.h"
|
||||
#include "espwifistack.h"
|
||||
#include "espcppmacros.h"
|
||||
#include "espstrutils.h"
|
||||
#include "strutils.h"
|
||||
#include "espchrono.h"
|
||||
#include "numberparsing.h"
|
||||
|
||||
namespace deckenlampe {
|
||||
httpd_handle_t httpdHandle;
|
||||
@@ -73,25 +78,23 @@ void update_webserver()
|
||||
}
|
||||
|
||||
namespace {
|
||||
#define CALL_AND_EXIT_ON_ERROR(METHOD, ...) \
|
||||
if (const auto result = METHOD(__VA_ARGS__); result != ESP_OK) \
|
||||
{ \
|
||||
ESP_LOGE(TAG, "%s() failed with %s", #METHOD, esp_err_to_name(result)); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define CALL_AND_EXIT(METHOD, ...) \
|
||||
if (const auto result = METHOD(__VA_ARGS__); result != ESP_OK) \
|
||||
{ \
|
||||
ESP_LOGE(TAG, "%s() failed with %s", #METHOD, esp_err_to_name(result)); \
|
||||
return result; \
|
||||
} \
|
||||
else \
|
||||
return result;
|
||||
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);
|
||||
esp_err_t webserver_bmp_display(httpd_req_t *req, std::string &body);
|
||||
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);
|
||||
esp_err_t webserver_config_display(httpd_req_t *req, std::string &body, std::string_view query);
|
||||
|
||||
esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
{
|
||||
std::string body = "this is work in progress...<br/>\n";
|
||||
std::string query;
|
||||
|
||||
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()) {
|
||||
body += "<a href=\"/on\">on</a><br/>\n"
|
||||
@@ -108,6 +111,34 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
if (config::enable_switch.value())
|
||||
body += fmt::format("Switch: {}<br/>\n", switchState ? "ON" : "OFF");
|
||||
|
||||
if (const auto result = webserver_dht_display(req, body); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
if (const auto result = webserver_tsl_display(req, body); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
if (const auto result = webserver_bmp_display(req, body); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
body += "<br/>\n";
|
||||
|
||||
if (const auto result = webserver_wifi_display(req, body); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
if (const auto result = webserver_mqtt_display(req, body); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
if (const auto result = webserver_config_display(req, body, query); result != ESP_OK)
|
||||
return result;
|
||||
|
||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t webserver_dht_display(httpd_req_t *req, std::string &body)
|
||||
{
|
||||
if (config::enable_dht.value()) {
|
||||
if (lastDhtValue) {
|
||||
body += fmt::format("DHT11 Temperature: {:.1f} C<br/>\n", lastDhtValue->temperature);
|
||||
@@ -116,6 +147,11 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
body += "DHT11 not available at the moment<br/>\n";
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t webserver_tsl_display(httpd_req_t *req, std::string &body)
|
||||
{
|
||||
if (config::enable_i2c.value() && config::enable_tsl.value()) {
|
||||
if (lastTslValue) {
|
||||
body += fmt::format("TSL2561 Brightness: {:.1f} lux<br/>\n", lastTslValue->lux);
|
||||
@@ -123,6 +159,11 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
body += "TSL2561 not available at the moment<br/>\n";
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t webserver_bmp_display(httpd_req_t *req, std::string &body)
|
||||
{
|
||||
if (config::enable_i2c.value() && config::enable_bmp.value()) {
|
||||
if (lastBmpValue) {
|
||||
body += fmt::format("BMP085 Pressure: {:.1f} lux<br/>\n", lastBmpValue->pressure);
|
||||
@@ -132,8 +173,12 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
body += "BMP085 not available at the moment<br/>\n";
|
||||
}
|
||||
|
||||
body += "<br/>\n"
|
||||
"<h2>wifi</h2>\n"
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t webserver_wifi_display(httpd_req_t *req, std::string &body)
|
||||
{
|
||||
body += "<h2>wifi</h2>\n"
|
||||
"<table border=\"1\">\n";
|
||||
body += fmt::format("<tr><th>state machine state</th><td>{}</td></tr>\n", wifi_stack::toString(wifi_stack::wifiStateMachineState));
|
||||
|
||||
@@ -182,15 +227,15 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
|
||||
for (const auto &entry : scanResult->entries) {
|
||||
body += fmt::format(
|
||||
"<tr>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"</tr>\n",
|
||||
"<tr>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"</tr>\n",
|
||||
htmlentities(entry.ssid),
|
||||
wifi_stack::toString(entry.authmode),
|
||||
wifi_stack::toString(entry.pairwise_cipher),
|
||||
@@ -206,6 +251,11 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
body += "<span style=\"color: red;\">no wifi scan result at the moment!</span><br/>\n";
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t webserver_mqtt_display(httpd_req_t *req, std::string &body)
|
||||
{
|
||||
if (config::enable_mqtt.value()) {
|
||||
body += "<br/>\n"
|
||||
"<h2>MQTT</h2>\n"
|
||||
@@ -219,8 +269,198 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
body += "</table>\n";
|
||||
}
|
||||
|
||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<T> &config, std::string_view query)
|
||||
{
|
||||
return "<span style=\"color: red;\">form not implemented</span>";
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<bool> &config, std::string_view query)
|
||||
{
|
||||
std::string str;
|
||||
|
||||
{
|
||||
char valueBufEncoded[256];
|
||||
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 (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 {
|
||||
str += fmt::format("<span style=\"color: red;\">Error while saving: Invalid value \"{}\"</span>", htmlentities(value));
|
||||
}
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
|
||||
str += fmt::format("<form>"
|
||||
"<input type=\"hidden\" name=\"{}\" value=\"false\" />"
|
||||
"<input type=\"checkbox\" name=\"{}\" value=\"true\"{} />"
|
||||
"<button type=\"submit\">Save</button>"
|
||||
"</form>",
|
||||
htmlentities(config.nvsKey()),
|
||||
htmlentities(config.nvsKey()),
|
||||
config.value() ? " checked" : "");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<std::string> &config, std::string_view query)
|
||||
{
|
||||
std::string str;
|
||||
|
||||
{
|
||||
char valueBufEncoded[256];
|
||||
if (const auto result = httpd_query_key_value(query.data(), config.nvsKey(), valueBufEncoded, 256); result == ESP_OK) {
|
||||
char valueBuf[257];
|
||||
espcpputils::urldecode(valueBuf, valueBufEncoded);
|
||||
|
||||
if (const auto result = config.writeToFlash(valueBuf))
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
str += fmt::format("<form>"
|
||||
"<input type=\"text\" name=\"{}\" value=\"{}\" />"
|
||||
"<button type=\"submit\">Save</button>"
|
||||
"</form>",
|
||||
htmlentities(config.nvsKey()),
|
||||
htmlentities(config.value()));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<gpio_num_t> &config, std::string_view query)
|
||||
{
|
||||
std::string str;
|
||||
|
||||
{
|
||||
char valueBufEncoded[256];
|
||||
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 (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 {
|
||||
str += fmt::format("<span style=\"color: red;\">Error while saving: Invalid value \"{}\"</span>", htmlentities(value));
|
||||
}
|
||||
} 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("<form>"
|
||||
"<input type=\"number\" name=\"{}\" value=\"{}\" />"
|
||||
"<button type=\"submit\">Save</button>"
|
||||
"</form>",
|
||||
htmlentities(config.nvsKey()),
|
||||
config.value());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string webserver_form_for_config(httpd_req_t *req, ConfigWrapper<espchrono::seconds32> &config, std::string_view query)
|
||||
{
|
||||
std::string str;
|
||||
|
||||
{
|
||||
char valueBufEncoded[256];
|
||||
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 (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 {
|
||||
str += fmt::format("<span style=\"color: red;\">Error while saving: Invalid value \"{}\"</span>", htmlentities(value));
|
||||
}
|
||||
} 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("<form>"
|
||||
"<input type=\"number\" name=\"{}\" value=\"{}\" />"
|
||||
"<button type=\"submit\">Save</button>"
|
||||
"</form>",
|
||||
htmlentities(config.nvsKey()),
|
||||
config.value().count());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
esp_err_t webserver_config_display(httpd_req_t *req, std::string &body, std::string_view query)
|
||||
{
|
||||
body += "<br/>\n"
|
||||
"<h2>config</h2>\n"
|
||||
"<table border=\"1\">\n"
|
||||
"<thead>\n"
|
||||
"<tr>\n"
|
||||
"<th>name</th>\n"
|
||||
//"<th>current value</th>\n"
|
||||
"<th>set new value</th>\n"
|
||||
"<th>value in flash</th>\n"
|
||||
"</tr>\n"
|
||||
"</thead>\n"
|
||||
"<tbody>\n";
|
||||
|
||||
config::foreachConfig([&](auto &config){
|
||||
using cpputils::toString;
|
||||
using espchrono::toString;
|
||||
|
||||
body += fmt::format("<tr>\n"
|
||||
"<th>{}</th>\n"
|
||||
//"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"<td>{}</td>\n"
|
||||
"</tr>\n",
|
||||
htmlentities(config.name()),
|
||||
//htmlentities(toString(config.value())),
|
||||
webserver_form_for_config(req, config, query),
|
||||
[&]() -> std::string {
|
||||
if (const auto result = config.readFromFlash()) {
|
||||
if (*result)
|
||||
return htmlentities(toString(**result));
|
||||
else
|
||||
return "<span style=\"color: grey;\">not set</span>";
|
||||
} else
|
||||
return fmt::format("<span style=\"color: red\">{}</span>", htmlentities(result.error()));
|
||||
}());
|
||||
});
|
||||
|
||||
body += "</tbody>\n"
|
||||
"</table>\n";
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
Reference in New Issue
Block a user