Browse Source

sys: clean-up system-specific functions

- shrink utils source file, move heartbeat and boot management into system
- improvise with 'heartbeat' functionality. include scheduler implementation that will
manage the per-module heartbeat callbacks with individual 'mode' and
'interval' settings. current ones are mqtt (including relays, lights, thermostat), debug and
influxdb. preserve heartbeat NONE, ONCE and REPEAT, REPEAT_STATUS is effectively a hbReport & status bit.
- mqtt heartbeat is managed through mqttHeartbeat() callbacks
- tweak mqtt callbacks to use lists instead of the vector, slighly reducing the size of the .bin
- update WebUI, include report setting and update hbMode values
- make sure general.h settings include new heartbeat,
move constant definitions outside of the header
- correctly include dependencies through the .cpp, avoid leaking
internal details.
- as a side-effect, base headers are no longer included recursively
mcspr-patch-1
Maxim Prokhorov 3 years ago
parent
commit
021f0afb86
130 changed files with 27259 additions and 26952 deletions
  1. +1
    -0
      code/espurna/alexa.cpp
  2. +0
    -5
      code/espurna/alexa.h
  3. +1
    -1
      code/espurna/board.h
  4. +0
    -2
      code/espurna/config/dependencies.h
  5. +94
    -175
      code/espurna/config/general.h
  6. +1
    -1
      code/espurna/config/hardware.h
  7. +8
    -0
      code/espurna/config/types.h
  8. +30
    -31
      code/espurna/crash.cpp
  9. +2
    -1
      code/espurna/curtain_kingart.cpp
  10. BIN
      code/espurna/data/index.all.html.gz
  11. BIN
      code/espurna/data/index.curtain.html.gz
  12. BIN
      code/espurna/data/index.garland.html.gz
  13. BIN
      code/espurna/data/index.light.html.gz
  14. BIN
      code/espurna/data/index.lightfox.html.gz
  15. BIN
      code/espurna/data/index.rfbridge.html.gz
  16. BIN
      code/espurna/data/index.rfm69.html.gz
  17. BIN
      code/espurna/data/index.sensor.html.gz
  18. BIN
      code/espurna/data/index.small.html.gz
  19. BIN
      code/espurna/data/index.thermostat.html.gz
  20. +28
    -0
      code/espurna/debug.cpp
  21. +2
    -17
      code/espurna/debug.h
  22. +15
    -3
      code/espurna/espurna.h
  23. +4
    -43
      code/espurna/espurna.ino
  24. +0
    -1
      code/espurna/garland/animations/anim_spread.h
  25. +19
    -7
      code/espurna/gpio.h
  26. +20
    -15
      code/espurna/homeassistant.cpp
  27. +33
    -2
      code/espurna/influxdb.cpp
  28. +6
    -0
      code/espurna/ir.cpp
  29. +0
    -10
      code/espurna/ir.h
  30. +0
    -1
      code/espurna/led.h
  31. +32
    -13
      code/espurna/light.cpp
  32. +11
    -0
      code/espurna/light.h
  33. +5
    -2
      code/espurna/llmnr.cpp
  34. +0
    -5
      code/espurna/llmnr.h
  35. +33
    -72
      code/espurna/main.cpp
  36. +65
    -0
      code/espurna/main.h
  37. +1
    -0
      code/espurna/migrate.cpp
  38. +109
    -20
      code/espurna/mqtt.cpp
  39. +47
    -8
      code/espurna/mqtt.h
  40. +5
    -2
      code/espurna/netbios.cpp
  41. +0
    -6
      code/espurna/netbios.h
  42. +2
    -0
      code/espurna/nofuss.cpp
  43. +0
    -6
      code/espurna/nofuss.h
  44. +19
    -10
      code/espurna/ntp.cpp
  45. +7
    -23
      code/espurna/ntp.h
  46. +4
    -0
      code/espurna/ntp_legacy.cpp
  47. +0
    -1
      code/espurna/ntp_timelib.h
  48. +0
    -6
      code/espurna/ota.h
  49. +10
    -6
      code/espurna/ota_httpupdate.cpp
  50. +8
    -7
      code/espurna/relay.cpp
  51. +6
    -2
      code/espurna/rfm69.cpp
  52. +0
    -8
      code/espurna/rfm69.h
  53. +1
    -1
      code/espurna/rpc.cpp
  54. +1
    -0
      code/espurna/rpnrules.cpp
  55. +7
    -5
      code/espurna/scheduler.cpp
  56. +3
    -4
      code/espurna/sensors/ADE7953Sensor.h
  57. +0
    -2
      code/espurna/sensors/AM2320Sensor.h
  58. +0
    -4
      code/espurna/sensors/AnalogSensor.h
  59. +0
    -2
      code/espurna/sensors/BH1750Sensor.h
  60. +2
    -3
      code/espurna/sensors/BME680Sensor.h
  61. +0
    -2
      code/espurna/sensors/BMP180Sensor.h
  62. +0
    -41
      code/espurna/sensors/BMX280Sensor.h
  63. +139
    -131
      code/espurna/sensors/BaseSensor.h
  64. +2
    -5
      code/espurna/sensors/CSE7766Sensor.h
  65. +0
    -1
      code/espurna/sensors/DHTSensor.h
  66. +0
    -1
      code/espurna/sensors/DallasSensor.h
  67. +0
    -1
      code/espurna/sensors/DigitalSensor.h
  68. +2
    -6
      code/espurna/sensors/ECH1560Sensor.h
  69. +0
    -1
      code/espurna/sensors/EZOPHSensor.h
  70. +0
    -1
      code/espurna/sensors/EmonADC121Sensor.h
  71. +0
    -1
      code/espurna/sensors/EmonADS1X15Sensor.h
  72. +0
    -1
      code/espurna/sensors/EmonAnalogSensor.h
  73. +0
    -3
      code/espurna/sensors/EmonSensor.h
  74. +0
    -3
      code/espurna/sensors/EventSensor.h
  75. +1
    -2
      code/espurna/sensors/GUVAS12SDSensor.h
  76. +0
    -3
      code/espurna/sensors/GeigerSensor.h
  77. +0
    -1
      code/espurna/sensors/HDC1080Sensor.h
  78. +2
    -5
      code/espurna/sensors/HLW8012Sensor.h
  79. +0
    -1
      code/espurna/sensors/LDRSensor.h
  80. +0
    -1
      code/espurna/sensors/MAX6675Sensor.h
  81. +0
    -1
      code/espurna/sensors/MHZ19Sensor.h
  82. +0
    -1
      code/espurna/sensors/MICS2710Sensor.h
  83. +0
    -1
      code/espurna/sensors/MICS5525Sensor.h
  84. +0
    -1
      code/espurna/sensors/NTCSensor.h
  85. +2
    -4
      code/espurna/sensors/PMSX003Sensor.h
  86. +0
    -1
      code/espurna/sensors/PZEM004TSensor.h
  87. +0
    -1
      code/espurna/sensors/PZEM004TV30Sensor.h
  88. +0
    -4
      code/espurna/sensors/PulseMeterSensor.h
  89. +0
    -1
      code/espurna/sensors/SDS011Sensor.h
  90. +0
    -1
      code/espurna/sensors/SHT3XI2CSensor.h
  91. +0
    -1
      code/espurna/sensors/SI1145Sensor.h
  92. +0
    -1
      code/espurna/sensors/SI7021Sensor.h
  93. +0
    -1
      code/espurna/sensors/SenseAirSensor.h
  94. +0
    -1
      code/espurna/sensors/SonarSensor.h
  95. +0
    -1
      code/espurna/sensors/T6613Sensor.h
  96. +0
    -1
      code/espurna/sensors/TMP3XSensor.h
  97. +0
    -1
      code/espurna/sensors/V9261FSensor.h
  98. +0
    -1
      code/espurna/sensors/VEML6075Sensor.h
  99. +0
    -1
      code/espurna/sensors/VL53L1XSensor.h
  100. +7
    -4
      code/espurna/settings.cpp

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

@ -15,6 +15,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "api.h"
#include "broker.h"
#include "light.h"
#include "mqtt.h"
#include "relay.h"
#include "rpc.h"
#include "web.h"


+ 0
- 5
code/espurna/alexa.h View File

@ -10,10 +10,5 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "espurna.h"
#if ALEXA_SUPPORT
bool alexaEnabled();
void alexaSetup();
#endif // ALEXA_SUPPORT == 1

+ 1
- 1
code/espurna/board.h View File

@ -6,7 +6,7 @@ BOARD MODULE
#pragma once
#include "espurna.h"
#include <Arduino.h>
const String& getChipId();
const String& getIdentifier();


+ 0
- 2
code/espurna/config/dependencies.h View File

@ -135,8 +135,6 @@
#if IFAN_SUPPORT
#undef RELAY_SUPPORT
#define RELAY_SUPPORT 1 // Need relays to manage general state
#undef FAN_SUPPORT
#define FAN_SUPPORT 1
#endif
//------------------------------------------------------------------------------


+ 94
- 175
code/espurna/config/general.h View File

