Browse Source

Load ratios after boot + show pwr defaults with `get` (#2241)

* emon: configure ratios without reboot

* settings: serialize() support

* debug: use vsnprintf from newlib, not from sdk

* settings/experimental: show defaults via `get`

* emon: override base methods, fix defaults

* sensor/emon: expose internal index calculation

- refactor configuration to use the correct index when accessing indexed
  sensor methods. store index value on magnitude, refactor loops to
  accomodate this new functionality
- rename slot(index) -> description(index), since we use 'slot' as
  numeric value
mcspr-patch-1
Max Prokhorov 4 years ago
committed by GitHub
parent
commit
025e8c82ab
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 562 additions and 245 deletions
  1. +1
    -1
      code/espurna/alexa.cpp
  2. +48
    -0
      code/espurna/button.cpp
  3. +1
    -1
      code/espurna/crash.cpp
  4. +23
    -8
      code/espurna/debug.cpp
  5. +1
    -1
      code/espurna/influxdb.cpp
  6. +1
    -1
      code/espurna/main.cpp
  7. +1
    -1
      code/espurna/mdns.cpp
  8. +2
    -2
      code/espurna/mqtt.cpp
  9. +193
    -101
      code/espurna/sensor.cpp
  10. +7
    -2
      code/espurna/sensors/ADE7953Sensor.h
  11. +1
    -1
      code/espurna/sensors/AM2320Sensor.h
  12. +1
    -1
      code/espurna/sensors/AnalogSensor.h
  13. +34
    -6
      code/espurna/sensors/BaseEmonSensor.h
  14. +6
    -3
      code/espurna/sensors/BaseSensor.h
  15. +31
    -15
      code/espurna/sensors/CSE7766Sensor.h
  16. +1
    -1
      code/espurna/sensors/DHTSensor.h
  17. +1
    -1
      code/espurna/sensors/DallasSensor.h
  18. +1
    -1
      code/espurna/sensors/DigitalSensor.h
  19. +1
    -1
      code/espurna/sensors/ECH1560Sensor.h
  20. +1
    -1
      code/espurna/sensors/EZOPHSensor.h
  21. +1
    -1
      code/espurna/sensors/EmonADC121Sensor.h
  22. +6
    -1
      code/espurna/sensors/EmonADS1X15Sensor.h
  23. +21
    -10
      code/espurna/sensors/EmonSensor.h
  24. +1
    -1
      code/espurna/sensors/EventSensor.h
  25. +1
    -1
      code/espurna/sensors/GUVAS12SDSensor.h
  26. +1
    -1
      code/espurna/sensors/GeigerSensor.h
  27. +1
    -1
      code/espurna/sensors/HDC1080Sensor.h
  28. +73
    -43
      code/espurna/sensors/HLW8012Sensor.h
  29. +1
    -1
      code/espurna/sensors/I2CSensor.h
  30. +1
    -1
      code/espurna/sensors/LDRSensor.h
  31. +1
    -1
      code/espurna/sensors/MAX6675Sensor.h
  32. +1
    -1
      code/espurna/sensors/MHZ19Sensor.h
  33. +1
    -1
      code/espurna/sensors/MICS2710Sensor.h
  34. +1
    -1
      code/espurna/sensors/MICS5525Sensor.h
  35. +1
    -1
      code/espurna/sensors/NTCSensor.h
  36. +1
    -1
      code/espurna/sensors/PMSX003Sensor.h
  37. +17
    -12
      code/espurna/sensors/PZEM004TSensor.h
  38. +1
    -1
      code/espurna/sensors/PulseMeterSensor.h
  39. +1
    -1
      code/espurna/sensors/SDS011Sensor.h
  40. +1
    -1
      code/espurna/sensors/SI1145Sensor.h
  41. +1
    -1
      code/espurna/sensors/SI7021Sensor.h
  42. +1
    -1
      code/espurna/sensors/SenseAirSensor.h
  43. +1
    -1
      code/espurna/sensors/SonarSensor.h
  44. +1
    -1
      code/espurna/sensors/T6613Sensor.h
  45. +1
    -1
      code/espurna/sensors/TMP3XSensor.h
  46. +1
    -1
      code/espurna/sensors/V9261FSensor.h
  47. +1
    -1
      code/espurna/sensors/VEML6075Sensor.h
  48. +1
    -1
      code/espurna/sensors/VL53L1XSensor.h
  49. +16
    -0
      code/espurna/settings.cpp
  50. +32
    -2
      code/espurna/settings.h
  51. +6
    -1
      code/espurna/terminal.cpp
  52. +1
    -1
      code/espurna/thingspeak.cpp
  53. +10
    -2
      code/espurna/wifi.cpp

+ 1
- 1
code/espurna/alexa.cpp View File

@ -82,7 +82,7 @@ void _alexaBrokerCallback(const String& topic, unsigned char id, unsigned int va
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool alexaEnabled() { bool alexaEnabled() {
return getSetting<bool>("alexaEnabled", 1 == ALEXA_ENABLED);
return getSetting("alexaEnabled", 1 == ALEXA_ENABLED);
} }
void alexaLoop() { void alexaLoop() {


+ 48
- 0
code/espurna/button.cpp View File

@ -42,6 +42,21 @@ debounce_event::types::Mode convert(const String& value) {
} }
} }
template<>
String serialize(const debounce_event::types::Mode& value) {
String result;
switch (value) {
case debounce_event::types::Mode::Switch:
result = "1";
break;
case debounce_event::types::Mode::Pushbutton:
default:
result = "0";
break;
}
return result;
}
template<> template<>
debounce_event::types::PinValue convert(const String& value) { debounce_event::types::PinValue convert(const String& value) {
switch (value.toInt()) { switch (value.toInt()) {
@ -53,6 +68,21 @@ debounce_event::types::PinValue convert(const String& value) {
} }
} }
template<>
String serialize(const debounce_event::types::PinValue& value) {
String result;
switch (value) {
case debounce_event::types::PinValue::Low:
result = "0";
break;
case debounce_event::types::PinValue::High:
default:
result = "1";
break;
}
return result;
}
template<> template<>
debounce_event::types::PinMode convert(const String& value) { debounce_event::types::PinMode convert(const String& value) {
switch (value.toInt()) { switch (value.toInt()) {
@ -66,6 +96,24 @@ debounce_event::types::PinMode convert(const String& value) {
} }
} }
template<>
String serialize(const debounce_event::types::PinMode& mode) {
String result;
switch (mode) {
case debounce_event::types::PinMode::InputPullup:
result = "1";
break;
case debounce_event::types::PinMode::InputPulldown:
result = "2";
break;
case debounce_event::types::PinMode::Input:
default:
result = "0";
break;
}
return result;
}
} // namespace settings::internal } // namespace settings::internal
} // namespace settings } // namespace settings


+ 1
- 1
code/espurna/crash.cpp View File

@ -152,7 +152,7 @@ void crashSetup() {
// Minumum of 16 and align for column formatter in crashDump() // Minumum of 16 and align for column formatter in crashDump()
// Maximum of flash sector size minus reserved space at the beginning // Maximum of flash sector size minus reserved space at the beginning
const uint16_t trace_max = constrain( const uint16_t trace_max = constrain(
abs((getSetting<int>("sysTraceMax", SAVE_CRASH_STACK_TRACE_MAX) + 15) & -16),
abs((getSetting("sysTraceMax", SAVE_CRASH_STACK_TRACE_MAX) + 15) & -16),
0, (SPI_FLASH_SEC_SIZE - crashUsedSpace()) 0, (SPI_FLASH_SEC_SIZE - crashUsedSpace())
); );


+ 23
- 8
code/espurna/debug.cpp View File

@ -29,6 +29,8 @@ char _udp_syslog_header[40] = {0};
bool _debug_enabled = false; bool _debug_enabled = false;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// printf-like debug methods // printf-like debug methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -41,7 +43,7 @@ void _debugSendInternal(const char * message, bool add_timestamp = DEBUG_ADD_TIM
void _debugSend(const char * format, va_list args) { void _debugSend(const char * format, va_list args) {
char temp[DEBUG_SEND_STRING_BUFFER_SIZE]; char temp[DEBUG_SEND_STRING_BUFFER_SIZE];
int len = ets_vsnprintf(temp, sizeof(temp), format, args);
int len = vsnprintf(temp, sizeof(temp), format, args);
// strlen(...) + '\0' already in temp buffer, avoid using malloc when possible // strlen(...) + '\0' already in temp buffer, avoid using malloc when possible
if (len < DEBUG_SEND_STRING_BUFFER_SIZE) { if (len < DEBUG_SEND_STRING_BUFFER_SIZE) {
@ -54,7 +56,7 @@ void _debugSend(const char * format, va_list args) {
if (!buffer) { if (!buffer) {
return; return;
} }
ets_vsnprintf(buffer, len, format, args);
vsnprintf(buffer, len, format, args);
_debugSendInternal(buffer); _debugSendInternal(buffer);
free(buffer); free(buffer);
@ -282,19 +284,29 @@ void debugSetup() {
} }
String _debugLogModeSerialize(DebugLogMode value) {
namespace settings {
namespace internal {
template<>
String serialize(const DebugLogMode& value) {
String result;
switch (value) { switch (value) {
case DebugLogMode::Disabled: case DebugLogMode::Disabled:
return "0";
result = "0";
break;
case DebugLogMode::SkipBoot: case DebugLogMode::SkipBoot:
return "2";
result = "2";
break;
default: default:
case DebugLogMode::Enabled: case DebugLogMode::Enabled:
return "1";
result = "1";
break;
} }
return result;
} }
DebugLogMode _debugLogModeDeserialize(const String& value) {
template<>
DebugLogMode convert(const String& value) {
switch (value.toInt()) { switch (value.toInt()) {
case 0: case 0:
return DebugLogMode::Disabled; return DebugLogMode::Disabled;
@ -306,13 +318,16 @@ DebugLogMode _debugLogModeDeserialize(const String& value) {
} }
} }
}
}
void debugConfigureBoot() { void debugConfigureBoot() {
static_assert( static_assert(
std::is_same<int, std::underlying_type<DebugLogMode>::type>::value, std::is_same<int, std::underlying_type<DebugLogMode>::type>::value,
"should be able to match DebugLogMode with int" "should be able to match DebugLogMode with int"
); );
const auto mode = getSetting<DebugLogMode, _debugLogModeDeserialize>("dbgLogMode", DEBUG_LOG_MODE);
const auto mode = getSetting("dbgLogMode", DEBUG_LOG_MODE);
switch (mode) { switch (mode) {
case DebugLogMode::SkipBoot: case DebugLogMode::SkipBoot:
schedule_function([]() { schedule_function([]() {


+ 1
- 1
code/espurna/influxdb.cpp View File

@ -210,7 +210,7 @@ void _idbFlush() {
if (!wifiConnected()) return; if (!wifiConnected()) return;
const auto host = getSetting("idbHost", INFLUXDB_HOST); const auto host = getSetting("idbHost", INFLUXDB_HOST);
const auto port = getSetting<uint16_t>("idbPort", INFLUXDB_PORT);
const auto port = getSetting("idbPort", static_cast<uint16_t>(INFLUXDB_PORT));
// TODO: should we always store specific pairs like tspk keeps relay / sensor readings? // TODO: should we always store specific pairs like tspk keeps relay / sensor readings?
// note that we also send heartbeat data, persistent values should be flagged // note that we also send heartbeat data, persistent values should be flagged


+ 1
- 1
code/espurna/main.cpp View File

@ -131,7 +131,7 @@ void setup() {
// Return bogus free heap value for broken devices // Return bogus free heap value for broken devices
// XXX: device is likely to trigger other bugs! tread carefuly // XXX: device is likely to trigger other bugs! tread carefuly
wtfHeap(getSetting<int>("wtfHeap", 0));
wtfHeap(getSetting("wtfHeap", 0));
// Init Serial, SPIFFS and system check // Init Serial, SPIFFS and system check
systemSetup(); systemSetup();


+ 1
- 1
code/espurna/mdns.cpp View File

@ -45,7 +45,7 @@ void _mdnsServerStart() {
void mdnsServerSetup() { void mdnsServerSetup() {
#if WEB_SUPPORT #if WEB_SUPPORT
MDNS.addService("http", "tcp", getSetting<uint16_t>("webPort", WEB_PORT));
MDNS.addService("http", "tcp", getSetting("webPort", static_cast<uint16_t>(WEB_PORT)));
#endif #endif
#if TELNET_SUPPORT #if TELNET_SUPPORT


+ 2
- 2
code/espurna/mqtt.cpp View File

@ -127,7 +127,7 @@ SecureClientConfig _mqtt_sc_config {
return getSetting("mqttFP", MQTT_SSL_FINGERPRINT); return getSetting("mqttFP", MQTT_SSL_FINGERPRINT);
}, },
[]() -> uint16_t { []() -> uint16_t {
return getSetting<uint16_t>("mqttScMFLN", MQTT_SECURE_CLIENT_MFLN);
return getSetting("mqttScMFLN", MQTT_SECURE_CLIENT_MFLN);
}, },
true true
}; };
@ -258,7 +258,7 @@ void _mqttConfigure() {
// Enable only when server is set // Enable only when server is set
{ {
const String server = getSetting("mqttServer", MQTT_SERVER); const String server = getSetting("mqttServer", MQTT_SERVER);
const auto port = getSetting<uint16_t>("mqttPort", MQTT_PORT);
const auto port = getSetting("mqttPort", static_cast<uint16_t>(MQTT_PORT));
bool enabled = false; bool enabled = false;
if (server.length()) { if (server.length()) {
enabled = getSetting("mqttEnabled", 1 == MQTT_ENABLED); enabled = getSetting("mqttEnabled", 1 == MQTT_ENABLED);


+ 193
- 101
code/espurna/sensor.cpp View File

@ -201,7 +201,6 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
struct sensor_magnitude_t { struct sensor_magnitude_t {
private: private:
@ -215,17 +214,19 @@ struct sensor_magnitude_t {
} }
sensor_magnitude_t(); sensor_magnitude_t();
sensor_magnitude_t(unsigned char type, unsigned char local, sensor::Unit units, BaseSensor* sensor);
sensor_magnitude_t(unsigned char slot, unsigned char index_local, unsigned char type, sensor::Unit units, BaseSensor* sensor);
BaseSensor * sensor; // Sensor object BaseSensor * sensor; // Sensor object
BaseFilter * filter; // Filter object BaseFilter * filter; // Filter object
unsigned char type; // Type of measurement
unsigned char local; // Local index in its provider
unsigned char global; // Global index in its type
unsigned char decimals; // Number of decimals in textual representation
unsigned char slot; // Sensor slot # taken by the magnitude, used to access the measurement
unsigned char type; // Type of measurement, returned by the BaseSensor::type(slot)
unsigned char index_local; // N'th magnitude of it's type, local to the sensor
unsigned char index_global; // ... and across all of the active sensors
sensor::Unit units; // Units of measurement sensor::Unit units; // Units of measurement
unsigned char decimals; // Number of decimals in textual representation
double last; // Last raw value from sensor (unfiltered) double last; // Last raw value from sensor (unfiltered)
double reported; // Last reported value double reported; // Last reported value
@ -375,7 +376,7 @@ void _sensorApiResetEnergy(const sensor_magnitude_t& magnitude, const char* payl
auto* sensor = static_cast<BaseEmonSensor*>(magnitude.sensor); auto* sensor = static_cast<BaseEmonSensor*>(magnitude.sensor);
auto energy = _sensorParseEnergy(payload); auto energy = _sensorParseEnergy(payload);
sensor->resetEnergy(magnitude.global, energy);
sensor->resetEnergy(magnitude.index_global, energy);
} }
sensor::Energy _sensorEnergyTotal(unsigned char index) { sensor::Energy _sensorEnergyTotal(unsigned char index) {
@ -413,21 +414,21 @@ void _magnitudeSaveEnergyTotal(sensor_magnitude_t& magnitude, bool persistent) {
const auto energy = sensor->totalEnergy(); const auto energy = sensor->totalEnergy();
// Always save to RTCMEM // Always save to RTCMEM
if (magnitude.global < (sizeof(Rtcmem->energy) / sizeof(*Rtcmem->energy))) {
_sensorRtcmemSaveEnergy(magnitude.global, energy);
if (magnitude.index_global < (sizeof(Rtcmem->energy) / sizeof(*Rtcmem->energy))) {
_sensorRtcmemSaveEnergy(magnitude.index_global, energy);
} }
// Save to EEPROM every '_sensor_save_every' readings // Save to EEPROM every '_sensor_save_every' readings
// Format is `<kwh>+<ws>`, value without `+` is treated as `<ws>` // Format is `<kwh>+<ws>`, value without `+` is treated as `<ws>`
if (persistent && _sensor_save_every) { if (persistent && _sensor_save_every) {
_sensor_save_count[magnitude.global] =
(_sensor_save_count[magnitude.global] + 1) % _sensor_save_every;
_sensor_save_count[magnitude.index_global] =
(_sensor_save_count[magnitude.index_global] + 1) % _sensor_save_every;
if (0 == _sensor_save_count[magnitude.global]) {
if (0 == _sensor_save_count[magnitude.index_global]) {
const String total = String(energy.kwh.value) + "+" + String(energy.ws.value); const String total = String(energy.kwh.value) + "+" + String(energy.ws.value);
setSetting({"eneTotal", magnitude.global}, total);
setSetting({"eneTotal", magnitude.index_global}, total);
#if NTP_SUPPORT #if NTP_SUPPORT
if (ntpSynced()) setSetting({"eneTime", magnitude.global}, ntpDateTime());
if (ntpSynced()) setSetting({"eneTime", magnitude.index_global}, ntpDateTime());
#endif #endif
} }
} }
@ -450,11 +451,12 @@ unsigned char _sensor_report_every = SENSOR_REPORT_EVERY;
sensor_magnitude_t::sensor_magnitude_t() : sensor_magnitude_t::sensor_magnitude_t() :
sensor(nullptr), sensor(nullptr),
filter(nullptr), filter(nullptr),
slot(0),
type(0), type(0),
local(0),
global(0),
decimals(0),
index_local(0),
index_global(0),
units(sensor::Unit::None), units(sensor::Unit::None),
decimals(0),
last(0.0), last(0.0),
reported(0.0), reported(0.0),
min_change(0.0), min_change(0.0),
@ -462,14 +464,15 @@ sensor_magnitude_t::sensor_magnitude_t() :
correction(0.0) correction(0.0)
{} {}
sensor_magnitude_t::sensor_magnitude_t(unsigned char type, unsigned char local, sensor::Unit units, BaseSensor* sensor) :
sensor_magnitude_t::sensor_magnitude_t(unsigned char slot, unsigned char index_local, unsigned char type, sensor::Unit units, BaseSensor* sensor) :
sensor(sensor), sensor(sensor),
filter(nullptr), filter(nullptr),
slot(slot),
type(type), type(type),
local(local),
global(_counts[type]),
decimals(0),
index_local(index_local),
index_global(_counts[type]),
units(units), units(units),
decimals(0),
last(0.0), last(0.0),
reported(0.0), reported(0.0),
min_change(0.0), min_change(0.0),
@ -784,7 +787,7 @@ sensor::Unit _magnitudeUnitFilter(const sensor_magnitude_t& magnitude, sensor::U
double _magnitudeProcess(const sensor_magnitude_t& magnitude, double value) { double _magnitudeProcess(const sensor_magnitude_t& magnitude, double value) {
// Process input (sensor) units and convert to the ones that magnitude specifies as output // Process input (sensor) units and convert to the ones that magnitude specifies as output
switch (magnitude.sensor->units(magnitude.local)) {
switch (magnitude.sensor->units(magnitude.slot)) {
case sensor::Unit::Celcius: case sensor::Unit::Celcius:
if (magnitude.units == sensor::Unit::Farenheit) { if (magnitude.units == sensor::Unit::Farenheit) {
value = (value * 1.8) + 32.0; value = (value * 1.8) + 32.0;
@ -822,8 +825,84 @@ double _magnitudeProcess(const sensor_magnitude_t& magnitude, double value) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool _sensorMatchKeyPrefix(const char * key) {
if (strncmp(key, "pwr", 3) == 0) return true;
if (strncmp(key, "sns", 3) == 0) return true;
if (strncmp(key, "tmp", 3) == 0) return true;
if (strncmp(key, "hum", 3) == 0) return true;
if (strncmp(key, "ene", 3) == 0) return true;
if (strncmp(key, "lux", 3) == 0) return true;
return false;
}
const String _sensorQueryDefault(const String& key) {
auto get_defaults = [](unsigned char type, BaseSensor* ptr) -> String {
if (!ptr) return String();
auto* sensor = static_cast<BaseEmonSensor*>(ptr);
switch (type) {
case MAGNITUDE_CURRENT:
return String(sensor->defaultCurrentRatio());
case MAGNITUDE_VOLTAGE:
return String(sensor->defaultVoltageRatio());
case MAGNITUDE_POWER_ACTIVE:
return String(sensor->defaultPowerRatio());
case MAGNITUDE_ENERGY:
return String(sensor->defaultEnergyRatio());
default:
return String();
}
};
auto magnitude_key = [](const sensor_magnitude_t& magnitude) -> settings_key_t {
switch (magnitude.type) {
case MAGNITUDE_CURRENT:
return {"pwrRatioC", magnitude.index_global};
case MAGNITUDE_VOLTAGE:
return {"pwrRatioV", magnitude.index_global};
case MAGNITUDE_POWER_ACTIVE:
return {"pwrRatioP", magnitude.index_global};
case MAGNITUDE_ENERGY:
return {"pwrRatioE", magnitude.index_global};
default:
return {};
}
};
unsigned char type = MAGNITUDE_NONE;
BaseSensor* target = nullptr;
for (auto& magnitude : _magnitudes) {
switch (magnitude.type) {
case MAGNITUDE_CURRENT:
case MAGNITUDE_VOLTAGE:
case MAGNITUDE_POWER_ACTIVE:
case MAGNITUDE_ENERGY: {
auto ratioKey(magnitude_key(magnitude));
if (ratioKey.match(key)) {
target = magnitude.sensor;
type = magnitude.type;
goto return_defaults;
}
break;
}
default:
break;
}
}
return_defaults:
return get_defaults(type, target);
}
#if WEB_SUPPORT #if WEB_SUPPORT
bool _sensorWebSocketOnKeyCheck(const char* key, JsonVariant&) {
return _sensorMatchKeyPrefix(key);
}
// Used by modules to generate magnitude_id<->module_id mapping for the WebUI // Used by modules to generate magnitude_id<->module_id mapping for the WebUI
void sensorWebSocketMagnitudes(JsonObject& root, const String& prefix) { void sensorWebSocketMagnitudes(JsonObject& root, const String& prefix) {
@ -848,16 +927,6 @@ void sensorWebSocketMagnitudes(JsonObject& root, const String& prefix) {
} }
} }
bool _sensorWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
if (strncmp(key, "pwr", 3) == 0) return true;
if (strncmp(key, "sns", 3) == 0) return true;
if (strncmp(key, "tmp", 3) == 0) return true;
if (strncmp(key, "hum", 3) == 0) return true;
if (strncmp(key, "ene", 3) == 0) return true;
if (strncmp(key, "lux", 3) == 0) return true;
return false;
}
void _sensorWebSocketOnVisible(JsonObject& root) { void _sensorWebSocketOnVisible(JsonObject& root) {
root["snsVisible"] = 1; root["snsVisible"] = 1;
@ -888,14 +957,11 @@ void _sensorWebSocketMagnitudesConfig(JsonObject& root) {
if (magnitude.type == MAGNITUDE_EVENT) continue; if (magnitude.type == MAGNITUDE_EVENT) continue;
++size; ++size;
index.add<uint8_t>(magnitude.global);
// Note: we use int instead of bool to ever so slightly compress json output
index.add<uint8_t>(magnitude.index_global);
type.add<uint8_t>(magnitude.type); type.add<uint8_t>(magnitude.type);
units.add(_magnitudeUnits(magnitude)); units.add(_magnitudeUnits(magnitude));
{
String sensor_desc = magnitude.sensor->slot(magnitude.local);
description.add(sensor_desc);
}
description.add(magnitude.sensor->description(magnitude.slot));
} }
@ -928,7 +994,7 @@ void _sensorWebSocketSendData(JsonObject& root) {
#if NTP_SUPPORT #if NTP_SUPPORT
if ((_sensor_save_every > 0) && (magnitude.type == MAGNITUDE_ENERGY)) { if ((_sensor_save_every > 0) && (magnitude.type == MAGNITUDE_ENERGY)) {
String string = F("Last saved: "); String string = F("Last saved: ");
string += getSetting({"eneTime", magnitude.global}, F("(unknown)"));
string += getSetting({"eneTime", magnitude.index_global}, F("(unknown)"));
info.add(string); info.add(string);
} else { } else {
info.add((uint8_t)0); info.add((uint8_t)0);
@ -1029,7 +1095,7 @@ void _sensorAPISetup() {
auto& magnitude = _magnitudes.at(magnitude_id); auto& magnitude = _magnitudes.at(magnitude_id);
String topic = magnitudeTopic(magnitude.type); String topic = magnitudeTopic(magnitude.type);
if (SENSOR_USE_INDEX || (sensor_magnitude_t::counts(magnitude.type) > 1)) topic = topic + "/" + String(magnitude.global);
if (SENSOR_USE_INDEX || (sensor_magnitude_t::counts(magnitude.type) > 1)) topic = topic + "/" + String(magnitude.index_global);
api_get_callback_f get_cb = [&magnitude](char * buffer, size_t len) { api_get_callback_f get_cb = [&magnitude](char * buffer, size_t len) {
double value = _sensor_realtime ? magnitude.last : magnitude.reported; double value = _sensor_realtime ? magnitude.last : magnitude.reported;
@ -1065,7 +1131,7 @@ void _sensorMqttCallback(unsigned int type, const char* topic, char* payload) {
for (auto& magnitude : _magnitudes) { for (auto& magnitude : _magnitudes) {
if (MAGNITUDE_ENERGY != magnitude.type) continue; if (MAGNITUDE_ENERGY != magnitude.type) continue;
if (index != magnitude.global) continue;
if (index != magnitude.index_global) continue;
_sensorApiResetEnergy(magnitude, payload); _sensorApiResetEnergy(magnitude, payload);
break; break;
} }
@ -1099,8 +1165,8 @@ void _sensorInitCommands() {
dtostrf(magnitude.reported, 1, magnitude.decimals, reported); dtostrf(magnitude.reported, 1, magnitude.decimals, reported);
DEBUG_MSG_P(PSTR("[SENSOR] %2u * %s/%u @ %s (last:%s, reported:%s)\n"), DEBUG_MSG_P(PSTR("[SENSOR] %2u * %s/%u @ %s (last:%s, reported:%s)\n"),
index, index,
magnitudeTopic(magnitude.type).c_str(), magnitude.global,
magnitude.sensor->slot(magnitude.local).c_str(),
magnitudeTopic(magnitude.type).c_str(), magnitude.index_global,
magnitude.sensor->description(magnitude.slot).c_str(),
last, reported last, reported
); );
} }
@ -1207,7 +1273,7 @@ void _sensorLoad() {
#if BMX280_SUPPORT #if BMX280_SUPPORT
{ {
// Support up to two sensors with full auto-discovery. // Support up to two sensors with full auto-discovery.
const unsigned char number = constrain(getSetting<int>("bmx280Number", BMX280_NUMBER), 1, 2);
const unsigned char number = constrain(getSetting("bmx280Number", BMX280_NUMBER), 1, 2);
// For second sensor, if BMX280_ADDRESS is 0x00 then auto-discover // For second sensor, if BMX280_ADDRESS is 0x00 then auto-discover
// otherwise choose the other unnamed sensor address // otherwise choose the other unnamed sensor address
@ -1742,7 +1808,7 @@ void _sensorReport(unsigned char index, double value) {
dtostrf(value, 1, magnitude.decimals, buffer); dtostrf(value, 1, magnitude.decimals, buffer);
#if BROKER_SUPPORT #if BROKER_SUPPORT
SensorReportBroker::Publish(magnitudeTopic(magnitude.type), magnitude.global, value, buffer);
SensorReportBroker::Publish(magnitudeTopic(magnitude.type), magnitude.index_global, value, buffer);
#endif #endif
#if MQTT_SUPPORT #if MQTT_SUPPORT
@ -1753,9 +1819,9 @@ void _sensorReport(unsigned char index, double value) {
char topic[32]; char topic[32];
snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, magnitudeTopic(magnitude.type).c_str()); snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, magnitudeTopic(magnitude.type).c_str());
if (SENSOR_USE_INDEX || (sensor_magnitude_t::counts(magnitude.type) > 1)) { if (SENSOR_USE_INDEX || (sensor_magnitude_t::counts(magnitude.type) > 1)) {
mqttSend(topic, magnitude.global, magnitude.sensor->address(magnitude.local).c_str());
mqttSend(topic, magnitude.index_global, magnitude.sensor->address(magnitude.slot).c_str());
} else { } else {
mqttSend(topic, magnitude.sensor->address(magnitude.local).c_str());
mqttSend(topic, magnitude.sensor->address(magnitude.slot).c_str());
} }
#endif // SENSOR_PUBLISH_ADDRESSES #endif // SENSOR_PUBLISH_ADDRESSES
@ -1788,7 +1854,6 @@ void _sensorCallback(unsigned char i, unsigned char type, double value) {
void _sensorInit() { void _sensorInit() {
_sensors_ready = true; _sensors_ready = true;
_sensor_save_every = 0;
for (unsigned char i=0; i<_sensors.size(); i++) { for (unsigned char i=0; i<_sensors.size(); i++) {
@ -1808,14 +1873,19 @@ void _sensorInit() {
for (unsigned char magnitude_index = 0; magnitude_index < _sensors[i]->count(); ++magnitude_index) { for (unsigned char magnitude_index = 0; magnitude_index < _sensors[i]->count(); ++magnitude_index) {
const auto magnitude_type = _sensors[i]->type(magnitude_index); const auto magnitude_type = _sensors[i]->type(magnitude_index);
const auto magnitude_local = _sensors[i]->local(magnitude_type);
_magnitudes.emplace_back( _magnitudes.emplace_back(
magnitude_type, // specific type of the magnitude
magnitude_index, // index local to the sensor
sensor::Unit::None, // set up later, in configuration
_sensors[i] // bind the sensor to allow us to reference it later
magnitude_index, // id of the magnitude, unique to the sensor
magnitude_local, // index_local, # of the magnitude
magnitude_type, // specific type of the magnitude
sensor::Unit::None, // set up later, in configuration
_sensors[i] // bind the sensor to allow us to reference it later
); );
if (MAGNITUDE_ENERGY == magnitude_type) {
if (_sensorIsEmon(_sensors[i]) && (MAGNITUDE_ENERGY == magnitude_type)) {
const auto index_global = _magnitudes.back().index_global;
auto* sensor = static_cast<BaseEmonSensor*>(_sensors[i]);
sensor->resetEnergy(magnitude_local, _sensorEnergyTotal(index_global));
_sensor_save_count.push_back(0); _sensor_save_count.push_back(0);
} }
@ -1846,36 +1916,6 @@ void _sensorInit() {
break; break;
} }
// TODO: compatibility proxy, fetch global key before indexed
auto get_ratio = [](const char* key, unsigned char index, double default_value) -> double {
return getSetting({key, index}, getSetting(key, default_value));
};
if (_sensorIsEmon(_sensors[i])) {
auto* sensor = static_cast<BaseEmonSensor*>(_sensors[i]);
for (size_t index = 0; index < sensor->countDevices(); ++index) {
sensor->resetEnergy(index, _sensorEnergyTotal(index));
sensor->setCurrentRatio(
index, get_ratio("pwrRatioC", index, sensor->getCurrentRatio(index))
);
sensor->setVoltageRatio(
index, get_ratio("pwrRatioV", index, sensor->getVoltageRatio(index))
);
sensor->setPowerRatio(
index, get_ratio("pwrRatioP", index, sensor->getPowerRatio(index))
);
sensor->setEnergyRatio(
index, get_ratio("pwrRatioE", index, sensor->getEnergyRatio(index))
);
sensor->setVoltage(
index, get_ratio("pwrVoltage", index, sensor->getVoltage(index))
);
}
}
} }
} }
@ -1893,6 +1933,11 @@ sensor::Unit convert(const String& string) {
return sensor::Unit::None; return sensor::Unit::None;
} }
template <>
String serialize(const sensor::Unit& unit) {
return String(static_cast<int>(unit));
}
} // ns settings::internal } // ns settings::internal
} // ns settings } // ns settings
@ -1913,7 +1958,7 @@ void _sensorConfigure() {
const auto hum_min_delta = getSetting("humMinDelta", HUMIDITY_MIN_CHANGE); const auto hum_min_delta = getSetting("humMinDelta", HUMIDITY_MIN_CHANGE);
const auto ene_max_delta = getSetting("eneMaxDelta", ENERGY_MAX_CHANGE); const auto ene_max_delta = getSetting("eneMaxDelta", ENERGY_MAX_CHANGE);
// Specific sensor settings
// Apply settings based on sensor type
for (unsigned char index = 0; index < _sensors.size(); ++index) { for (unsigned char index = 0; index < _sensors.size(); ++index) {
#if MICS2710_SUPPORT || MICS5525_SUPPORT #if MICS2710_SUPPORT || MICS5525_SUPPORT
@ -1974,8 +2019,6 @@ void _sensorConfigure() {
sensor->resetRatios(); sensor->resetRatios();
} }
sensor->setEnergyRatio(getSetting("pwrRatioE", sensor->getEnergyRatio()));
} // is emon? } // is emon?
} }
@ -1997,34 +2040,73 @@ void _sensorConfigure() {
auto& magnitude = _magnitudes.at(index); auto& magnitude = _magnitudes.at(index);
// process emon-specific settings first. ensure that settings use global index and we access sensor with the local one
if (_sensorIsEmon(magnitude.sensor)) {
// TODO: compatibility proxy, fetch global key before indexed
auto get_ratio = [](const char* key, unsigned char index, double default_value) -> double {
return getSetting({key, index}, getSetting(key, default_value));
};
auto* sensor = static_cast<BaseEmonSensor*>(magnitude.sensor);
switch (magnitude.type) {
case MAGNITUDE_CURRENT:
sensor->setCurrentRatio(
magnitude.index_local, get_ratio("pwrRatioC", magnitude.index_global, sensor->defaultCurrentRatio())
);
break;
case MAGNITUDE_POWER_ACTIVE:
sensor->setPowerRatio(
magnitude.index_local, get_ratio("pwrRatioP", magnitude.index_global, sensor->defaultPowerRatio())
);
break;
case MAGNITUDE_VOLTAGE:
sensor->setVoltageRatio(
magnitude.index_local, get_ratio("pwrRatioV", magnitude.index_global, sensor->defaultVoltageRatio())
);
sensor->setVoltage(
magnitude.index_local, get_ratio("pwrVoltage", magnitude.index_global, sensor->defaultVoltage())
);
break;
case MAGNITUDE_ENERGY:
sensor->setEnergyRatio(
magnitude.index_local, get_ratio("pwrRatioE", magnitude.index_global, sensor->defaultEnergyRatio())
);
break;
default:
break;
}
}
// adjust type-specific units (TODO: try to adjust settings to use type prefixes?)
switch (magnitude.type) { switch (magnitude.type) {
case MAGNITUDE_TEMPERATURE: case MAGNITUDE_TEMPERATURE:
magnitude.units = _magnitudeUnitFilter( magnitude.units = _magnitudeUnitFilter(
magnitude, magnitude,
getSetting({"tmpUnits", magnitude.global}, tmpUnits)
getSetting({"tmpUnits", magnitude.index_global}, tmpUnits)
); );
magnitude.correction = getSetting({"tmpCorrection", magnitude.global}, tmpCorrection);
magnitude.correction = getSetting({"tmpCorrection", magnitude.index_global}, tmpCorrection);
break; break;
case MAGNITUDE_HUMIDITY: case MAGNITUDE_HUMIDITY:
magnitude.correction = getSetting({"humCorrection", magnitude.global}, humCorrection);
magnitude.correction = getSetting({"humCorrection", magnitude.index_global}, humCorrection);
break; break;
case MAGNITUDE_POWER_ACTIVE: case MAGNITUDE_POWER_ACTIVE:
magnitude.units = _magnitudeUnitFilter( magnitude.units = _magnitudeUnitFilter(
magnitude, magnitude,
getSetting({"pwrUnits", magnitude.global}, pwrUnits)
getSetting({"pwrUnits", magnitude.index_global}, pwrUnits)
); );
break; break;
case MAGNITUDE_ENERGY: case MAGNITUDE_ENERGY:
magnitude.units = _magnitudeUnitFilter( magnitude.units = _magnitudeUnitFilter(
magnitude, magnitude,
getSetting({"eneUnits", magnitude.global}, eneUnits)
getSetting({"eneUnits", magnitude.index_global}, eneUnits)
); );
break; break;
case MAGNITUDE_LUX: case MAGNITUDE_LUX:
magnitude.correction = getSetting({"luxCorrection", magnitude.global}, luxCorrection);
magnitude.correction = getSetting({"luxCorrection", magnitude.index_global}, luxCorrection);
break; break;
default: default:
magnitude.units = magnitude.sensor->units(magnitude.local);
magnitude.units = magnitude.sensor->units(magnitude.slot);
break; break;
} }
@ -2037,6 +2119,7 @@ void _sensorConfigure() {
// adjust min & max change delta value to trigger report // adjust min & max change delta value to trigger report
// TODO: find a proper way to extend this to min/max of any magnitude // TODO: find a proper way to extend this to min/max of any magnitude
// TODO: we can't use index_global b/c we don't specify type in the setting
{ {
auto min_default = 0.0; auto min_default = 0.0;
auto max_default = 0.0; auto max_default = 0.0;
@ -2061,7 +2144,7 @@ void _sensorConfigure() {
// in case we don't save energy periodically, purge existing value in ram & settings // in case we don't save energy periodically, purge existing value in ram & settings
if ((MAGNITUDE_ENERGY == magnitude.type) && (0 == _sensor_save_every)) { if ((MAGNITUDE_ENERGY == magnitude.type) && (0 == _sensor_save_every)) {
_sensorResetEnergyTotal(magnitude.global);
_sensorResetEnergyTotal(magnitude.index_global);
} }
} }
@ -2086,7 +2169,7 @@ unsigned char magnitudeCount() {
String magnitudeName(unsigned char index) { String magnitudeName(unsigned char index) {
if (index < _magnitudes.size()) { if (index < _magnitudes.size()) {
sensor_magnitude_t magnitude = _magnitudes[index]; sensor_magnitude_t magnitude = _magnitudes[index];
return magnitude.sensor->slot(magnitude.local);
return magnitude.sensor->description(magnitude.slot);
} }
return String(); return String();
} }
@ -2107,7 +2190,7 @@ double magnitudeValue(unsigned char index) {
unsigned char magnitudeIndex(unsigned char index) { unsigned char magnitudeIndex(unsigned char index) {
if (index < _magnitudes.size()) { if (index < _magnitudes.size()) {
return int(_magnitudes[index].global);
return int(_magnitudes[index].index_global);
} }
return 0; return 0;
} }
@ -2117,7 +2200,7 @@ String magnitudeTopicIndex(unsigned char index) {
if (index < _magnitudes.size()) { if (index < _magnitudes.size()) {
sensor_magnitude_t magnitude = _magnitudes[index]; sensor_magnitude_t magnitude = _magnitudes[index];
if (SENSOR_USE_INDEX || (sensor_magnitude_t::counts(magnitude.type) > 1)) { if (SENSOR_USE_INDEX || (sensor_magnitude_t::counts(magnitude.type) > 1)) {
snprintf(topic, sizeof(topic), "%s/%u", magnitudeTopic(magnitude.type).c_str(), magnitude.global);
snprintf(topic, sizeof(topic), "%s/%u", magnitudeTopic(magnitude.type).c_str(), magnitude.index_global);
} else { } else {
snprintf(topic, sizeof(topic), "%s", magnitudeTopic(magnitude.type).c_str()); snprintf(topic, sizeof(topic), "%s", magnitudeTopic(magnitude.type).c_str());
} }
@ -2133,7 +2216,7 @@ void _sensorBackwards() {
moveSetting("powerUnits", "pwrUnits"); moveSetting("powerUnits", "pwrUnits");
moveSetting("energyUnits", "eneUnits"); moveSetting("energyUnits", "eneUnits");
// Energy is now indexed (based on magnitude.global)
// Energy is now indexed (based on magnitude.index_global)
moveSetting("eneTotal", "eneTotal0"); moveSetting("eneTotal", "eneTotal0");
// Update PZEM004T energy total across multiple devices // Update PZEM004T energy total across multiple devices
@ -2165,6 +2248,15 @@ void sensorSetup() {
// Configure based on settings // Configure based on settings
_sensorConfigure(); _sensorConfigure();
// Allow us to query key default
settingsRegisterDefaults({
[](const char* key) -> bool {
if (strncmp(key, "pwr", 3) == 0) return true;
return false;
},
_sensorQueryDefault
});
// Websockets integration, send sensor readings and configuration // Websockets integration, send sensor readings and configuration
#if WEB_SUPPORT #if WEB_SUPPORT
wsRegister() wsRegister()
@ -2242,7 +2334,7 @@ void sensorLoop() {
// Instant value // Instant value
// ------------------------------------------------------------- // -------------------------------------------------------------
value_raw = magnitude.sensor->value(magnitude.local);
value_raw = magnitude.sensor->value(magnitude.slot);
// Completely remove spurious values if relay is OFF // Completely remove spurious values if relay is OFF
#if RELAY_SUPPORT && SENSOR_POWER_CHECK_STATUS #if RELAY_SUPPORT && SENSOR_POWER_CHECK_STATUS
@ -2290,7 +2382,7 @@ void sensorLoop() {
{ {
char buffer[64]; char buffer[64];
dtostrf(value_show, 1, magnitude.decimals, buffer); dtostrf(value_show, 1, magnitude.decimals, buffer);
SensorReadBroker::Publish(magnitudeTopic(magnitude.type), magnitude.global, value_show, buffer);
SensorReadBroker::Publish(magnitudeTopic(magnitude.type), magnitude.index_global, value_show, buffer);
} }
#endif #endif
@ -2303,7 +2395,7 @@ void sensorLoop() {
char buffer[64]; char buffer[64];
dtostrf(value_show, 1, magnitude.decimals, buffer); dtostrf(value_show, 1, magnitude.decimals, buffer);
DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"), DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"),
magnitude.sensor->slot(magnitude.local).c_str(),
magnitude.sensor->description(magnitude.slot).c_str(),
magnitudeTopic(magnitude.type).c_str(), magnitudeTopic(magnitude.type).c_str(),
buffer, buffer,
_magnitudeUnits(magnitude).c_str() _magnitudeUnits(magnitude).c_str()


+ 7
- 2
code/espurna/sensors/ADE7953Sensor.h View File

@ -75,11 +75,10 @@ class ADE7953Sensor : public I2CSensor<BaseEmonSensor> {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };
// Pre-read hook (usually to populate registers with up-to-date data) // Pre-read hook (usually to populate registers with up-to-date data)
void pre() { void pre() {
uint32_t active_power1 = 0; uint32_t active_power1 = 0;
@ -150,6 +149,12 @@ class ADE7953Sensor : public I2CSensor<BaseEmonSensor> {
return 0; return 0;
} }
// Convert slot # to a magnitude #
unsigned char local(unsigned char index) override {
if (index == 0) { return 0; } // common voltage
return (index - 1) / countDevices(); // device { energy, current, active power }
}
// Type for slot # index // Type for slot # index
unsigned char type(unsigned char index) { unsigned char type(unsigned char index) {
if (index == 0) return MAGNITUDE_VOLTAGE; if (index == 0) return MAGNITUDE_VOLTAGE;


+ 1
- 1
code/espurna/sensors/AM2320Sensor.h View File

@ -65,7 +65,7 @@ class AM2320Sensor : public I2CSensor<> {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/AnalogSensor.h View File

@ -78,7 +78,7 @@ class AnalogSensor : public BaseAnalogSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 34
- 6
code/espurna/sensors/BaseEmonSensor.h View File

@ -67,6 +67,10 @@ class BaseEmonSensor : public BaseSensor {
} }
// --- configuration --- // --- configuration ---
virtual double defaultVoltage() {
return 0.0;
}
// when sensor needs explicit mains voltage value // when sensor needs explicit mains voltage value
virtual void setVoltage(double) {} virtual void setVoltage(double) {}
@ -74,7 +78,7 @@ class BaseEmonSensor : public BaseSensor {
setVoltage(value); setVoltage(value);
} }
virtual double getVoltage() { virtual double getVoltage() {
return 0.0;
return defaultVoltage();
} }
virtual double getVoltage(unsigned char index) { virtual double getVoltage(unsigned char index) {
return getVoltage(); return getVoltage();
@ -100,18 +104,33 @@ class BaseEmonSensor : public BaseSensor {
setEnergyRatio(value); setEnergyRatio(value);
} }
// Generic ratio configuration, default is a
// no-op and must be implemented by the sensor class
virtual double defaultCurrentRatio() const {
return 0.0;
}
virtual double defaultVoltageRatio() const {
return 0.0;
}
virtual double defaultPowerRatio() const {
return 0.0;
}
virtual double defaultEnergyRatio() const {
return 0.0;
}
// when sensor implements a single device // when sensor implements a single device
virtual double getCurrentRatio() { virtual double getCurrentRatio() {
return 0.0;
return defaultCurrentRatio();
} }
virtual double getVoltageRatio() { virtual double getVoltageRatio() {
return 0.0;
return defaultVoltageRatio();
} }
virtual double getPowerRatio() { virtual double getPowerRatio() {
return 0.0;
return defaultPowerRatio();
} }
virtual double getEnergyRatio() { virtual double getEnergyRatio() {
return 0.0;
return defaultEnergyRatio();
} }
// when sensor implements more than one device // when sensor implements more than one device
@ -132,7 +151,16 @@ class BaseEmonSensor : public BaseSensor {
virtual void expectedVoltage(unsigned int value) {} virtual void expectedVoltage(unsigned int value) {}
virtual void expectedPower(unsigned int value) {} virtual void expectedPower(unsigned int value) {}
virtual void resetCalibration(double value) {}
virtual void expectedCurrent(unsigned char index, double value) {
expectedCurrent(value);
}
virtual void expectedVoltage(unsigned char index, unsigned int value) {
expectedVoltage(value);
}
virtual void expectedPower(unsigned char index, unsigned int value) {
expectedPower(value);
}
virtual void resetRatios() {} virtual void resetRatios() {}
protected: protected:


+ 6
- 3
code/espurna/sensors/BaseSensor.h View File

@ -39,12 +39,12 @@ class BaseSensor {
// Descriptive name of the sensor // Descriptive name of the sensor
virtual String description() = 0; virtual String description() = 0;
// Descriptive name of the slot # index
virtual String description(unsigned char index) = 0;
// Address of the sensor (it could be the GPIO or I2C address) // Address of the sensor (it could be the GPIO or I2C address)
virtual String address(unsigned char index) = 0; virtual String address(unsigned char index) = 0;
// Descriptive name of the slot # index
virtual String slot(unsigned char index) = 0;
// Type of sensor // Type of sensor
virtual unsigned char type() { return sensor::type::Base; } virtual unsigned char type() { return sensor::type::Base; }
@ -84,6 +84,9 @@ class BaseSensor {
// Number of available slots // Number of available slots
unsigned char count() { return _count; } unsigned char count() { return _count; }
// Convert slot # index to a magnitude # index
virtual unsigned char local(unsigned char slot) { return 0; }
// Hook for event callback // Hook for event callback
void onEvent(TSensorCallback fn) { _callback = fn; }; void onEvent(TSensorCallback fn) { _callback = fn; };


+ 31
- 15
code/espurna/sensors/CSE7766Sensor.h View File

@ -59,50 +59,64 @@ class CSE7766Sensor : public BaseEmonSensor {
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
void expectedCurrent(double expected) {
void expectedCurrent(double expected) override {
if ((expected > 0) && (_current > 0)) { if ((expected > 0) && (_current > 0)) {
_ratioC = _ratioC * (expected / _current); _ratioC = _ratioC * (expected / _current);
} }
} }
void expectedVoltage(unsigned int expected) {
void expectedVoltage(unsigned int expected) override {
if ((expected > 0) && (_voltage > 0)) { if ((expected > 0) && (_voltage > 0)) {
_ratioV = _ratioV * (expected / _voltage); _ratioV = _ratioV * (expected / _voltage);
} }
} }
void expectedPower(unsigned int expected) {
void expectedPower(unsigned int expected) override {
if ((expected > 0) && (_active > 0)) { if ((expected > 0) && (_active > 0)) {
_ratioP = _ratioP * (expected / _active); _ratioP = _ratioP * (expected / _active);
} }
} }
void setCurrentRatio(double value) {
double defaultCurrentRatio() const override {
return 1.0;
}
double defaultVoltageRatio() const override {
return 1.0;
}
double defaultPowerRatio() const override {
return 1.0;
}
void setCurrentRatio(double value) override {
_ratioC = value; _ratioC = value;
}; };
void setVoltageRatio(double value) {
void setVoltageRatio(double value) override {
_ratioV = value; _ratioV = value;
}; };
void setPowerRatio(double value) {
void setPowerRatio(double value) override {
_ratioP = value; _ratioP = value;
}; };
double getCurrentRatio() {
double getCurrentRatio() override {
return _ratioC; return _ratioC;
}; };
double getVoltageRatio() {
double getVoltageRatio() override {
return _ratioV; return _ratioV;
}; };
double getPowerRatio() {
double getPowerRatio() override {
return _ratioP; return _ratioP;
}; };
void resetCalibration() {
_ratioC = _ratioV = _ratioP = 1.0;
void resetRatios() override {
_ratioC = defaultCurrentRatio();
_ratioV = defaultVoltageRatio();
_ratioP = defaultPowerRatio();
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -112,6 +126,8 @@ class CSE7766Sensor : public BaseEmonSensor {
// Initialization method, must be idempotent // Initialization method, must be idempotent
void begin() { void begin() {
resetRatios();
if (!_dirty) return; if (!_dirty) return;
if (_serial) delete _serial; if (_serial) delete _serial;
@ -141,7 +157,7 @@ class CSE7766Sensor : public BaseEmonSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };
@ -387,9 +403,9 @@ class CSE7766Sensor : public BaseEmonSensor {
double _voltage = 0; double _voltage = 0;
double _current = 0; double _current = 0;
double _ratioV = 1.0;
double _ratioC = 1.0;
double _ratioP = 1.0;
double _ratioV;
double _ratioC;
double _ratioP;
unsigned char _data[24]; unsigned char _data[24];


+ 1
- 1
code/espurna/sensors/DHTSensor.h View File

@ -132,7 +132,7 @@ class DHTSensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/DallasSensor.h View File

@ -239,7 +239,7 @@ class DallasSensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
if (index < _count) { if (index < _count) {
char buffer[40]; char buffer[40];
uint8_t * address = _devices[index].address; uint8_t * address = _devices[index].address;


+ 1
- 1
code/espurna/sensors/DigitalSensor.h View File

@ -70,7 +70,7 @@ class DigitalSensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/ECH1560Sensor.h View File

@ -94,7 +94,7 @@ class ECH1560Sensor : public BaseEmonSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/EZOPHSensor.h View File

@ -81,7 +81,7 @@ class EZOPHSensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/EmonADC121Sensor.h View File

@ -119,7 +119,7 @@ class EmonADC121Sensor : public EmonSensor {
// Current value for slot # index // Current value for slot # index
double value(unsigned char index) { double value(unsigned char index) {
unsigned char channel = index / _magnitudes;
unsigned char channel = local(index);
unsigned char i=0; unsigned char i=0;
#if EMON_REPORT_CURRENT #if EMON_REPORT_CURRENT
if (index == i++) return _current[channel]; if (index == i++) return _current[channel];


+ 6
- 1
code/espurna/sensors/EmonADS1X15Sensor.h View File

@ -146,6 +146,11 @@ class EmonADS1X15Sensor : public EmonSensor {
// Sensor API // Sensor API
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Convert slot # index to a magnitude # index
unsigned char local(unsigned char index) override {
return (_ports) ? (index / _ports) : 0u;
}
// Initialization method, must be idempotent // Initialization method, must be idempotent
void begin() { void begin() {
@ -194,7 +199,7 @@ class EmonADS1X15Sensor : public EmonSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
char buffer[35]; char buffer[35];
unsigned char channel = getChannel(index % _ports); unsigned char channel = getChannel(index % _ports);
snprintf(buffer, sizeof(buffer), "EMON @ ADS1%d15 (A%d) @ I2C (0x%02X)", _type == ADS1X15_CHIP_ADS1015 ? 0 : 1, channel, _address); snprintf(buffer, sizeof(buffer), "EMON @ ADS1%d15 (A%d) @ I2C (0x%02X)", _type == ADS1X15_CHIP_ADS1015 ? 0 : 1, channel, _address);


+ 21
- 10
code/espurna/sensors/EmonSensor.h View File

@ -41,7 +41,9 @@ class EmonSensor : public I2CSensor<BaseEmonSensor> {
} }
void expectedPower(unsigned char channel, unsigned int expected) {
// ---------------------------------------------------------------------
void expectedPower(unsigned char channel, unsigned int expected) override {
if (channel >= _channels) return; if (channel >= _channels) return;
unsigned int actual = _current[channel] * _voltage; unsigned int actual = _current[channel] * _voltage;
if (actual == 0) return; if (actual == 0) return;
@ -51,9 +53,7 @@ class EmonSensor : public I2CSensor<BaseEmonSensor> {
_dirty = true; _dirty = true;
} }
// ---------------------------------------------------------------------
void setVoltage(double voltage) {
void setVoltage(double voltage) override {
if (_voltage == voltage) return; if (_voltage == voltage) return;
_voltage = voltage; _voltage = voltage;
_dirty = true; _dirty = true;
@ -65,7 +65,11 @@ class EmonSensor : public I2CSensor<BaseEmonSensor> {
_dirty = true; _dirty = true;
} }
void setCurrentRatio(unsigned char channel, double current_ratio) {
double defaultCurrentRatio() const override {
return EMON_CURRENT_RATIO;
}
void setCurrentRatio(unsigned char channel, double current_ratio) override {
if (channel >= _channels) return; if (channel >= _channels) return;
if (_current_ratio[channel] == current_ratio) return; if (_current_ratio[channel] == current_ratio) return;
_current_ratio[channel] = current_ratio; _current_ratio[channel] = current_ratio;
@ -73,13 +77,15 @@ class EmonSensor : public I2CSensor<BaseEmonSensor> {
_dirty = true; _dirty = true;
} }
void resetRatios() {
setCurrentRatio(0, EMON_CURRENT_RATIO);
void resetRatios() override {
for (unsigned char channel = 0; channel < _channels; ++channel) {
setCurrentRatio(channel, defaultCurrentRatio());
}
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
double getVoltage() {
double getVoltage() override {
return _voltage; return _voltage;
} }
@ -87,12 +93,12 @@ class EmonSensor : public I2CSensor<BaseEmonSensor> {
return _reference; return _reference;
} }
double getCurrentRatio(unsigned char channel) {
double getCurrentRatio(unsigned char channel) override {
if (channel >= _channels) return 0; if (channel >= _channels) return 0;
return _current_ratio[channel]; return _current_ratio[channel];
} }
unsigned char getChannels() {
size_t countDevices() override {
return _channels; return _channels;
} }
@ -128,6 +134,11 @@ class EmonSensor : public I2CSensor<BaseEmonSensor> {
} }
// Convert slot # index to a magnitude # index
unsigned char local(unsigned char index) override {
return (_magnitudes) ? (index / _magnitudes) : 0u;
}
protected: protected:
// --------------------------------------------------------------------- // ---------------------------------------------------------------------


+ 1
- 1
code/espurna/sensors/EventSensor.h View File

@ -107,7 +107,7 @@ class EventSensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/GUVAS12SDSensor.h View File

@ -91,7 +91,7 @@ class GUVAS12SDSensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/GeigerSensor.h View File

@ -94,7 +94,7 @@ String description() {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
char buffer[30]; char buffer[30];
unsigned char i=0; unsigned char i=0;
#if GEIGER_REPORT_CPM #if GEIGER_REPORT_CPM


+ 1
- 1
code/espurna/sensors/HDC1080Sensor.h View File

@ -57,7 +57,7 @@ class HDC1080Sensor : public I2CSensor<> {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 73
- 43
code/espurna/sensors/HLW8012Sensor.h View File

@ -33,22 +33,6 @@ class HLW8012Sensor : public BaseEmonSensor {
delete _hlw8012; delete _hlw8012;
} }
void expectedCurrent(double expected) {
_hlw8012->expectedCurrent(expected);
}
void expectedVoltage(unsigned int expected) {
_hlw8012->expectedVoltage(expected);
}
void expectedPower(unsigned int expected) {
_hlw8012->expectedActivePower(expected);
}
void resetRatios() {
_hlw8012->resetMultipliers();
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
void setSEL(unsigned char sel) { void setSEL(unsigned char sel) {
@ -73,18 +57,62 @@ class HLW8012Sensor : public BaseEmonSensor {
_sel_current = value; _sel_current = value;
} }
void setCurrentRatio(double value) {
// ---------------------------------------------------------------------
void expectedCurrent(double expected) override {
_hlw8012->expectedCurrent(expected);
}
void expectedVoltage(unsigned int expected) override {
_hlw8012->expectedVoltage(expected);
}
void expectedPower(unsigned int expected) override {
_hlw8012->expectedActivePower(expected);
}
double defaultCurrentRatio() const override {
return HLW8012_CURRENT_RATIO;
}
double defaultVoltageRatio() const override {
return HLW8012_VOLTAGE_RATIO;
}
double defaultPowerRatio() const override {
return HLW8012_POWER_RATIO;
}
void resetRatios() override {
_hlw8012->setCurrentMultiplier(_initialRatioC);
_hlw8012->setVoltageMultiplier(_initialRatioV);
_hlw8012->setPowerMultiplier(_initialRatioP);
}
void setCurrentRatio(double value) override {
_hlw8012->setCurrentMultiplier(value); _hlw8012->setCurrentMultiplier(value);
}; };
void setVoltageRatio(double value) {
void setVoltageRatio(double value) override {
_hlw8012->setVoltageMultiplier(value); _hlw8012->setVoltageMultiplier(value);
}; };
void setPowerRatio(double value) {
void setPowerRatio(double value) override {
_hlw8012->setPowerMultiplier(value); _hlw8012->setPowerMultiplier(value);
}; };
double getCurrentRatio() override {
return _hlw8012->getCurrentMultiplier();
};
double getVoltageRatio() override {
return _hlw8012->getVoltageMultiplier();
};
double getPowerRatio() override {
return _hlw8012->getPowerMultiplier();
};
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
unsigned char getSEL() { unsigned char getSEL() {
@ -103,18 +131,6 @@ class HLW8012Sensor : public BaseEmonSensor {
return _sel_current; return _sel_current;
} }
double getCurrentRatio() {
return _hlw8012->getCurrentMultiplier();
};
double getVoltageRatio() {
return _hlw8012->getVoltageMultiplier();
};
double getPowerRatio() {
return _hlw8012->getPowerMultiplier();
};
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Sensors API // Sensors API
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -135,17 +151,8 @@ class HLW8012Sensor : public BaseEmonSensor {
_hlw8012->begin(_cf, _cf1, _sel, _sel_current, false, 1000000); _hlw8012->begin(_cf, _cf1, _sel, _sel_current, false, 1000000);
#endif #endif
// These values are used to calculate current, voltage and power factors as per datasheet formula
// These are the nominal values for the Sonoff POW resistors:
// * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
// * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
// * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
_hlw8012->setResistors(HLW8012_CURRENT_R, HLW8012_VOLTAGE_R_UP, HLW8012_VOLTAGE_R_DOWN);
// Also, adjust with ratio values that could be set in hardware profile
if (HLW8012_CURRENT_RATIO > 0.0) _hlw8012->setCurrentMultiplier(HLW8012_CURRENT_RATIO);
if (HLW8012_VOLTAGE_RATIO > 0.0) _hlw8012->setVoltageMultiplier(HLW8012_VOLTAGE_RATIO);
if (HLW8012_POWER_RATIO > 0.0) _hlw8012->setPowerMultiplier(HLW8012_POWER_RATIO);
// Adjust with ratio values that could be set in the hardware profile
_defaultRatios();
// Handle interrupts // Handle interrupts
#if HLW8012_USE_INTERRUPTS && (!HLW8012_WAIT_FOR_WIFI) #if HLW8012_USE_INTERRUPTS && (!HLW8012_WAIT_FOR_WIFI)
@ -165,7 +172,7 @@ class HLW8012Sensor : public BaseEmonSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };
@ -232,6 +239,25 @@ class HLW8012Sensor : public BaseEmonSensor {
protected: protected:
void _defaultRatios() {
// These values are used to calculate current, voltage and power factors as per datasheet formula
// These are the nominal values for the Sonoff POW resistors:
// * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
// * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
// * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
_hlw8012->setResistors(HLW8012_CURRENT_R, HLW8012_VOLTAGE_R_UP, HLW8012_VOLTAGE_R_DOWN);
// Multipliers are already set, but we might have changed default values via the hardware profile
if (defaultCurrentRatio() > 0.0) _hlw8012->setCurrentMultiplier(defaultCurrentRatio());
if (defaultVoltageRatio() > 0.0) _hlw8012->setVoltageMultiplier(defaultVoltageRatio());
if (defaultPowerRatio() > 0.0) _hlw8012->setPowerMultiplier(defaultPowerRatio());
// Preserve ratios as a fallback
_initialRatioC = getCurrentRatio();
_initialRatioV = getVoltageRatio();
_initialRatioP = getPowerRatio();
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Interrupt management // Interrupt management
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -276,6 +302,10 @@ class HLW8012Sensor : public BaseEmonSensor {
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
double _initialRatioC;
double _initialRatioV;
double _initialRatioP;
unsigned char _sel = GPIO_NONE; unsigned char _sel = GPIO_NONE;
unsigned char _cf = GPIO_NONE; unsigned char _cf = GPIO_NONE;
unsigned char _cf1 = GPIO_NONE; unsigned char _cf1 = GPIO_NONE;


+ 1
- 1
code/espurna/sensors/I2CSensor.h View File

@ -47,7 +47,7 @@ class I2CSensor : public T {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return static_cast<T*>(this)->description(); return static_cast<T*>(this)->description();
}; };


+ 1
- 1
code/espurna/sensors/LDRSensor.h View File

@ -125,7 +125,7 @@ class LDRSensor : public AnalogSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
} }


+ 1
- 1
code/espurna/sensors/MAX6675Sensor.h View File

@ -95,7 +95,7 @@ class MAX6675Sensor : public BaseSensor {
// Address of the device // Address of the device
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
if (index < _count) { if (index < _count) {
// char buffer[40]; // char buffer[40];
// uint8_t * address = _devices[index].address; // uint8_t * address = _devices[index].address;


+ 1
- 1
code/espurna/sensors/MHZ19Sensor.h View File

@ -94,7 +94,7 @@ class MHZ19Sensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/MICS2710Sensor.h View File

@ -90,7 +90,7 @@ class MICS2710Sensor : public BaseAnalogSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/MICS5525Sensor.h View File

@ -62,7 +62,7 @@ class MICS5525Sensor : public BaseAnalogSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/NTCSensor.h View File

@ -61,7 +61,7 @@ class NTCSensor : public AnalogSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
} }


+ 1
- 1
code/espurna/sensors/PMSX003Sensor.h View File

@ -247,7 +247,7 @@ class PMSX003Sensor : public BaseSensor, PMSX003 {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
char buffer[36] = {0}; char buffer[36] = {0};
if (_soft) { if (_soft) {
snprintf(buffer, sizeof(buffer), "%d @ %s @ SwSerial(%u,%u)", int(index + 1), pms_specs[_type].name, _pin_rx, _pin_tx); snprintf(buffer, sizeof(buffer), "%d @ %s @ SwSerial(%u,%u)", int(index + 1), pms_specs[_type].name, _pin_rx, _pin_tx);


+ 17
- 12
code/espurna/sensors/PZEM004TSensor.h View File

@ -89,21 +89,23 @@ class PZEM004TSensor : public BaseEmonSensor {
return PZEM004TSensor::instance; return PZEM004TSensor::instance;
} }
// ---------------------------------------------------------------------
// We can't modify PZEM values, just ignore this // We can't modify PZEM values, just ignore this
void resetEnergy() {}
void resetEnergy(unsigned char) {}
void resetEnergy(unsigned char, sensor::Energy) {}
void resetEnergy() override {}
void resetEnergy(unsigned char) override {}
void resetEnergy(unsigned char, sensor::Energy) override {}
// Override Base methods that deal with _energy[] // Override Base methods that deal with _energy[]
size_t countDevices() {
size_t countDevices() override {
return _addresses.size(); return _addresses.size();
} }
double getEnergy(unsigned char index) {
double getEnergy(unsigned char index) override {
return _readings[index].energy; return _readings[index].energy;
} }
sensor::Energy totalEnergy(unsigned char index) {
sensor::Energy totalEnergy(unsigned char index) override {
return getEnergy(index); return getEnergy(index);
} }
@ -210,8 +212,8 @@ class PZEM004TSensor : public BaseEmonSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
int dev = index / PZ_MAGNITUDE_COUNT;
String description(unsigned char index) {
auto dev = local(index);
char buffer[25]; char buffer[25];
snprintf(buffer, sizeof(buffer), "(%u/%s)", dev, getAddress(dev).c_str()); snprintf(buffer, sizeof(buffer), "(%u/%s)", dev, getAddress(dev).c_str());
return description() + String(buffer); return description() + String(buffer);
@ -219,14 +221,17 @@ class PZEM004TSensor : public BaseEmonSensor {
// Address of the sensor (it could be the GPIO or I2C address) // Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) { String address(unsigned char index) {
int dev = index / PZ_MAGNITUDE_COUNT;
return _addresses[dev].toString();
return _addresses[local(index)].toString();
}
// Convert slot # to a magnitude #
unsigned char local(unsigned char index) override {
return index / PZ_MAGNITUDE_COUNT;
} }
// Type for slot # index // Type for slot # index
unsigned char type(unsigned char index) { unsigned char type(unsigned char index) {
int dev = index / PZ_MAGNITUDE_COUNT;
index = index - (dev * PZ_MAGNITUDE_COUNT);
index = index - (local(index) * PZ_MAGNITUDE_COUNT);
if (index == PZ_MAGNITUDE_CURRENT_INDEX) return MAGNITUDE_CURRENT; if (index == PZ_MAGNITUDE_CURRENT_INDEX) return MAGNITUDE_CURRENT;
if (index == PZ_MAGNITUDE_VOLTAGE_INDEX) return MAGNITUDE_VOLTAGE; if (index == PZ_MAGNITUDE_VOLTAGE_INDEX) return MAGNITUDE_VOLTAGE;
if (index == PZ_MAGNITUDE_POWER_ACTIVE_INDEX) return MAGNITUDE_POWER_ACTIVE; if (index == PZ_MAGNITUDE_POWER_ACTIVE_INDEX) return MAGNITUDE_POWER_ACTIVE;


+ 1
- 1
code/espurna/sensors/PulseMeterSensor.h View File

@ -82,7 +82,7 @@ class PulseMeterSensor : public BaseEmonSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/SDS011Sensor.h View File

@ -83,7 +83,7 @@ class SDS011Sensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/SI1145Sensor.h View File

@ -51,7 +51,7 @@ class SI1145Sensor : public I2CSensor<> {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/SI7021Sensor.h View File

@ -63,7 +63,7 @@ class SI7021Sensor : public I2CSensor<> {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/SenseAirSensor.h View File

@ -180,7 +180,7 @@ class SenseAirSensor : public BaseSensor, SenseAir {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
} }


+ 1
- 1
code/espurna/sensors/SonarSensor.h View File

@ -85,7 +85,7 @@ class SonarSensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/T6613Sensor.h View File

@ -89,7 +89,7 @@ class T6613Sensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/TMP3XSensor.h View File

@ -56,7 +56,7 @@ class TMP3XSensor : public BaseSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/V9261FSensor.h View File

@ -84,7 +84,7 @@ class V9261FSensor : public BaseEmonSensor {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/VEML6075Sensor.h View File

@ -50,7 +50,7 @@ class VEML6075Sensor : public I2CSensor<> {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 1
- 1
code/espurna/sensors/VL53L1XSensor.h View File

@ -80,7 +80,7 @@ class VL53L1XSensor : public I2CSensor<> {
} }
// Descriptive name of the slot # index // Descriptive name of the slot # index
String slot(unsigned char index) {
String description(unsigned char index) {
return description(); return description();
}; };


+ 16
- 0
code/espurna/settings.cpp View File

@ -241,6 +241,22 @@ std::vector<String> settingsKeys() {
return keys; return keys;
} }
static std::vector<settings_key_match_t> _settings_matchers;
void settingsRegisterDefaults(const settings_key_match_t& matcher) {
_settings_matchers.push_back(matcher);
}
String settingsQueryDefaults(const String& key) {
for (auto& matcher : _settings_matchers) {
if (matcher.match(key.c_str())) {
return matcher.key(key);
}
}
return String();
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Key-value API // Key-value API
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 32
- 2
code/espurna/settings.h View File

@ -38,6 +38,17 @@ class settings_key_t {
settings_key_t(const __FlashStringHelper* value) : settings_key_t(const __FlashStringHelper* value) :
value(value), index(-1) value(value), index(-1)
{} {}
settings_key_t() :
value(), index(-1)
{}
bool match(const char* _value) const {
return (value == _value) || (toString() == _value);
}
bool match(const String& _value) const {
return (value == _value) || (toString() == _value);
}
String toString() const; String toString() const;
@ -105,19 +116,38 @@ unsigned short convert(const String& value);
template <> template <>
unsigned char convert(const String& value); unsigned char convert(const String& value);
template<typename T>
String serialize(const T& value);
template<typename T>
String serialize(const T& value) {
return String(value);
}
} // namespace settings::internal } // namespace settings::internal
} // namespace settings } // namespace settings
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
struct settings_key_match_t {
using match_f = bool(*)(const char* key);
using key_f = const String(*)(const String& key);
match_f match;
key_f key;
};
void settingsRegisterDefaults(const settings_key_match_t& matcher);
String settingsQueryDefaults(const String& key);
// --------------------------------------------------------------------------
void moveSetting(const String& from, const String& to); void moveSetting(const String& from, const String& to);
void moveSetting(const String& from, const String& to, unsigned int index); void moveSetting(const String& from, const String& to, unsigned int index);
void moveSettings(const String& from, const String& to); void moveSettings(const String& from, const String& to);
#if 1
template<typename R, settings::internal::convert_t<R> Rfunc = settings::internal::convert> template<typename R, settings::internal::convert_t<R> Rfunc = settings::internal::convert>
R getSetting(const settings_key_t& key, R defaultValue) __attribute__((noinline)); R getSetting(const settings_key_t& key, R defaultValue) __attribute__((noinline));
#endif
template<typename R, settings::internal::convert_t<R> Rfunc = settings::internal::convert> template<typename R, settings::internal::convert_t<R> Rfunc = settings::internal::convert>
R getSetting(const settings_key_t& key, R defaultValue) { R getSetting(const settings_key_t& key, R defaultValue) {


+ 6
- 1
code/espurna/terminal.cpp View File

@ -254,7 +254,12 @@ void _terminalInitCommand() {
String key = String(e->argv[i]); String key = String(e->argv[i]);
String value; String value;
if (!Embedis::get(key, value)) { if (!Embedis::get(key, value)) {
DEBUG_MSG_P(PSTR("> %s =>\n"), key.c_str());
const auto maybeDefault = settingsQueryDefaults(key);
if (maybeDefault.length()) {
DEBUG_MSG_P(PSTR("> %s => %s (default)\n"), key.c_str(), maybeDefault.c_str());
} else {
DEBUG_MSG_P(PSTR("> %s =>\n"), key.c_str());
}
continue; continue;
} }


+ 1
- 1
code/espurna/thingspeak.cpp View File

@ -404,7 +404,7 @@ void _tspkFlush() {
// POST data if any // POST data if any
if (_tspk_data.length()) { if (_tspk_data.length()) {
_tspk_data.concat("&api_key="); _tspk_data.concat("&api_key=");
_tspk_data.concat(getSetting<String>("tspkKey", THINGSPEAK_APIKEY));
_tspk_data.concat(getSetting("tspkKey", THINGSPEAK_APIKEY));
--_tspk_tries; --_tspk_tries;
_tspkPost(getSetting("tspkAddress", THINGSPEAK_ADDRESS)); _tspkPost(getSetting("tspkAddress", THINGSPEAK_ADDRESS));
} }


+ 10
- 2
code/espurna/wifi.cpp View File

@ -25,6 +25,7 @@ unsigned long _wifi_gratuitous_arp_last = 0;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// PRIVATE // PRIVATE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
struct wifi_scan_info_t { struct wifi_scan_info_t {
String ssid_scan; String ssid_scan;
int32_t rssi_scan; int32_t rssi_scan;
@ -58,7 +59,11 @@ void _wifiCheckAP() {
} }
} }
WiFiSleepType_t _wifiSleepModeConvert(const String& value) {
namespace settings {
namespace internal {
template<>
WiFiSleepType_t convert(const String& value) {
switch (value.toInt()) { switch (value.toInt()) {
case 2: case 2:
return WIFI_MODEM_SLEEP; return WIFI_MODEM_SLEEP;
@ -70,6 +75,9 @@ WiFiSleepType_t _wifiSleepModeConvert(const String& value) {
} }
} }
}
}
void _wifiConfigure() { void _wifiConfigure() {
jw.setHostname(getSetting("hostname").c_str()); jw.setHostname(getSetting("hostname").c_str());
@ -131,7 +139,7 @@ void _wifiConfigure() {
jw.enableScan(getSetting("wifiScan", 1 == WIFI_SCAN_NETWORKS)); jw.enableScan(getSetting("wifiScan", 1 == WIFI_SCAN_NETWORKS));
const auto sleep_mode = getSetting<WiFiSleepType_t, _wifiSleepModeConvert>("wifiSleep", WIFI_SLEEP_MODE);
const auto sleep_mode = getSetting("wifiSleep", WIFI_SLEEP_MODE);
WiFi.setSleepMode(sleep_mode); WiFi.setSleepMode(sleep_mode);
#if WIFI_GRATUITOUS_ARP_SUPPORT #if WIFI_GRATUITOUS_ARP_SUPPORT


Loading…
Cancel
Save