@ -32,13 +32,29 @@
// https://github.com/esp8266/Arduino/issues/5825
#endif
//------------------------------------------------------------------------------
// HEARTBEAT
//------------------------------------------------------------------------------
#ifndef HEARTBEAT_MODE
#define HEARTBEAT_MODE HEARTBEAT_REPEAT
#endif
#ifndef HEARTBEAT_INTERVAL
#define HEARTBEAT_INTERVAL heartbeat::Seconds(300ul) // Interval between heartbeat messages
#endif
//------------------------------------------------------------------------------
// DEBUG
//------------------------------------------------------------------------------
// Set global logger mode. One of:
// - DebugLogMode::Enabled
// - DebugLogMode::Disabled
// - DebugLogMode::SkipBoot
#ifndef DEBUG_LOG_MODE
#define DEBUG_LOG_MODE DebugLogMode::Enabled // Set global logger mode. One of:
// ::Enabled, ::Disabled or ::SkipBoot
#define DEBUG_LOG_MODE DebugLogMode::Enabled
#endif
// Serial debug log
@ -236,11 +252,11 @@
#endif
#ifndef GARLAND_D_PIN
#define GARLAND_D_PIN D2 // WS2812 pin number
#define GARLAND_D_PIN 4 // WS2812 pin number (default: D2 / GPIO4)
#endif
#ifndef GARLAND_LEDS
#define GARLAND_LEDS 60 // Leds number
#define GARLAND_LEDS 60 // Number of LEDs
#endif
//------------------------------------------------------------------------------
@ -267,30 +283,9 @@
#endif
//------------------------------------------------------------------------------
// HEARTBEAT
// HEARTBEAT REPORT
//------------------------------------------------------------------------------
#define HEARTBEAT_NONE 0 // Never send heartbeat
#define HEARTBEAT_ONCE 1 // Send it only once upon MQTT connection
#define HEARTBEAT_REPEAT 2 // Send it upon MQTT connection and every HEARTBEAT_INTERVAL
#define HEARTBEAT_REPEAT_STATUS 3 // Send it upon MQTT connection and every HEARTBEAT_INTERVAL only STATUS report
// Backwards compatibility check
#if defined(HEARTBEAT_ENABLED) && (HEARTBEAT_ENABLED == 0)
#define HEARTBEAT_MODE HEARTBEAT_NONE
#endif
#ifndef HEARTBEAT_MODE
#define HEARTBEAT_MODE HEARTBEAT_REPEAT
#endif
#ifndef HEARTBEAT_INTERVAL
#define HEARTBEAT_INTERVAL 300UL // Interval between heartbeat messages (in sec)
#endif
#define UPTIME_OVERFLOW 4294967295UL // Uptime overflow value
// Values that will be reported in heartbeat
#ifndef HEARTBEAT_REPORT_STATUS
#define HEARTBEAT_REPORT_STATUS 1
#endif
@ -364,11 +359,11 @@
#endif
#ifndef HEARTBEAT_REPORT_RANGE
#define HEARTBEAT_REPORT_RANGE THERMOSTAT_SUPPORT
#define HEARTBEAT_REPORT_RANGE 1
#endif
#ifndef HEARTBEAT_REPORT_REMOTE_TEMP
#define HEARTBEAT_REPORT_REMOTE_TEMP THERMOSTAT_SUPPORT
#define HEARTBEAT_REPORT_REMOTE_TEMP 1
#endif
#ifndef HEARTBEAT_REPORT_BSSID
@ -383,73 +378,6 @@
#define LOADAVG_INTERVAL 30000 // Interval between calculating load average (in ms)
#endif
//------------------------------------------------------------------------------
// BUTTON
//------------------------------------------------------------------------------
#ifndef BUTTON_SUPPORT
#define BUTTON_SUPPORT 1
#endif
#ifndef BUTTON_DEBOUNCE_DELAY
#define BUTTON_DEBOUNCE_DELAY 50 // Debounce delay (ms)
#endif
#ifndef BUTTON_REPEAT_DELAY
#define BUTTON_REPEAT_DELAY 500 // Time in ms to wait for a second (or third...) click
#endif
#ifndef BUTTON_LNGCLICK_DELAY
#define BUTTON_LNGCLICK_DELAY 1000 // Time in ms holding the button down to get a long click
#endif
#ifndef BUTTON_LNGLNGCLICK_DELAY
#define BUTTON_LNGLNGCLICK_DELAY 10000 // Time in ms holding the button down to get a long-long click
#endif
#ifndef BUTTON_MQTT_SEND_ALL_EVENTS
#define BUTTON_MQTT_SEND_ALL_EVENTS 0 // 0 - to send only events the are bound to actions
// 1 - to send all button events to MQTT
#endif
#ifndef BUTTON_MQTT_RETAIN
#define BUTTON_MQTT_RETAIN 0
#endif
// Generic digital pin support
#ifndef BUTTON_PROVIDER_GPIO_SUPPORT
#define BUTTON_PROVIDER_GPIO_SUPPORT 1
#endif
// Resistor ladder support. Poll analog pin and return digital LOW when analog reading is in a certain range
// ref. https://github.com/bxparks/AceButton/tree/develop/docs/resistor_ladder
// Uses BUTTON#_ANALOG_LEVEL for the individual button level configuration
#ifndef BUTTON_PROVIDER_ANALOG_SUPPORT
#define BUTTON_PROVIDER_ANALOG_SUPPORT 0
#endif
//------------------------------------------------------------------------------
// ENCODER
//------------------------------------------------------------------------------
#ifndef ENCODER_SUPPORT
#define ENCODER_SUPPORT 0
#endif
#ifndef ENCODER_MINIMUM_DELTA
#define ENCODER_MINIMUM_DELTA 1
#endif
//------------------------------------------------------------------------------
// LED
//------------------------------------------------------------------------------
#ifndef LED_SUPPORT
#define LED_SUPPORT 1
#endif
//------------------------------------------------------------------------------
// RELAY
//------------------------------------------------------------------------------
@ -533,6 +461,73 @@
#define RELAY_MQTT_TOGGLE "2"
#endif
//------------------------------------------------------------------------------
// BUTTON
//------------------------------------------------------------------------------
#ifndef BUTTON_SUPPORT
#define BUTTON_SUPPORT 1
#endif
#ifndef BUTTON_DEBOUNCE_DELAY
#define BUTTON_DEBOUNCE_DELAY 50 // Debounce delay (ms)
#endif
#ifndef BUTTON_REPEAT_DELAY
#define BUTTON_REPEAT_DELAY 500 // Time in ms to wait for a second (or third...) click
#endif
#ifndef BUTTON_LNGCLICK_DELAY
#define BUTTON_LNGCLICK_DELAY 1000 // Time in ms holding the button down to get a long click
#endif
#ifndef BUTTON_LNGLNGCLICK_DELAY
#define BUTTON_LNGLNGCLICK_DELAY 10000 // Time in ms holding the button down to get a long-long click
#endif
#ifndef BUTTON_MQTT_SEND_ALL_EVENTS
#define BUTTON_MQTT_SEND_ALL_EVENTS 0 // 0 - to send only events the are bound to actions
// 1 - to send all button events to MQTT
#endif
#ifndef BUTTON_MQTT_RETAIN
#define BUTTON_MQTT_RETAIN 0
#endif
// Generic digital pin support
#ifndef BUTTON_PROVIDER_GPIO_SUPPORT
#define BUTTON_PROVIDER_GPIO_SUPPORT 1
#endif
// Resistor ladder support. Poll analog pin and return digital LOW when analog reading is in a certain range
// ref. https://github.com/bxparks/AceButton/tree/develop/docs/resistor_ladder
// Uses BUTTON#_ANALOG_LEVEL for the individual button level configuration
#ifndef BUTTON_PROVIDER_ANALOG_SUPPORT
#define BUTTON_PROVIDER_ANALOG_SUPPORT 0
#endif
//------------------------------------------------------------------------------
// ENCODER
//------------------------------------------------------------------------------
#ifndef ENCODER_SUPPORT
#define ENCODER_SUPPORT 0
#endif
#ifndef ENCODER_MINIMUM_DELTA
#define ENCODER_MINIMUM_DELTA 1
#endif
//------------------------------------------------------------------------------
// LED
//------------------------------------------------------------------------------
#ifndef LED_SUPPORT
#define LED_SUPPORT 1
#endif
// -----------------------------------------------------------------------------
// WIFI
// -----------------------------------------------------------------------------
@ -1132,7 +1127,6 @@
#define MQTT_KEEPALIVE 120 // MQTT keepalive value
#endif
#ifndef MQTT_RECONNECT_DELAY_MIN
#define MQTT_RECONNECT_DELAY_MIN 5000 // Try to reconnect in 5 seconds upon disconnection
#endif
@ -1188,71 +1182,6 @@
#define MQTT_ENQUEUE_MESSAGE_ID 1
#endif
// These particles will be concatenated to the MQTT_TOPIC base to form the actual topic
#define MQTT_TOPIC_JSON "data"
#define MQTT_TOPIC_ACTION "action"
#define MQTT_TOPIC_RELAY "relay"
#define MQTT_TOPIC_LED "led"
#define MQTT_TOPIC_BUTTON "button"
#define MQTT_TOPIC_IP "ip"
#define MQTT_TOPIC_SSID "ssid"
#define MQTT_TOPIC_BSSID "bssid"
#define MQTT_TOPIC_VERSION "version"
#define MQTT_TOPIC_UPTIME "uptime"
#define MQTT_TOPIC_DATETIME "datetime"
#define MQTT_TOPIC_TIMESTAMP "timestamp"
#define MQTT_TOPIC_FREEHEAP "freeheap"
#define MQTT_TOPIC_VCC "vcc"
#ifndef MQTT_TOPIC_STATUS
#define MQTT_TOPIC_STATUS "status"
#endif
#define MQTT_TOPIC_MAC "mac"
#define MQTT_TOPIC_RSSI "rssi"
#define MQTT_TOPIC_MESSAGE_ID "id"
#define MQTT_TOPIC_APP "app"
#define MQTT_TOPIC_INTERVAL "interval"
#define MQTT_TOPIC_HOSTNAME "host"
#define MQTT_TOPIC_DESCRIPTION "desc"
#define MQTT_TOPIC_TIME "time"
#define MQTT_TOPIC_RFOUT "rfout"
#define MQTT_TOPIC_RFIN "rfin"
#define MQTT_TOPIC_RFLEARN "rflearn"
#define MQTT_TOPIC_RFRAW "rfraw"
#define MQTT_TOPIC_UARTIN "uartin"
#define MQTT_TOPIC_UARTOUT "uartout"
#define MQTT_TOPIC_LOADAVG "loadavg"
#define MQTT_TOPIC_BOARD "board"
#define MQTT_TOPIC_PULSE "pulse"
#define MQTT_TOPIC_SPEED "speed"
#define MQTT_TOPIC_IRIN "irin"
#define MQTT_TOPIC_IROUT "irout"
#define MQTT_TOPIC_OTA "ota"
#define MQTT_TOPIC_TELNET_REVERSE "telnet_reverse"
#define MQTT_TOPIC_CURTAIN "curtain"
#define MQTT_TOPIC_CMD "cmd"
// Light module
#define MQTT_TOPIC_LIGHT "light"
#define MQTT_TOPIC_CHANNEL "channel"
#define MQTT_TOPIC_COLOR_RGB "rgb"
#define MQTT_TOPIC_COLOR_HSV "hsv"
#define MQTT_TOPIC_ANIM_MODE "anim_mode"
#define MQTT_TOPIC_ANIM_SPEED "anim_speed"
#define MQTT_TOPIC_BRIGHTNESS "brightness"
#define MQTT_TOPIC_MIRED "mired"
#define MQTT_TOPIC_KELVIN "kelvin"
#define MQTT_TOPIC_TRANSITION "transition"
// Thermostat module
#define MQTT_TOPIC_HOLD_TEMP "hold_temp"
#define MQTT_TOPIC_HOLD_TEMP_MIN "min"
#define MQTT_TOPIC_HOLD_TEMP_MAX "max"
#define MQTT_TOPIC_REMOTE_TEMP "remote_temp"
#define MQTT_TOPIC_ASK_TEMP_RANGE "ask_temp_range"
#define MQTT_TOPIC_NOTIFY_TEMP_RANGE_MIN "notify_temp_range_min"
#define MQTT_TOPIC_NOTIFY_TEMP_RANGE_MAX "notify_temp_range_max"
#ifndef MQTT_STATUS_ONLINE
#define MQTT_STATUS_ONLINE "1" // Value for the device ON message
#endif
@ -1492,7 +1421,6 @@
#define INFLUXDB_PASSWORD "" // Default password
#endif
// -----------------------------------------------------------------------------
// THINGSPEAK
// -----------------------------------------------------------------------------
@ -1842,30 +1770,18 @@
#define PROMETHEUS_SUPPORT 0
#endif
//--------------------------------------------------------------------------------
// Generic Fan support
//--------------------------------------------------------------------------------
#ifndef FAN_SUPPORT
#define FAN_SUPPORT 0
#endif
//--------------------------------------------------------------------------------
// ITEAD iFan support
//--------------------------------------------------------------------------------
// Note: enabling this will also implicitly enable FAN_SUPPORT
#ifndef IFAN_SUPPORT
#define IFAN_SUPPORT 0
#endif
// =============================================================================
// Configuration helpers
// Configuration helpers to help detect features
// =============================================================================
//------------------------------------------------------------------------------
// Provide generic way to detect debugging support
//------------------------------------------------------------------------------
#ifndef DEBUG_SUPPORT
#define DEBUG_SUPPORT ( \
DEBUG_SERIAL_SUPPORT || \
@ -1875,3 +1791,6 @@
)
#endif
#ifndef FAN_SUPPORT
#define FAN_SUPPORT IFAN_SUPPORT
#endif

+ 1
- 1
code/espurna/config/hardware.h View File

@ -1018,7 +1018,7 @@
#define DEVICE "SONOFF_IFAN02"
// Base module
#define FAN_SUPPORT 1
#define IFAN_SUPPORT 1
// These buttons are triggered by the remote
// Fan module adds a custom button handler and a special relay controlling the speed


+ 8
- 0
code/espurna/config/types.h View File

@ -167,6 +167,14 @@
#define SYSLOG_LOCAL6 (22<<3) /* reserved for local use */
#define SYSLOG_LOCAL7 (23<<3) /* reserved for local use */
//------------------------------------------------------------------------------
// Heartbeat
//------------------------------------------------------------------------------
#define HEARTBEAT_NONE heartbeat::Mode::None
#define HEARTBEAT_ONCE heartbeat::Mode::Once
#define HEARTBEAT_REPEAT heartbeat::Mode::Repeat
//------------------------------------------------------------------------------
// MQTT
//------------------------------------------------------------------------------


+ 30
- 31
code/espurna/crash.cpp View File

@ -59,29 +59,29 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
// We will use this later as a marker that there was a crash
uint32_t crash_time = millis();
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, crash_time);
eepromPut(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, crash_time);
// XXX rst_info::reason and ::exccause are uint32_t, but are holding small values
// make sure we are using ::write() instead of ::put(), former tries to deduce the required size based on variable type
EEPROMr.write(EepromCrashBegin + SAVE_CRASH_RESTART_REASON,
eepromWrite(EepromCrashBegin + SAVE_CRASH_RESTART_REASON,
static_cast<uint8_t>(rst_info->reason));
EEPROMr.write(EepromCrashBegin + SAVE_CRASH_EXCEPTION_CAUSE,
eepromWrite(EepromCrashBegin + SAVE_CRASH_EXCEPTION_CAUSE,
static_cast<uint8_t>(rst_info->exccause));
// write epc1, epc2, epc3, excvaddr and depc to EEPROM as uint32_t
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_EPC1, rst_info->epc1);
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_EPC2, rst_info->epc2);
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_EPC3, rst_info->epc3);
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_EXCVADDR, rst_info->excvaddr);
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_DEPC, rst_info->depc);
eepromPut(EepromCrashBegin + SAVE_CRASH_EPC1, rst_info->epc1);
eepromPut(EepromCrashBegin + SAVE_CRASH_EPC2, rst_info->epc2);
eepromPut(EepromCrashBegin + SAVE_CRASH_EPC3, rst_info->epc3);
eepromPut(EepromCrashBegin + SAVE_CRASH_EXCVADDR, rst_info->excvaddr);
eepromPut(EepromCrashBegin + SAVE_CRASH_DEPC, rst_info->depc);
// EEPROM size is limited, write as little as possible.
// we definitely want to avoid big stack traces, e.g. like when stack_end == 0x3fffffb0 and we are in SYS context.
// but still should get enough relevant info and it is possible to set needed size at build/runtime
const uint16_t stack_size = constrain((stack_end - stack_start), 0, CrashReservedSize);
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_STACK_START, stack_start);
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_STACK_END, stack_end);
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_STACK_SIZE, stack_size);
eepromPut(EepromCrashBegin + SAVE_CRASH_STACK_START, stack_start);
eepromPut(EepromCrashBegin + SAVE_CRASH_STACK_END, stack_end);
eepromPut(EepromCrashBegin + SAVE_CRASH_STACK_SIZE, stack_size);
// write stack trace to EEPROM and avoid overwriting settings and reserved data
// [EEPROM RESERVED SPACE] >>> ... CRASH DATA ... >>> [SETTINGS]
@ -89,13 +89,12 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
auto *addr = reinterpret_cast<uint32_t*>(stack_start);
while (EepromCrashEnd > eeprom_addr) {
EEPROMr.put(eeprom_addr, *addr);
eepromPut(eeprom_addr, *addr);
eeprom_addr += sizeof(uint32_t);
++addr;
}
EEPROMr.commit();
eepromForceCommit();
}
/**
@ -103,8 +102,8 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
*/
void crashClear() {
uint32_t crash_time = 0xFFFFFFFF;
EEPROMr.put(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, crash_time);
EEPROMr.commit();
eepromPut(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, crash_time);
eepromCommit();
}
namespace {
@ -118,14 +117,14 @@ void _crashDump(Print& print, bool check) {
char buffer[256] = {0};
uint32_t crash_time;
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, crash_time);
eepromGet(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, crash_time);
bool crash_time_erased = ((crash_time == 0) || (crash_time == 0xFFFFFFFF));
if (check && crash_time_erased) {
return;
}
uint8_t reason = EEPROMr.read(EepromCrashBegin + SAVE_CRASH_RESTART_REASON);
uint8_t reason = eepromRead(EepromCrashBegin + SAVE_CRASH_RESTART_REASON);
if (!crash_time_erased) {
snprintf_P(buffer, sizeof(buffer), PSTR("\nLatest crash was at %lu ms after boot\n"), crash_time);
print.print(buffer);
@ -136,15 +135,15 @@ void _crashDump(Print& print, bool check) {
if (reason == REASON_EXCEPTION_RST) {
snprintf_P(buffer, sizeof(buffer), PSTR("\nException (%u):\n"),
EEPROMr.read(EepromCrashBegin + SAVE_CRASH_EXCEPTION_CAUSE));
eepromRead(EepromCrashBegin + SAVE_CRASH_EXCEPTION_CAUSE));
print.print(buffer);
uint32_t epc1, epc2, epc3, excvaddr, depc;
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_EPC1, epc1);
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_EPC2, epc2);
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_EPC3, epc3);
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_EXCVADDR, excvaddr);
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_DEPC, depc);
eepromGet(EepromCrashBegin + SAVE_CRASH_EPC1, epc1);
eepromGet(EepromCrashBegin + SAVE_CRASH_EPC2, epc2);
eepromGet(EepromCrashBegin + SAVE_CRASH_EPC3, epc3);
eepromGet(EepromCrashBegin + SAVE_CRASH_EXCVADDR, excvaddr);
eepromGet(EepromCrashBegin + SAVE_CRASH_DEPC, depc);
snprintf_P(buffer, sizeof(buffer), PSTR("epc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"),
epc1, epc2, epc3, excvaddr, depc);
@ -169,9 +168,9 @@ void _crashDump(Print& print, bool check) {
uint32_t stack_start, stack_end;
uint16_t stack_size;
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_STACK_START, stack_start);
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_STACK_END, stack_end);
EEPROMr.get(EepromCrashBegin + SAVE_CRASH_STACK_SIZE, stack_size);
eepromGet(EepromCrashBegin + SAVE_CRASH_STACK_START, stack_start);
eepromGet(EepromCrashBegin + SAVE_CRASH_STACK_END, stack_end);
eepromGet(EepromCrashBegin + SAVE_CRASH_STACK_SIZE, stack_size);
if ((0 == stack_size) || (0xffff == stack_size)) return;
stack_size = constrain(stack_size, 0, CrashTraceReservedSize);
@ -191,10 +190,10 @@ void _crashDump(Print& print, bool check) {
uint32_t addr1, addr2, addr3, addr4;
while ((eeprom_addr + (4 * step)) < EepromCrashEnd) {
EEPROMr.get(eeprom_addr, addr1);
EEPROMr.get((eeprom_addr += step), addr2);
EEPROMr.get((eeprom_addr += step), addr3);
EEPROMr.get((eeprom_addr += step), addr4);
eepromGet(eeprom_addr, addr1);
eepromGet((eeprom_addr += step), addr2);
eepromGet((eeprom_addr += step), addr3);
eepromGet((eeprom_addr += step), addr4);
snprintf_P(buffer, sizeof(buffer),
PSTR("%08x: %08x %08x %08x %08x \n"),


+ 2
- 1
code/espurna/curtain_kingart.cpp View File

@ -14,8 +14,9 @@ Copyright (C) 2020 - Eric Chauvet
#if KINGART_CURTAIN_SUPPORT
#include "ntp.h"
#include "mqtt.h"
#include "ntp.h"
#include "ntp_timelib.h"
#include "settings.h"
#include "ws.h"


BIN
code/espurna/data/index.all.html.gz View File


BIN
code/espurna/data/index.curtain.html.gz View File


BIN
code/espurna/data/index.garland.html.gz View File


BIN
code/espurna/data/index.light.html.gz View File


BIN
code/espurna/data/index.lightfox.html.gz View File


BIN
code/espurna/data/index.rfbridge.html.gz View File


BIN
code/espurna/data/index.rfm69.html.gz View File


BIN
code/espurna/data/index.sensor.html.gz View File


BIN
code/espurna/data/index.small.html.gz View File


BIN
code/espurna/data/index.thermostat.html.gz View File


+ 28
- 0
code/espurna/debug.cpp View File

@ -17,8 +17,14 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "settings.h"
#include "telnet.h"
#include "web.h"
#include "ntp.h"
#include "utils.h"
#include "ws.h"
#if DEBUG_WEB_SUPPORT
#include <ArduinoJson.h>
#endif
#if DEBUG_UDP_SUPPORT
#include <WiFiUdp.h>
WiFiUDP _udp_debug;
@ -367,6 +373,24 @@ void debugConfigureBoot() {
debugConfigure();
}
bool _debugHeartbeat(heartbeat::Mask mask) {
if (mask & heartbeat::Report::Uptime)
DEBUG_MSG_P(PSTR("[MAIN] Uptime: %s\n"), getUptime().c_str());
if (mask & heartbeat::Report::Freeheap)
infoHeapStats();
if ((mask & heartbeat::Report::Vcc) && (ADC_MODE_VALUE == ADC_VCC))
DEBUG_MSG_P(PSTR("[MAIN] Power: %lu mV\n"), ESP.getVcc());
#if NTP_SUPPORT
if ((mask & heartbeat::Report::Datetime) && (ntpSynced()))
DEBUG_MSG_P(PSTR("[MAIN] Time: %s\n"), ntpDateTime().c_str());
#endif
return true;
}
void debugConfigure() {
// HardwareSerial::begin() will automatically enable this when
@ -408,6 +432,10 @@ void debugConfigure() {
}
#endif // DEBUG_LOG_BUFFER
systemHeartbeat(_debugHeartbeat,
getSetting("dbgHbMode", heartbeat::currentMode()),
getSetting("dbgHbIntvl", heartbeat::currentInterval()));
}
#endif // DEBUG_SUPPORT

+ 2
- 17
code/espurna/debug.h View File

@ -6,14 +6,10 @@ DEBUG MODULE
#pragma once
#include "espurna.h"
#if DEBUG_WEB_SUPPORT
#include <ArduinoJson.h>
#endif
#include <Arduino.h>
extern "C" {
void custom_crash_callback(struct rst_info*, uint32_t, uint32_t);
void custom_crash_callback(struct rst_info*, uint32_t, uint32_t);
}
class PrintRaw;
@ -36,14 +32,3 @@ void debugSendRaw(const char* line, bool timestamp = false);
void debugSend(const char* format, ...);
void debugSend_P(const char* format, ...);
#if DEBUG_SUPPORT
#define DEBUG_MSG(...) debugSend(__VA_ARGS__)
#define DEBUG_MSG_P(...) debugSend_P(__VA_ARGS__)
#endif
#ifndef DEBUG_MSG
#define DEBUG_MSG(...)
#define DEBUG_MSG_P(...)
#endif

+ 15
- 3
code/espurna/espurna.h View File

@ -3,6 +3,7 @@
ESPurna
Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2019-2021 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -41,12 +42,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <vector>
#include <memory>
using void_callback_f = void (*)();
#if DEBUG_SUPPORT
#define DEBUG_MSG(...) debugSend(__VA_ARGS__)
#define DEBUG_MSG_P(...) debugSend_P(__VA_ARGS__)
#endif
void espurnaRegisterLoop(void_callback_f callback);
void espurnaRegisterReload(void_callback_f callback);
#ifndef DEBUG_MSG
#define DEBUG_MSG(...)
#define DEBUG_MSG_P(...)
#endif
using LoopCallback = void (*)();
void espurnaRegisterLoop(LoopCallback callback);
void espurnaRegisterReload(LoopCallback callback);
void espurnaReload();
unsigned long espurnaLoopDelay();
void espurnaLoopDelay(unsigned long);
void extraSetup();

+ 4
- 43
code/espurna/espurna.ino View File

@ -3,6 +3,7 @@
ESPurna
Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2019-2021 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,48 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// !!! NOTICE !!!
//
// This file is only for compatibility with Arduino IDE / arduino-cli
// See main.cpp
//
// !!! This file is only for Arduino IDE / arduino-cli compatibility !!!
// !!! See main{.h,.cpp} !!!
#include "espurna.h"
#include "alexa.h"
#include "api.h"
#include "broker.h"
#include "button.h"
#include "crash.h"
#include "debug.h"
#include "domoticz.h"
#include "homeassistant.h"
#include "i2c.h"
#include "influxdb.h"
#include "ir.h"
#include "led.h"
#include "light.h"
#include "llmnr.h"
#include "mdns.h"
#include "mqtt.h"
#include "netbios.h"
#include "nofuss.h"
#include "ntp.h"
#include "ota.h"
#include "relay.h"
#include "rfbridge.h"
#include "rfm69.h"
#include "rpc.h"
#include "rpnrules.h"
#include "rtcmem.h"
#include "scheduler.h"
#include "sensor.h"
#include "ssdp.h"
#include "telnet.h"
#include "thermostat.h"
#include "thingspeak.h"
#include "tuya.h"
#include "uartmqtt.h"
#include "web.h"
#include "ws.h"
#include "main.h"

+ 0
- 1
code/espurna/garland/animations/anim_spread.h View File

@ -3,7 +3,6 @@
#include "../anim.h"
#include "../color.h"
#include "../palette.h"
#include "debug.h"
//------------------------------------------------------------------------------
class AnimSpread : public Anim {


+ 19
- 7
code/espurna/gpio.h View File

@ -8,9 +8,11 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#pragma once
#include "espurna.h"
#include "settings.h"
#include "libs/BasePin.h"
#include <cstddef>
enum class GpioType : int {
None,
Hardware,
@ -19,14 +21,24 @@ enum class GpioType : int {
class GpioBase {
public:
virtual const char* id() const = 0;
virtual size_t pins() const = 0;
virtual bool lock(unsigned char index) const = 0;
virtual void lock(unsigned char index, bool value) = 0;
virtual bool valid(unsigned char index) const = 0;
virtual BasePinPtr pin(unsigned char index) = 0;
virtual const char* id() const = 0;
virtual size_t pins() const = 0;
virtual bool lock(unsigned char index) const = 0;
virtual void lock(unsigned char index, bool value) = 0;
virtual bool valid(unsigned char index) const = 0;
virtual BasePinPtr pin(unsigned char index) = 0;
};
namespace settings {
namespace internal {
template <>
GpioType convert(const String& value);
} // namespace internal
} // namespace settings
GpioBase& hardwareGpio();
GpioBase* gpioBase(GpioType);


+ 20
- 15
code/espurna/homeassistant.cpp View File

@ -50,11 +50,15 @@ String _haFixPayload(const String& value) {
return value;
}
String& _haFixName(String& name) {
for (unsigned char i=0; i<name.length(); i++) {
if (!isalnum(name.charAt(i))) name.setCharAt(i, '_');
String _haFixName(String&& name) {
auto* ptr = const_cast<char*>(name.c_str());
while (*ptr != '\0') {
if (!isalnum(*ptr)) {
*ptr = '_';
}
++ptr;
}
return name;
return std::move(name);
}
#if (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE) || (defined(ITEAD_SLAMPHER))
@ -75,7 +79,7 @@ struct ha_config_t {
jsonBuffer(size),
deviceConfig(jsonBuffer.createObject()),
root(jsonBuffer.createObject()),
name(getSetting("desc", getSetting("hostname"))),
name(getSetting("desc", getSetting("hostname", getIdentifier()))),
identifier(getIdentifier().c_str()),
version(getVersion().c_str()),
manufacturer(getManufacturer().c_str()),
@ -126,9 +130,9 @@ struct ha_discovery_t {
DEBUG_MSG_P(PSTR("[HA] Discovery %s\n"), empty() ? "OK" : "FAILED");
}
// TODO: is this expected behaviour?
void add(String& topic, String& message) {
_messages.emplace_back(std::move(topic), std::move(message));
auto msg = mqtt_msg_t { std::move(topic), std::move(message) };
_messages.push_back(std::move(msg));
}
// We don't particulary care about the order since names have indexes?
@ -181,7 +185,7 @@ void _haSendDiscovery() {
if (_ha_discovery->empty()) break;
auto& message = _ha_discovery->next();
if (!mqttSendRaw(message.first.c_str(), message.second.c_str())) {
if (!mqttSendRaw(message.topic.c_str(), message.message.c_str())) {
break;
}
_ha_discovery->pop();
@ -210,7 +214,7 @@ void _haSendDiscovery() {
#if SENSOR_SUPPORT
void _haSendMagnitude(unsigned char index, JsonObject& config) {
config["name"] = _haFixName(getSetting("hostname") + String(" ") + magnitudeTopic(magnitudeType(index)));
config["name"] = _haFixName(getSetting("hostname", getIdentifier()) + String(" ") + magnitudeTopic(magnitudeType(index)));
config["state_topic"] = mqttTopic(magnitudeTopicIndex(index).c_str(), false);
config["unit_of_measurement"] = magnitudeUnits(index);
}
@ -224,7 +228,7 @@ void ha_discovery_t::prepareMagnitudes(ha_config_t& config) {
String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) +
"/sensor/" +
getSetting("hostname") + "_" + String(i) +
getSetting("hostname", getIdentifier()) + "_" + String(i) +
"/config";
String message;
@ -251,12 +255,13 @@ void ha_discovery_t::prepareMagnitudes(ha_config_t& config) {
void _haSendSwitch(unsigned char i, JsonObject& config) {
String name = getSetting("hostname");
String name = _haFixName(getSetting("hostname", getIdentifier()));
if (relayCount() > 1) {
name += String("_") + String(i);
name += '_';
name += i;
}
config.set("name", _haFixName(name));
config.set("name", name);
if (relayCount()) {
config["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, false);
@ -304,7 +309,7 @@ void ha_discovery_t::prepareSwitches(ha_config_t& config) {
String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) +
"/" + switchType +
"/" + getSetting("hostname") + "_" + String(i) +
"/" + getSetting("hostname", getIdentifier()) + "_" + String(i) +
"/config";
String message;
@ -401,7 +406,7 @@ void _haSensorYaml(unsigned char index, JsonObject& root) {
void _haGetDeviceConfig(JsonObject& config) {
config.createNestedArray("identifiers").add(getIdentifier().c_str());
config["name"] = getSetting("desc", getSetting("hostname"));
config["name"] = getSetting("desc", getSetting("hostname", getIdentifier()));
config["manufacturer"] = getManufacturer().c_str();
config["model"] = getDevice().c_str();
config["sw_version"] = getVersion().c_str();


+ 33
- 2
code/espurna/influxdb.cpp View File

@ -14,13 +14,14 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <memory>
#include "broker.h"
#include "mqtt.h"
#include "rpc.h"
#include "sensor.h"
#include "terminal.h"
#include "ws.h"
#include "libs/AsyncClientHelpers.h"
#include <ESPAsyncTCP.h>
#include "libs/AsyncClientHelpers.h"
const char InfluxDb_http_success[] = "HTTP/1.1 204";
const char InfluxDb_http_template[] PROGMEM = "POST /write?db=%s&u=%s&p=%s HTTP/1.1\r\nHost: %s:%u\r\nContent-Length: %d\r\n\r\n";
@ -249,7 +250,38 @@ bool idbEnabled() {
return _idb_enabled;
}
bool _idbHeartbeat(heartbeat::Mask mask) {
if (mask & heartbeat::Report::Uptime)
idbSend(MQTT_TOPIC_UPTIME, String(systemUptime()).c_str());
if (mask & heartbeat::Report::Freeheap) {
auto stats = systemHeapStats();
idbSend(MQTT_TOPIC_FREEHEAP, String(stats.available).c_str());
}
if (mask & heartbeat::Report::Rssi)
idbSend(MQTT_TOPIC_RSSI, String(WiFi.RSSI()).c_str());
if ((mask & heartbeat::Report::Vcc) && (ADC_MODE_VALUE == ADC_VCC))
idbSend(MQTT_TOPIC_VCC, String(ESP.getVcc()).c_str());
if (mask & heartbeat::Report::Loadavg)
idbSend(MQTT_TOPIC_LOADAVG, String(systemLoadAverage()).c_str());
if (mask & heartbeat::Report::Ssid)
idbSend(MQTT_TOPIC_SSID, WiFi.SSID().c_str());
if (mask & heartbeat::Report::Bssid)
idbSend(MQTT_TOPIC_BSSID, WiFi.BSSIDstr().c_str());
return true;
}
void idbSetup() {
systemHeartbeat(_idbHeartbeat);
systemHeartbeat(_idbHeartbeat,
getSetting("idbHbMode", heartbeat::currentMode()),
getSetting("idbHbIntvl", heartbeat::currentInterval()));
_idbConfigure();
@ -279,7 +311,6 @@ void idbSetup() {
idbSend(ctx.argv[1].c_str(), ctx.argv[2].toInt(), ctx.argv[3].c_str());
});
#endif
}
#endif

+ 6
- 0
code/espurna/ir.cpp View File

@ -50,6 +50,12 @@ Raw messages:
#if IR_SUPPORT
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRsend.h>
#include "ir_button.h"
#include "light.h"
#include "mqtt.h"
#include "relay.h"


+ 0
- 10
code/espurna/ir.h View File

@ -12,14 +12,4 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "espurna.h"
#if IR_SUPPORT
#include "ir_button.h"
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRsend.h>
void irSetup();
#endif // IR_SUPPORT == 1

+ 0
- 1
code/espurna/led.h View File

@ -11,7 +11,6 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "espurna.h"
#include <vector>
#include <memory>
constexpr size_t LedsMax = 8;


+ 32
- 13
code/espurna/light.cpp View File

@ -277,19 +277,25 @@ void _lightApplyBrightnessColor() {
}
String lightDesc(unsigned char id) {
if (id >= _light_channels.size()) return FPSTR(pstr_unknown);
const char tag = pgm_read_byte(&_light_channel_desc[_light_channels.size() - 1][id]);
switch (tag) {
case 'W': return F("WARM WHITE");
case 'C': return F("COLD WHITE");
case 'R': return F("RED");
case 'G': return F("GREEN");
case 'B': return F("BLUE");
default: break;
if (id < _light_channels.size()) {
const char tag = pgm_read_byte(&_light_channel_desc[_light_channels.size() - 1][id]);
switch (tag) {
case 'W':
return F("WARM WHITE");
case 'C':
return F("COLD WHITE");
case 'R':
return F("RED");
case 'G':
return F("GREEN");
case 'B':
return F("BLUE");
default:
break;
}
}
return FPSTR(pstr_unknown);
return F("UNKNOWN");
}
// -----------------------------------------------------------------------------
@ -939,7 +945,15 @@ void _lightUpdateFromMqttGroup() {
}
#if MQTT_SUPPORT
void _lightMQTTCallback(unsigned int type, const char * topic, const char * payload) {
bool _lightMqttHeartbeat(heartbeat::Mask mask) {
if (mask & heartbeat::Report::Light)
lightMQTT();
return mqttConnected();
}
void _lightMqttCallback(unsigned int type, const char * topic, const char * payload) {
String mqtt_group_color = getSetting("mqttGroupColor");
@ -1046,6 +1060,11 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl
}
void _lightMqttSetup() {
mqttHeartbeat(_lightMqttHeartbeat);
mqttRegister(_lightMqttCallback);
}
void lightMQTT() {
char buffer[20];
@ -1851,7 +1870,7 @@ void lightSetup() {
#endif
#if MQTT_SUPPORT
mqttRegister(_lightMQTTCallback);
_lightMqttSetup();
#endif
#if TERMINAL_SUPPORT


+ 11
- 0
code/espurna/light.h View File

@ -6,6 +6,17 @@
#include "espurna.h"
#define MQTT_TOPIC_LIGHT "light"
#define MQTT_TOPIC_CHANNEL "channel"
#define MQTT_TOPIC_COLOR_RGB "rgb"
#define MQTT_TOPIC_COLOR_HSV "hsv"
#define MQTT_TOPIC_ANIM_MODE "anim_mode"
#define MQTT_TOPIC_ANIM_SPEED "anim_speed"
#define MQTT_TOPIC_BRIGHTNESS "brightness"
#define MQTT_TOPIC_MIRED "mired"
#define MQTT_TOPIC_KELVIN "kelvin"
#define MQTT_TOPIC_TRANSITION "transition"
// TODO: lowercase
namespace Light {


+ 5
- 2
code/espurna/llmnr.cpp View File

@ -10,9 +10,12 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if LLMNR_SUPPORT
#include <ESP8266LLMNR.h>
void llmnrSetup() {
LLMNR.begin(getSetting("hostname").c_str());
DEBUG_MSG_P(PSTR("[LLMNR] Configured\n"));
auto hostname = getSetting("hostname", getIdentifier());
LLMNR.begin(hostname.c_str());
DEBUG_MSG_P(PSTR("[LLMNR] Configured for %s\n"), hostname.c_str());
}
#endif // LLMNR_SUPPORT

+ 0
- 5
code/espurna/llmnr.h View File

@ -8,9 +8,4 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "espurna.h"
#if LLMNR_SUPPORT
#include <ESP8266LLMNR.h>
void llmnrSetup();
#endif // LLMNR_SUPPORT

+ 33
- 72
code/espurna/main.cpp View File

@ -3,6 +3,7 @@
ESPurna
Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2019-2021 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,66 +21,26 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "espurna.h"
#include "main.h"
#include "alexa.h"
#include "api.h"
#include "broker.h"
#include "button.h"
#include "crash.h"
#include "curtain_kingart.h"
#include "debug.h"
#include "domoticz.h"
#include "encoder.h"
#include "homeassistant.h"
#include "garland.h"
#include "i2c.h"
#include "influxdb.h"
#include "fan.h"
#include "ir.h"
#include "led.h"
#include "light.h"
#include "lightfox.h"
#include "llmnr.h"
#include "mdns.h"
#include "mqtt.h"
#include "netbios.h"
#include "nofuss.h"
#include "ntp.h"
#include "ota.h"
#include "relay.h"
#include "rfbridge.h"
#include "rfm69.h"
#include "rpc.h"
#include "rpnrules.h"
#include "rtcmem.h"
#include "scheduler.h"
#include "sensor.h"
#include "ssdp.h"
#include "telnet.h"
#include "thermostat.h"
#include "thingspeak.h"
#include "tuya.h"
#include "uartmqtt.h"
#include "web.h"
#include "ws.h"
#include "mcp23s08.h"
#include "prometheus.h"
std::vector<void_callback_f> _loop_callbacks;
std::vector<void_callback_f> _reload_callbacks;
std::vector<LoopCallback> _loop_callbacks;
std::vector<LoopCallback> _reload_callbacks;
bool _reload_config = false;
unsigned long _loop_delay = 0;
constexpr unsigned long LoopDelayMin { 10ul };
constexpr unsigned long LoopDelayMax { 300ul };
// -----------------------------------------------------------------------------
// GENERAL CALLBACKS
// -----------------------------------------------------------------------------
void espurnaRegisterLoop(void_callback_f callback) {
void espurnaRegisterLoop(LoopCallback callback) {
_loop_callbacks.push_back(callback);
}
void espurnaRegisterReload(void_callback_f callback) {
void espurnaRegisterReload(LoopCallback callback) {
_reload_callbacks.push_back(callback);
}
@ -97,6 +58,14 @@ unsigned long espurnaLoopDelay() {
return _loop_delay;
}
void espurnaLoopDelay(unsigned long loop_delay) {
_loop_delay = loop_delay;
}
constexpr unsigned long _loopDelay() {
return LOOP_DELAY_TIME;
}
// -----------------------------------------------------------------------------
// BOOTING
// -----------------------------------------------------------------------------
@ -108,7 +77,7 @@ void setup() {
// -------------------------------------------------------------------------
// Cache initial free heap value
setInitialFreeHeap();
systemInitialFreeHeap();
// Init logging module
#if DEBUG_SUPPORT
@ -133,10 +102,6 @@ void setup() {
crashSetup();
#endif
// Return bogus free heap value for broken devices
// XXX: device is likely to trigger other bugs! tread carefuly
wtfHeap(getSetting("wtfHeap", 0));
// Init Serial, SPIFFS and system check
systemSetup();
@ -308,44 +273,40 @@ void setup() {
#if FAN_SUPPORT
fanSetup();
#endif
#if GARLAND_SUPPORT
garlandSetup();
#endif
// 3rd party code hook
#if USE_EXTRA
extraSetup();
#endif
#if GARLAND_SUPPORT
garlandSetup();
#endif
// Prepare configuration for version 2.0
// Update `cfg` version
migrate();
// Set up delay() after loop callbacks are finished
// Note: should be after settingsSetup()
_loop_delay = constrain(
getSetting("loopDelay", LOOP_DELAY_TIME), 0, 300
);
saveSettings();
unsigned long loop_delay { getSetting("loopDelay", _loopDelay()) };
_loop_delay = ((LoopDelayMin < loop_delay) && (loop_delay <= LoopDelayMax))
? loop_delay : LoopDelayMin;
if (_loop_delay != loop_delay) {
setSetting("loopDelay", _loop_delay);
}
}
void loop() {
// Reload config before running any callbacks
if (_reload_config) {
_espurnaReload();
_reload_config = false;
}
// Call registered loop callbacks
for (unsigned char i = 0; i < _loop_callbacks.size(); i++) {
(_loop_callbacks[i])();
for (auto* callback : _loop_callbacks) {
callback();
}
// Power saving delay
if (_loop_delay) delay(_loop_delay);
if (_loop_delay) {
delay(_loop_delay);
}
}

+ 65
- 0
code/espurna/main.h View File

@ -0,0 +1,65 @@
/*
ESPurna
Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2019-2021 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "alexa.h"
#include "api.h"
#include "broker.h"
#include "button.h"
#include "crash.h"
#include "curtain_kingart.h"
#include "debug.h"
#include "domoticz.h"
#include "encoder.h"
#include "homeassistant.h"
#include "garland.h"
#include "i2c.h"
#include "influxdb.h"
#include "fan.h"
#include "ir.h"
#include "led.h"
#include "light.h"
#include "lightfox.h"
#include "llmnr.h"
#include "mdns.h"
#include "mqtt.h"
#include "netbios.h"
#include "nofuss.h"
#include "ntp.h"
#include "ota.h"
#include "relay.h"
#include "rfbridge.h"
#include "rfm69.h"
#include "rpc.h"
#include "rpnrules.h"
#include "rtcmem.h"
#include "scheduler.h"
#include "sensor.h"
#include "ssdp.h"
#include "telnet.h"
#include "thermostat.h"
#include "thingspeak.h"
#include "tuya.h"
#include "uartmqtt.h"
#include "web.h"
#include "ws.h"
#include "mcp23s08.h"
#include "prometheus.h"

+ 1
- 0
code/espurna/migrate.cpp View File

@ -7,6 +7,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include "settings.h"
#include "config/version.h"
#include <vector>
#include <utility>


+ 109
- 20
code/espurna/mqtt.cpp View File

@ -12,6 +12,7 @@ Updated secure client support by Niek van der Maas < mail at niekvandermaas dot
#if MQTT_SUPPORT
#include <vector>
#include <forward_list>
#include <utility>
#include <Ticker.h>
@ -92,10 +93,14 @@ String _mqtt_server;
uint16_t _mqtt_port;
String _mqtt_clientid;
std::forward_list<heartbeat::Callback> _mqtt_heartbeat_callbacks;
heartbeat::Mode _mqtt_heartbeat_mode;
heartbeat::Seconds _mqtt_heartbeat_interval;
String _mqtt_payload_online;
String _mqtt_payload_offline;
std::vector<mqtt_callback_f> _mqtt_callbacks;
std::forward_list<mqtt_callback_f> _mqtt_callbacks;
struct mqtt_message_t {
static const unsigned char END = 255;
@ -331,10 +336,7 @@ void _mqttConfigure() {
_mqttApplySetting(_mqtt_retain, retain);
_mqttApplySetting(_mqtt_keepalive, keepalive);
_mqttApplySetting(_mqtt_clientid, id);
}
// MQTT WILL
{
_mqttApplyTopic(_mqtt_will, MQTT_TOPIC_STATUS);
}
@ -344,6 +346,11 @@ void _mqttConfigure() {
_mqttApplyTopic(_mqtt_topic_json, MQTT_TOPIC_JSON);
}
_mqttApplySetting(_mqtt_heartbeat_mode,
getSetting("mqttHbMode", heartbeat::currentMode()));
_mqttApplySetting(_mqtt_heartbeat_interval,
getSetting("mqttHbIntvl", heartbeat::currentInterval()));
// Skip messages in a small window right after the connection
_mqtt_skip_time = getSetting("mqttSkipTime", MQTT_SKIP_TIME);
@ -509,29 +516,104 @@ void _mqttInitCommands() {
// -----------------------------------------------------------------------------
void _mqttCallback(unsigned int type, const char * topic, const char * payload) {
if (type == MQTT_CONNECT_EVENT) {
// Subscribe to internal action topics
mqttSubscribe(MQTT_TOPIC_ACTION);
// Flag system to send heartbeat
systemSendHeartbeat();
}
if (type == MQTT_MESSAGE_EVENT) {
// Match topic
String t = mqttMagnitude(topic);
// Actions
if (t.equals(MQTT_TOPIC_ACTION)) {
rpcHandleAction(payload);
}
}
}
bool _mqttHeartbeat(heartbeat::Mask mask) {
// Backported from the older utils implementation.
// Wait until the time is synced to avoid sending partial report *and*
// as a result, wait until the next interval to actually send the datetime string.
#if NTP_SUPPORT
if ((mask & heartbeat::Report::Datetime) && !ntpSynced()) {
return false;
}
#endif
if (!mqttConnected()) {
return false;
}
// TODO: rework old HEARTBEAT_REPEAT_STATUS?
// for example: send full report once, send only the dynamic data after that
// (interval, hostname, description, ssid, bssid, ip, mac, rssi, uptime, datetime, heap, loadavg, vcc)
// otherwise, it is still possible by setting everything to 0 *but* the Report::Status bit
// TODO: per-module mask?
// TODO: simply send static data with onConnected, and the rest from here?
if (mask & heartbeat::Report::Status)
mqttSendStatus();
if (mask & heartbeat::Report::Interval)
mqttSend(MQTT_TOPIC_INTERVAL, String(_mqtt_heartbeat_interval.count()).c_str());
if (mask & heartbeat::Report::App)
mqttSend(MQTT_TOPIC_APP, APP_NAME);
if (mask & heartbeat::Report::Version)
mqttSend(MQTT_TOPIC_VERSION, getVersion().c_str());
if (mask & heartbeat::Report::Board)
mqttSend(MQTT_TOPIC_BOARD, getBoardName().c_str());
if (mask & heartbeat::Report::Hostname)
mqttSend(MQTT_TOPIC_HOSTNAME, getSetting("hostname", getIdentifier()).c_str());
if (mask & heartbeat::Report::Description) {
auto desc = getSetting("desc");
if (desc.length()) {
mqttSend(MQTT_TOPIC_DESCRIPTION, desc.c_str());
}
}
if (mask & heartbeat::Report::Ssid)
mqttSend(MQTT_TOPIC_SSID, WiFi.SSID().c_str());
if (mask & heartbeat::Report::Bssid)
mqttSend(MQTT_TOPIC_BSSID, WiFi.BSSIDstr().c_str());
if (mask & heartbeat::Report::Ip)
mqttSend(MQTT_TOPIC_IP, getIP().c_str());
if (mask & heartbeat::Report::Mac)
mqttSend(MQTT_TOPIC_MAC, WiFi.macAddress().c_str());
if (mask & heartbeat::Report::Rssi)
mqttSend(MQTT_TOPIC_RSSI, String(WiFi.RSSI()).c_str());
if (mask & heartbeat::Report::Uptime)
mqttSend(MQTT_TOPIC_UPTIME, String(systemUptime()).c_str());
#if NTP_SUPPORT
if (mask & heartbeat::Report::Datetime)
mqttSend(MQTT_TOPIC_DATETIME, ntpDateTime().c_str());
#endif
if (mask & heartbeat::Report::Freeheap) {
auto stats = systemHeapStats();
mqttSend(MQTT_TOPIC_FREEHEAP, String(stats.available).c_str());
}
if (mask & heartbeat::Report::Loadavg)
mqttSend(MQTT_TOPIC_LOADAVG, String(systemLoadAverage()).c_str());
if ((mask & heartbeat::Report::Vcc) && (ADC_MODE_VALUE == ADC_VCC))
mqttSend(MQTT_TOPIC_VCC, String(ESP.getVcc()).c_str());
auto status = mqttConnected();
for (auto& cb : _mqtt_heartbeat_callbacks) {
status = status && cb(mask);
}
return status;
}
void _mqttOnConnect() {
@ -541,6 +623,8 @@ void _mqttOnConnect() {
_mqtt_last_connection = millis();
_mqtt_state = AsyncClientState::Connected;
systemHeartbeat(_mqttHeartbeat, _mqtt_heartbeat_mode, _mqtt_heartbeat_interval);
DEBUG_MSG_P(PSTR("[MQTT] Connected!\n"));
// Clean subscriptions
@ -559,6 +643,8 @@ void _mqttOnDisconnect() {
_mqtt_last_connection = millis();
_mqtt_state = AsyncClientState::Disconnected;
systemStopHeartbeat(_mqttHeartbeat);
DEBUG_MSG_P(PSTR("[MQTT] Disconnected!\n"));
// Notify all subscribers about the disconnect
@ -937,7 +1023,7 @@ bool mqttForward() {
}
void mqttRegister(mqtt_callback_f callback) {
_mqtt_callbacks.push_back(callback);
_mqtt_callbacks.push_front(callback);
}
void mqttSetBroker(IPAddress ip, uint16_t port) {
@ -997,12 +1083,12 @@ void _mqttConnect() {
_mqtt_server = mdnsResolve(_mqtt_server);
#endif
DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%u\n"), _mqtt_server.c_str(), _mqtt_port);
DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%hu\n"), _mqtt_server.c_str(), _mqtt_port);
DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid.c_str());
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0);
DEBUG_MSG_P(PSTR("[MQTT] Keepalive time: %ds\n"), _mqtt_keepalive);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %c\n"), _mqtt_retain ? 'Y' : 'N');
DEBUG_MSG_P(PSTR("[MQTT] Keepalive time: %hu (s)\n"), _mqtt_keepalive);
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will.c_str());
_mqtt_state = AsyncClientState::Connecting;
@ -1058,6 +1144,10 @@ void mqttLoop() {
}
void mqttHeartbeat(heartbeat::Callback callback) {
_mqtt_heartbeat_callbacks.push_front(callback);
}
void mqttSetup() {
_mqttBackwards();
@ -1092,7 +1182,6 @@ void mqttSetup() {
});
_mqtt.onDisconnect([](AsyncMqttClientDisconnectReason reason) {
switch (reason) {
case AsyncMqttClientDisconnectReason::TCP_DISCONNECTED:
DEBUG_MSG_P(PSTR("[MQTT] TCP Disconnected\n"));


+ 47
- 8
code/espurna/mqtt.h View File

@ -11,16 +11,57 @@ Updated secure client support by Niek van der Maas < mail at niekvandermaas dot
#include "espurna.h"
#include <WString.h>
#include <utility>
#include <functional>
using mqtt_callback_f = std::function<void(unsigned int type, const char * topic, char * payload)>;
using mqtt_msg_t = std::pair<String, String>; // topic, payload
// These will be concatenated to the MQTT_TOPIC base to form the actual topic
#define MQTT_TOPIC_JSON "data"
#define MQTT_TOPIC_ACTION "action"
#define MQTT_TOPIC_RELAY "relay"
#define MQTT_TOPIC_LED "led"
#define MQTT_TOPIC_BUTTON "button"
#define MQTT_TOPIC_IP "ip"
#define MQTT_TOPIC_SSID "ssid"
#define MQTT_TOPIC_BSSID "bssid"
#define MQTT_TOPIC_VERSION "version"
#define MQTT_TOPIC_UPTIME "uptime"
#define MQTT_TOPIC_DATETIME "datetime"
#define MQTT_TOPIC_TIMESTAMP "timestamp"
#define MQTT_TOPIC_FREEHEAP "freeheap"
#define MQTT_TOPIC_VCC "vcc"
#define MQTT_TOPIC_STATUS "status"
#define MQTT_TOPIC_MAC "mac"
#define MQTT_TOPIC_RSSI "rssi"
#define MQTT_TOPIC_MESSAGE_ID "id"
#define MQTT_TOPIC_APP "app"
#define MQTT_TOPIC_INTERVAL "interval"
#define MQTT_TOPIC_HOSTNAME "host"
#define MQTT_TOPIC_DESCRIPTION "desc"
#define MQTT_TOPIC_TIME "time"
#define MQTT_TOPIC_RFOUT "rfout"
#define MQTT_TOPIC_RFIN "rfin"
#define MQTT_TOPIC_RFLEARN "rflearn"
#define MQTT_TOPIC_RFRAW "rfraw"
#define MQTT_TOPIC_UARTIN "uartin"
#define MQTT_TOPIC_UARTOUT "uartout"
#define MQTT_TOPIC_LOADAVG "loadavg"
#define MQTT_TOPIC_BOARD "board"
#define MQTT_TOPIC_PULSE "pulse"
#define MQTT_TOPIC_SPEED "speed"
#define MQTT_TOPIC_IRIN "irin"
#define MQTT_TOPIC_IROUT "irout"
#define MQTT_TOPIC_OTA "ota"
#define MQTT_TOPIC_TELNET_REVERSE "telnet_reverse"
#define MQTT_TOPIC_CURTAIN "curtain"
#define MQTT_TOPIC_CMD "cmd"
#if MQTT_SUPPORT
using mqtt_callback_f = std::function<void(unsigned int type, const char * topic, char * payload)>;
struct mqtt_msg_t {
String topic;
String message;
};
void mqttHeartbeat(heartbeat::Callback);
void mqttRegister(mqtt_callback_f callback);
String mqttTopic(const char * magnitude, bool is_set);
@ -67,5 +108,3 @@ bool mqttConnected();
void mqttDisconnect();
void mqttSetup();
#endif // MQTT_SUPPORT == 1

+ 5
- 2
code/espurna/netbios.cpp View File

@ -10,10 +10,13 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if NETBIOS_SUPPORT
#include <ESP8266NetBIOS.h>
void netbiosSetup() {
static WiFiEventHandler _netbios_wifi_onSTA = WiFi.onStationModeGotIP([](WiFiEventStationModeGotIP ipInfo) {
NBNS.begin(getSetting("hostname").c_str());
DEBUG_MSG_P(PSTR("[NETBIOS] Configured\n"));
auto hostname = getSetting("hostname", getIdentifier());
NBNS.begin(hostname.c_str());
DEBUG_MSG_P(PSTR("[NETBIOS] Configured for %s\n"), hostname.c_str());
});
}


+ 0
- 6
code/espurna/netbios.h View File

@ -8,10 +8,4 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "espurna.h"
#if NETBIOS_SUPPORT
#include <ESP8266NetBIOS.h>
void netbiosSetup();
#endif // NETBIOS_SUPPORT

+ 2
- 0
code/espurna/nofuss.cpp View File

@ -15,6 +15,8 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "terminal.h"
#include "ws.h"
#include <NoFUSSClient.h>
unsigned long _nofussLastCheck = 0;
unsigned long _nofussInterval = 0;
bool _nofussEnabled = false;


+ 0
- 6
code/espurna/nofuss.h View File

@ -8,10 +8,4 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "espurna.h"
#if NOFUSS_SUPPORT
#include <NoFUSSClient.h>
void nofussSetup();
#endif // NOFUSS_SUPPORT

+ 19
- 10
code/espurna/ntp.cpp View File

@ -19,13 +19,17 @@ Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#include <coredecls.h>
#include <Ticker.h>
#include <lwip/apps/sntp.h>
#include <TZ.h>
static_assert(
(SNTP_SERVER_DNS == 1),
"lwip must be configured with SNTP_SERVER_DNS"
);
#include "config/buildtime.h"
#include "debug.h"
#include "ntp_timelib.h"
#include "broker.h"
#include "ws.h"
@ -228,12 +232,16 @@ void _ntpConfigure() {
// Note: TZ_... provided by the Core are already wrapped with PSTR(...)
// but, String() already handles every char pointer as a flash-string
const auto cfg_tz = getSetting("ntpTZ", NTP_TIMEZONE);
auto cfg_tz = getSetting("ntpTZ", NTP_TIMEZONE);
const char* active_tz = getenv("TZ");
bool changed = cfg_tz != active_tz;
if (changed) {
setenv("TZ", cfg_tz.c_str(), 1);
if (cfg_tz.length()) {
setenv("TZ", cfg_tz.c_str(), 1);
} else {
unsetenv("TZ");
}
tzset();
}
@ -248,7 +256,8 @@ void _ntpConfigure() {
_ntp_server = cfg_server;
sntp_setservername(0, _ntp_server.c_str());
sntp_init();
DEBUG_MSG_P(PSTR("[NTP] Server: %s, TZ: %s\n"), cfg_server.c_str(), cfg_tz.length() ? cfg_tz.c_str() : "UTC0");
DEBUG_MSG_P(PSTR("[NTP] Server: %s, TZ: %s\n"), cfg_server.c_str(),
cfg_tz.length() ? cfg_tz.c_str() : "UTC0");
}
}
@ -259,7 +268,7 @@ bool ntpSynced() {
}
String ntpDateTime(tm* timestruct) {
char buffer[20];
char buffer[32];
snprintf_P(buffer, sizeof(buffer),
PSTR("%04d-%02d-%02d %02d:%02d:%02d"),
timestruct->tm_year + 1900,
@ -311,6 +320,7 @@ void _ntpBrokerCallback() {
static int last_minute = -1;
String datetime;
if ((last_minute != now_minute) || (last_hour != now_hour)) {
datetime = ntpDateTime(&local_tm);
}
@ -318,12 +328,12 @@ void _ntpBrokerCallback() {
// notify subscribers about each tick interval (note that both can happen simultaneously)
if (last_hour != now_hour) {
last_hour = now_hour;
NtpBroker::Publish(NtpTick::EveryHour, ts, datetime.c_str());
NtpBroker::Publish(NtpTick::EveryHour, ts, datetime);
}
if (last_minute != now_minute) {
last_minute = now_minute;
NtpBroker::Publish(NtpTick::EveryMinute, ts, datetime.c_str());
NtpBroker::Publish(NtpTick::EveryMinute, ts, datetime);
}
// try to autocorrect each invocation
@ -422,9 +432,8 @@ void ntpSetup() {
_ntp_startup_delay = secureRandom(startup_delay, startup_delay * 2);
_ntp_update_delay = secureRandom(update_delay, update_delay * 2);
DEBUG_MSG_P(PSTR("[NTP] Startup delay: %us, Update delay: %us\n"),
_ntp_startup_delay, _ntp_update_delay
);
DEBUG_MSG_P(PSTR("[NTP] Startup delay: %u (s), Update delay: %u (s)\n"),
_ntp_startup_delay, _ntp_update_delay);
_ntp_startup_delay = _ntp_startup_delay * 1000;
_ntp_update_delay = _ntp_update_delay * 1000;


+ 7
- 23
code/espurna/ntp.h View File

@ -2,34 +2,16 @@
NTP MODULE
Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2019-2021 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
*/
#pragma once
#include "espurna.h"
#if NTP_SUPPORT
#include "broker.h"
#if NTP_LEGACY_SUPPORT // Use legacy TimeLib and NtpClientLib
#include <TimeLib.h>
#include <WiFiUdp.h>
#include <NtpClientLib.h>
time_t ntpLocal2UTC(time_t local);
#else // POSIX time functions + configTime(...)
#include <lwip/apps/sntp.h>
#include <TZ.h>
#include "ntp_timelib.h"
#endif
// --- rest of the module is ESPurna functions
enum class NtpTick {
EveryMinute,
EveryHour
@ -56,11 +38,13 @@ BrokerDeclare(NtpBroker, void(NtpTick, time_t, const String&));
NtpInfo ntpInfo();
#if NTP_LEGACY_SUPPORT
time_t ntpLocal2UTC(time_t local);
#endif
String ntpDateTime(tm* timestruct);
String ntpDateTime(time_t ts);
String ntpDateTime();
bool ntpSynced();
void ntpSetup();
#endif // NTP_SUPPORT

+ 4
- 0
code/espurna/ntp_legacy.cpp View File

@ -10,6 +10,10 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if NTP_LEGACY_SUPPORT && NTP_SUPPORT
#include <TimeLib.h>
#include <WiFiUdp.h>
#include <NtpClientLib.h>
#include <Ticker.h>
#include "debug.h"


+ 0
- 1
code/espurna/ntp_timelib.h View File

@ -39,4 +39,3 @@ int month();
int year();
time_t now();

+ 0
- 6
code/espurna/ota.h View File

@ -28,16 +28,10 @@ void otaClientSetup();
#if OTA_CLIENT == OTA_CLIENT_HTTPUPDATE
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
void otaClientSetup();
#endif // OTA_CLIENT == OTA_CLIENT_HTTPUPDATE
#if SECURE_CLIENT != SECURE_CLIENT_NONE
#include <WiFiClientSecure.h>
#endif
void otaSetup();
void otaPrintError();
bool otaFinalize(size_t size, CustomResetReason reason, bool evenIfRemaining = false);


+ 10
- 6
code/espurna/ota_httpupdate.cpp View File

@ -20,18 +20,22 @@ Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#include "system.h"
#include "terminal.h"
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include "libs/URL.h"
#include "libs/TypeChecks.h"
#include "libs/SecureClientHelpers.h"
#if SECURE_CLIENT != SECURE_CLIENT_NONE
#include <WiFiClientSecure.h>
#if OTA_SECURE_CLIENT_INCLUDE_CA
#include "static/ota_client_trusted_root_ca.h"
#else
#include "static/digicert_evroot_pem.h"
#define _ota_client_trusted_root_ca _ssl_digicert_ev_root_ca
#endif
#if OTA_SECURE_CLIENT_INCLUDE_CA
#include "static/ota_client_trusted_root_ca.h"
#else
#include "static/digicert_evroot_pem.h"
#define _ota_client_trusted_root_ca _ssl_digicert_ev_root_ca
#endif
#endif // SECURE_CLIENT != SECURE_CLIENT_NONE


+ 8
- 7
code/espurna/relay.cpp View File

@ -1478,6 +1478,13 @@ void relayStatusWrap(unsigned char id, PayloadStatus value, bool is_group_topic)
}
}
bool _relayMqttHeartbeat(heartbeat::Mask mask) {
if (mask & heartbeat::Report::Relay)
relayMQTT();
return mqttConnected();
}
void relayMQTTCallback(unsigned int type, const char * topic, const char * payload) {
if (!relayCount()) {
@ -1485,12 +1492,6 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo
}
if (type == MQTT_CONNECT_EVENT) {
// Send status on connect
#if (HEARTBEAT_MODE == HEARTBEAT_NONE) or (not HEARTBEAT_REPORT_RELAY)
relayMQTT();
#endif
// Subscribe to own /set topic
char relay_topic[strlen(MQTT_TOPIC_RELAY) + 3];
snprintf_P(relay_topic, sizeof(relay_topic), PSTR("%s/+"), MQTT_TOPIC_RELAY);
@ -1506,7 +1507,6 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo
const auto t = getSetting({"mqttGroup", i});
if (t.length() > 0) mqttSubscribeRaw(t.c_str());
}
}
if (type == MQTT_MESSAGE_EVENT) {
@ -1583,6 +1583,7 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo
}
void relaySetupMQTT() {
mqttHeartbeat(_relayMqttHeartbeat);
mqttRegister(relayMQTTCallback);
}


+ 6
- 2
code/espurna/rfm69.cpp View File

@ -10,11 +10,15 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
#if RFM69_SUPPORT
#define RFM69_PACKET_SEPARATOR ':'
#include <RFM69.h>
#include <RFM69_ATC.h>
#include <SPI.h>
#include "mqtt.h"
#include "ws.h"
#define RFM69_PACKET_SEPARATOR ':'
// -----------------------------------------------------------------------------
// Locals
// -----------------------------------------------------------------------------


+ 0
- 8
code/espurna/rfm69.h View File

@ -10,12 +10,4 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
#include "espurna.h"
#if RFM69_SUPPORT
#include <RFM69.h>
#include <RFM69_ATC.h>
#include <SPI.h>
void rfm69Setup();
#endif // RFM69_SUPPORT == 1

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

@ -25,7 +25,7 @@ bool rpcHandleAction(const String& action) {
});
} else if (action.equals("heartbeat")) {
result = true;
schedule_function(heartbeat);
systemScheduleHeartbeat();
}
return result;
}


+ 1
- 0
code/espurna/rpnrules.cpp View File

@ -14,6 +14,7 @@ Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "light.h"
#include "mqtt.h"
#include "ntp.h"
#include "ntp_timelib.h"
#include "relay.h"
#include "rfbridge.h"
#include "rpc.h"


+ 7
- 5
code/espurna/scheduler.cpp View File

@ -14,11 +14,12 @@ Adapted by Xose Pérez <xose dot perez at gmail dot com>
#include "broker.h"
#include "light.h"
#include "ntp.h"
#include "ntp_timelib.h"
#include "relay.h"
#include "ws.h"
#include "curtain_kingart.h"
constexpr const int SchedulerDummySwitchId = 0xff;
constexpr int SchedulerDummySwitchId { 0xff };
int _sch_restore = 0;
@ -232,7 +233,6 @@ NtpCalendarWeekday _schGetWeekday(time_t timestamp, int daybefore) {
// If daybefore and relay is -1, check with current timestamp
// Otherwise, modify it by moving 'daybefore' days back and only use the 'relay' id
void _schCheck(int relay, int daybefore) {
time_t timestamp = now();
auto calendar_weekday = _schGetWeekday(timestamp, daybefore);
@ -341,10 +341,12 @@ void schSetup() {
.onKeyCheck(_schWebSocketOnKeyCheck);
#endif
NtpBroker::Register([](const NtpTick tick, time_t, const String&) {
if (NtpTick::EveryMinute != tick) return;
static bool restore_once = true;
NtpBroker::Register([](NtpTick tick, time_t, const String&) {
if (NtpTick::EveryMinute != tick) {
return;
}
static bool restore_once = true;
if (restore_once) {
for (unsigned char i = 0; i < schedulableCount(); i++) {
if (getSetting({"relayLastSch", i}, 1 == SCHEDULER_RESTORE_LAST_SCHEDULE)) {


+ 3
- 4
code/espurna/sensors/ADE7953Sensor.h View File

@ -8,13 +8,12 @@
#pragma once
#include <Arduino.h>
#include <Wire.h>
#include "BaseEmonSensor.h"
#include "I2CSensor.h"
#include "../utils.h"
#include "BaseEmonSensor.h"
#include "I2CSensor.h"
#include <Wire.h>
// -----------------------------------------------------------------------------
// ADE7953 - Energy (Shelly 2.5)


+ 0
- 2
code/espurna/sensors/AM2320Sensor.h View File

@ -7,8 +7,6 @@
#pragma once
#include <Arduino.h>
#include "I2CSensor.h"
// https://akizukidenshi.com/download/ds/aosong/AM2320.pdf


+ 0
- 4
code/espurna/sensors/AnalogSensor.h View File

@ -7,10 +7,6 @@
#pragma once
#include <Arduino.h>
#include "../debug.h"
#include "BaseSensor.h"
#include "BaseAnalogSensor.h"


+ 0
- 2
code/espurna/sensors/BH1750Sensor.h View File

@ -7,8 +7,6 @@
#pragma once
#include <Arduino.h>
#include "I2CSensor.h"
#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10 // Start measurement at 1lx resolution. Measurement time is approx 120ms.


+ 2
- 3
code/espurna/sensors/BME680Sensor.h View File

@ -48,11 +48,10 @@
#pragma once
#include <Arduino.h>
#include <bsec.h>
#include "I2CSensor.h"
#include <bsec.h>
// Available configuration modes based on parameters:
// voltage / maximum time between sensor calls / time considered
// for background calibration.


+ 0
- 2
code/espurna/sensors/BMP180Sensor.h View File

@ -7,8 +7,6 @@
#pragma once
#include <Arduino.h>
#include "I2CSensor.h"
#include "../utils.h"


+ 0
- 41
code/espurna/sensors/BMX280Sensor.h View File

@ -7,8 +7,6 @@
#pragma once
#include <Arduino.h>
#include "I2CSensor.h"
#include "../utils.h"
@ -156,45 +154,6 @@ class BMX280Sensor : public I2CSensor<> {
return 0;
}
// Load the configuration manifest
static void manifest(JsonArray& sensors) {
char buffer[10];
JsonObject& sensor = sensors.createNestedObject();
sensor["sensor_id"] = SENSOR_BMX280_ID;
JsonArray& fields = sensor.createNestedArray("fields");
{
JsonObject& field = fields.createNestedObject();
field["tag"] = UI_TAG_SELECT;
field["name"] = "address";
field["label"] = "Address";
JsonArray& options = field.createNestedArray("options");
{
JsonObject& option = options.createNestedObject();
option["name"] = "auto";
option["value"] = 0;
}
for (unsigned char i=0; i< sizeof(BMX280Sensor::addresses); i++) {
JsonObject& option = options.createNestedObject();
snprintf(buffer, sizeof(buffer), "0x%02X", BMX280Sensor::addresses[i]);
option["name"] = String(buffer);
option["value"] = BMX280Sensor::addresses[i];
}
}
};
void getConfig(JsonObject& root) {
root["sensor_id"] = _sensor_id;
root["address"] = _address;
};
void setConfig(JsonObject& root) {
if (root.containsKey("address")) setAddress(root["address"]);
};
protected:
void _init() {


+ 139
- 131
code/espurna/sensors/BaseSensor.h View File

@ -6,144 +6,152 @@
#pragma once
#include <Arduino.h>
#include <ArduinoJson.h>
#include <cstddef>
#include <cstdint>
#include <functional>
#include "../sensor.h"
class BaseSensor {
public:
// Must implement as virtual.
// Allows inhereting class correctly call it's own destructor through the ~BaseSensor()
virtual ~BaseSensor() {
}
// Initialization method, must be idempotent
virtual void begin() {
}
// Loop-like method, call it in your main loop
virtual void tick() {
}
// Pre-read hook (usually to populate registers with up-to-date data)
virtual void pre() {
}
// Post-read hook (usually to reset things)
virtual void post() {
}
// Type of sensor
virtual unsigned char type() {
return sensor::type::Base;
}
// Number of decimals for a unit (or -1 for default)
virtual signed char decimals(sensor::Unit) {
return -1;
}
// Generic calibration
virtual void calibrate() {
};
// Sensor ID
virtual unsigned char getID() {
return _sensor_id;
};
// Return status (true if no errors)
bool status() {
return 0 == _error;
}
// Return ready status (true for ready)
bool ready() {
return _ready;
}
// Return sensor last internal error
int error() {
return _error;
}
// Number of available slots
unsigned char count() {
return _count;
}
// Convert slot # index to a magnitude # index
virtual unsigned char local(unsigned char slot) {
return 0;
}
// Specify units attached to magnitudes
virtual sensor::Unit units(unsigned char index) {
switch (type(index)) {
case MAGNITUDE_TEMPERATURE:
return sensor::Unit::Celcius;
case MAGNITUDE_HUMIDITY:
case MAGNITUDE_POWER_FACTOR:
return sensor::Unit::Percentage;
case MAGNITUDE_PRESSURE:
return sensor::Unit::Hectopascal;
case MAGNITUDE_CURRENT:
return sensor::Unit::Ampere;
case MAGNITUDE_VOLTAGE:
return sensor::Unit::Volt;
case MAGNITUDE_POWER_ACTIVE:
return sensor::Unit::Watt;
case MAGNITUDE_POWER_APPARENT:
return sensor::Unit::Voltampere;
case MAGNITUDE_POWER_REACTIVE:
return sensor::Unit::VoltampereReactive;
case MAGNITUDE_ENERGY_DELTA:
return sensor::Unit::Joule;
case MAGNITUDE_ENERGY:
return sensor::Unit::KilowattHour;
case MAGNITUDE_PM1dot0:
case MAGNITUDE_PM2dot5:
return sensor::Unit::MicrogrammPerCubicMeter;
case MAGNITUDE_CO:
case MAGNITUDE_CO2:
case MAGNITUDE_NO2:
case MAGNITUDE_VOC:
return sensor::Unit::PartsPerMillion;
case MAGNITUDE_LUX:
return sensor::Unit::Lux;
case MAGNITUDE_RESISTANCE:
return sensor::Unit::Ohm;
case MAGNITUDE_HCHO:
return sensor::Unit::MilligrammPerCubicMeter;
case MAGNITUDE_GEIGER_CPM:
return sensor::Unit::CountsPerMinute;
case MAGNITUDE_GEIGER_SIEVERT:
return sensor::Unit::MicrosievertPerHour;
case MAGNITUDE_DISTANCE:
return sensor::Unit::Meter;
case MAGNITUDE_FREQUENCY:
return sensor::Unit::Hertz;
case MAGNITUDE_PH:
return sensor::Unit::Ph;
default:
break;
}
public:
return sensor::Unit::None;
}
// Constructor
BaseSensor() {}
// Destructor
virtual ~BaseSensor() {}
// Initialization method, must be idempotent
virtual void begin() {}
// Loop-like method, call it in your main loop
virtual void tick() {}
// Pre-read hook (usually to populate registers with up-to-date data)
virtual void pre() {}
// Post-read hook (usually to reset things)
virtual void post() {}
// Descriptive name of the sensor
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)
virtual String address(unsigned char index) = 0;
// Type of sensor
virtual unsigned char type() { return sensor::type::Base; }
// Type for slot # index
virtual unsigned char type(unsigned char index) = 0;
// Number of decimals for a unit (or -1 for default)
virtual signed char decimals(sensor::Unit) { return -1; }
// Current value for slot # index
virtual double value(unsigned char index) = 0;
// Generic calibration
virtual void calibrate() {};
// Retrieve current instance configuration
virtual void getConfig(JsonObject& root) {};
// Save current instance configuration
virtual void setConfig(JsonObject& root) {};
// Load the configuration manifest
static void manifest(JsonArray& root) {};
// Sensor ID
unsigned char getID() { return _sensor_id; };
// Return status (true if no errors)
bool status() { return 0 == _error; }
// Return ready status (true for ready)
bool ready() { return _ready; }
// Return sensor last internal error
int error() { return _error; }
// Number of available slots
unsigned char count() { return _count; }
// Convert slot # index to a magnitude # index
virtual unsigned char local(unsigned char slot) { return 0; }
// Specify units attached to magnitudes
virtual sensor::Unit units(unsigned char index) {
switch (type(index)) {
case MAGNITUDE_TEMPERATURE:
return sensor::Unit::Celcius;
case MAGNITUDE_HUMIDITY:
case MAGNITUDE_POWER_FACTOR:
return sensor::Unit::Percentage;
case MAGNITUDE_PRESSURE:
return sensor::Unit::Hectopascal;
case MAGNITUDE_CURRENT:
return sensor::Unit::Ampere;
case MAGNITUDE_VOLTAGE:
return sensor::Unit::Volt;
case MAGNITUDE_POWER_ACTIVE:
return sensor::Unit::Watt;
case MAGNITUDE_POWER_APPARENT:
return sensor::Unit::Voltampere;
case MAGNITUDE_POWER_REACTIVE:
return sensor::Unit::VoltampereReactive;
case MAGNITUDE_ENERGY_DELTA:
return sensor::Unit::Joule;
case MAGNITUDE_ENERGY:
return sensor::Unit::KilowattHour;
case MAGNITUDE_PM1dot0:
case MAGNITUDE_PM2dot5:
return sensor::Unit::MicrogrammPerCubicMeter;
case MAGNITUDE_CO:
case MAGNITUDE_CO2:
case MAGNITUDE_NO2:
case MAGNITUDE_VOC:
return sensor::Unit::PartsPerMillion;
case MAGNITUDE_LUX:
return sensor::Unit::Lux;
case MAGNITUDE_RESISTANCE:
return sensor::Unit::Ohm;
case MAGNITUDE_HCHO:
return sensor::Unit::MilligrammPerCubicMeter;
case MAGNITUDE_GEIGER_CPM:
return sensor::Unit::CountsPerMinute;
case MAGNITUDE_GEIGER_SIEVERT:
return sensor::Unit::MicrosievertPerHour;
case MAGNITUDE_DISTANCE:
return sensor::Unit::Meter;
case MAGNITUDE_FREQUENCY:
return sensor::Unit::Hertz;
case MAGNITUDE_PH:
return sensor::Unit::Ph;
default:
return sensor::Unit::None;
}
}
// Descriptive name of the sensor
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)
virtual String address(unsigned char index) = 0;
protected:
// Type for slot # index
virtual unsigned char type(unsigned char index) = 0;
unsigned char _sensor_id = 0x00;
int _error = 0;
bool _dirty = true;
unsigned char _count = 0;
bool _ready = false;
// Current value for slot # index
virtual double value(unsigned char index) = 0;
protected:
unsigned char _sensor_id = 0;
int _error = 0;
bool _dirty = true;
unsigned char _count = 0;
bool _ready = false;
};

+ 2
- 5
code/espurna/sensors/CSE7766Sensor.h View File

@ -8,14 +8,11 @@
#pragma once
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "../debug.h"
#include "BaseSensor.h"
#include "BaseEmonSensor.h"
#include <SoftwareSerial.h>
class CSE7766Sensor : public BaseEmonSensor {
public:


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "../gpio.h"
#include "../utils.h"


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

@ -8,7 +8,6 @@
#pragma once
#include <Arduino.h>
#include <OneWire.h>
#include <vector>


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "BaseSensor.h"


+ 2
- 6
code/espurna/sensors/ECH1560Sensor.h View File

@ -7,10 +7,6 @@
#pragma once
#include <Arduino.h>
#include "../debug.h"
#include "BaseSensor.h"
#include "BaseEmonSensor.h"
@ -89,7 +85,7 @@ class ECH1560Sensor : public BaseEmonSensor {
// Descriptive name of the sensor
String description() {
char buffer[35];
snprintf(buffer, sizeof(buffer), "ECH1560 (CLK,SDO) @ GPIO(%u,%u)", _clk, _miso);
snprintf(buffer, sizeof(buffer), "ECH1560 (CLK,SDO) @ GPIO(%hhu,%hhu)", _clk, _miso);
return String(buffer);
}
@ -101,7 +97,7 @@ class ECH1560Sensor : public BaseEmonSensor {
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
char buffer[6];
snprintf(buffer, sizeof(buffer), "%u:%u", _clk, _miso);
snprintf(buffer, sizeof(buffer), "%hhu:%hhu", _clk, _miso);
return String(buffer);
}


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

@ -9,7 +9,6 @@
#pragma once
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "BaseSensor.h"


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "../utils.h"
#include "EmonSensor.h"


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "EmonSensor.h"


+ 0
- 1
code/espurna/sensors/EmonAnalogSensor.h View File

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "EmonSensor.h"


+ 0
- 3
code/espurna/sensors/EmonSensor.h View File

@ -7,9 +7,6 @@
#pragma once
#include <Arduino.h>
#include "../debug.h"
#include "BaseEmonSensor.h"
#include "I2CSensor.h"


+ 0
- 3
code/espurna/sensors/EventSensor.h View File

@ -7,9 +7,6 @@
#pragma once
#include <Arduino.h>
#include "../debug.h"
#include "BaseSensor.h"
// we are bound by usable GPIOs


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

@ -8,7 +8,6 @@
#pragma once
#include <Arduino.h>
#include "BaseSensor.h"
#include "../utils.h"
@ -89,7 +88,7 @@ class GUVAS12SDSensor : public BaseSensor {
// Descriptive name of the sensor
String description() {
char buffer[18];
snprintf(buffer, sizeof(buffer), "GUVAS12SD @ GPIO%d", _gpio);
snprintf(buffer, sizeof(buffer), "GUVAS12SD @ GPIO%hhu", _gpio);
return String(buffer);
}


+ 0
- 3
code/espurna/sensors/GeigerSensor.h View File

@ -8,9 +8,6 @@
#pragma once
#include <Arduino.h>
#include "../debug.h"
#include "BaseSensor.h"
class GeigerSensor : public BaseSensor {


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

@ -9,7 +9,6 @@
#pragma once
#include <Arduino.h>
#include "I2CSensor.h"
#include "../utils.h"


+ 2
- 5
code/espurna/sensors/HLW8012Sensor.h View File

@ -7,13 +7,10 @@
#pragma once
#include <Arduino.h>
#include <HLW8012.h>
#include "../debug.h"
#include "BaseEmonSensor.h"
#include <HLW8012.h>
// ref. HLW8012/src/HLW8012.h
//
// These values are used to calculate current, voltage and power factors as per datasheet formula


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "AnalogSensor.h"
extern "C" {


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

@ -8,7 +8,6 @@
#pragma once
#include <Arduino.h>
#include <MAX6675.h>
#include <vector>


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

@ -10,7 +10,6 @@
#pragma once
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "BaseSensor.h"


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "BaseAnalogSensor.h"
extern "C" {


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "BaseAnalogSensor.h"
extern "C" {


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "AnalogSensor.h"
extern "C" {


+ 2
- 4
code/espurna/sensors/PMSX003Sensor.h View File

@ -9,12 +9,10 @@
#pragma once
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "../debug.h"
#include "BaseSensor.h"
#include <SoftwareSerial.h>
// Generic data
#define PMS_BAUD_RATE 9600


+ 0
- 1
code/espurna/sensors/PZEM004TSensor.h View File

@ -49,7 +49,6 @@
#pragma once
#include <Arduino.h>
#include <PZEM004T.h>
#include "BaseSensor.h"


+ 0
- 1
code/espurna/sensors/PZEM004TV30Sensor.h View File

@ -13,7 +13,6 @@ Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#include "BaseEmonSensor.h"
#include "../debug.h"
#include "../utils.h"
#include "../terminal.h"


+ 0
- 4
code/espurna/sensors/PulseMeterSensor.h View File

@ -7,10 +7,6 @@
#pragma once
#include <Arduino.h>
#include "../debug.h"
#include "BaseSensor.h"
#include "BaseEmonSensor.h"


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

@ -10,7 +10,6 @@
#pragma once
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "BaseSensor.h"


+ 0
- 1
code/espurna/sensors/SHT3XI2CSensor.h View File

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "I2CSensor.h"
#include "../utils.h"


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

@ -8,7 +8,6 @@
#pragma once
#include <Arduino.h>
#include <Adafruit_SI1145.h>
#include "I2CSensor.h"


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "I2CSensor.h"
#include "../utils.h"


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

@ -8,7 +8,6 @@
#pragma once
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "BaseSensor.h"


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

@ -8,7 +8,6 @@
#pragma once
#include <Arduino.h>
#include <NewPing.h>
#include "BaseSensor.h"


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

@ -9,7 +9,6 @@
#pragma once
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "BaseSensor.h"


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include "BaseSensor.h"


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "BaseEmonSensor.h"


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include <SparkFun_VEML6075_Arduino_Library.h>
#include "I2CSensor.h"


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

@ -7,7 +7,6 @@
#pragma once
#include <Arduino.h>
#include <VL53L1X.h>
#include "I2CSensor.h"


+ 7
- 4
code/espurna/settings.cpp View File

@ -373,10 +373,14 @@ void saveSettings() {
#endif
}
void autosaveSettings() {
#if SETTINGS_AUTOSAVE
eepromCommit();
#endif
}
void resetSettings() {
auto* ptr = EEPROMr.getDataPtr();
std::fill(ptr + EepromReservedSize, ptr + EepromSize, 0xFF);
EEPROMr.commit();
eepromClear();
}
// -----------------------------------------------------------------------------
@ -558,5 +562,4 @@ void settingsSetup() {
});
#endif
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save