Browse Source

Merge pull request #2003 from mcspr/upd-dummy-relays

Relay: update setup code, rework masking
master
Max Prokhorov 4 years ago
committed by GitHub
parent
commit
76e2542459
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 434 additions and 154 deletions
  1. +1
    -0
      code/espurna/alexa.ino
  2. +1
    -0
      code/espurna/button.ino
  3. +0
    -5
      code/espurna/config/general.h
  4. +0
    -30
      code/espurna/config/prototypes.h
  5. +2
    -0
      code/espurna/domoticz.ino
  6. +2
    -0
      code/espurna/espurna.ino
  7. +2
    -0
      code/espurna/ir.ino
  8. +1
    -0
      code/espurna/led.ino
  9. +72
    -0
      code/espurna/relay.h
  10. +151
    -107
      code/espurna/relay.ino
  11. +73
    -0
      code/espurna/relay_config.h
  12. +2
    -0
      code/espurna/rfbridge.ino
  13. +3
    -1
      code/espurna/rpnrules.ino
  14. +2
    -0
      code/espurna/scheduler.ino
  15. +1
    -0
      code/espurna/sensor.ino
  16. +4
    -2
      code/espurna/terminal.ino
  17. +2
    -0
      code/espurna/thermostat.ino
  18. +3
    -0
      code/espurna/tuya.ino
  19. +57
    -0
      code/espurna/utils.h
  20. +53
    -9
      code/espurna/utils.ino
  21. +2
    -0
      code/espurna/web.ino

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

@ -8,6 +8,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if ALEXA_SUPPORT
#include "relay.h"
#include "broker.h"
#include <fauxmoESP.h>


+ 1
- 0
code/espurna/button.ino View File

@ -15,6 +15,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <DebounceEvent.h>
#include <vector>
#include "relay.h"
#include "light.h"
typedef struct {


+ 0
- 5
code/espurna/config/general.h View File

@ -429,11 +429,6 @@
#define RELAY_MQTT_TOGGLE "2"
#endif
// TODO Only single EEPROM address is used to store state, which is 1 byte
// Relay status is stored using bitfield.
// This means that, atm, we are only storing the status of the first 8 relays.
#define RELAY_SAVE_MASK_MAX 8
// -----------------------------------------------------------------------------
// WIFI
// -----------------------------------------------------------------------------


+ 0
- 30
code/espurna/config/prototypes.h View File

@ -250,36 +250,6 @@ typedef struct {
int16_t rssi;
} packet_t;
// -----------------------------------------------------------------------------
// Relay
// -----------------------------------------------------------------------------
#include <bitset>
enum class RelayStatus : unsigned char {
OFF = 0,
ON = 1,
TOGGLE = 2,
UNKNOWN = 0xFF
};
RelayStatus relayParsePayload(const char * payload);
bool relayStatus(unsigned char id, bool status, bool report, bool group_report);
bool relayStatus(unsigned char id, bool status);
bool relayStatus(unsigned char id);
void relayToggle(unsigned char id, bool report, bool group_report);
void relayToggle(unsigned char id);
unsigned char relayCount();
const String& relayPayloadOn();
const String& relayPayloadOff();
const String& relayPayloadToggle();
const char* relayPayload(RelayStatus status);
void relaySetupDummy(unsigned char size, bool reconfigure = false);
// -----------------------------------------------------------------------------
// Settings
// -----------------------------------------------------------------------------


+ 2
- 0
code/espurna/domoticz.ino View File

@ -8,7 +8,9 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if DOMOTICZ_SUPPORT
#include "relay.h"
#include "broker.h"
#include <ArduinoJson.h>
bool _dcz_enabled = false;


+ 2
- 0
code/espurna/espurna.ino View File

@ -22,6 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config/all.h"
#include <vector>
#include "utils.h"
#include "relay.h"
#include "broker.h"
#include "tuya.h"
#include "libs/HeapStats.h"


+ 2
- 0
code/espurna/ir.ino View File

@ -48,6 +48,8 @@ Raw messages:
#if IR_SUPPORT
#include "relay.h"
#include <IRremoteESP8266.h>
#if defined(IR_RX_PIN)


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

@ -12,6 +12,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if LED_SUPPORT
#include "relay.h"
#include "broker.h"
typedef struct {


+ 72
- 0
code/espurna/relay.h View File

@ -0,0 +1,72 @@
/*
RELAY MODULE
Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
*/
#pragma once
#include <bitset>
#include "utils.h"
constexpr size_t RELAYS_MAX = 32;
enum class RelayStatus : unsigned char {
OFF = 0,
ON = 1,
TOGGLE = 2,
UNKNOWN = 0xFF
};
struct RelayMask {
explicit RelayMask(const String& string) :
as_string(string),
as_u32(u32fromString(string))
{}
explicit RelayMask(String&& string) :
as_string(std::move(string)),
as_u32(u32fromString(as_string))
{}
explicit RelayMask(uint32_t value) :
as_string(std::move(u32toString(value, 2))),
as_u32(value)
{}
explicit RelayMask(std::bitset<RELAYS_MAX> bitset) :
RelayMask(bitset.to_ulong())
{}
RelayMask(String&& string, uint32_t value) :
as_string(std::move(string)),
as_u32(value)
{}
const String as_string;
uint32_t as_u32;
};
RelayStatus relayParsePayload(const char * payload);
bool relayStatus(unsigned char id, bool status, bool report, bool group_report);
bool relayStatus(unsigned char id, bool status);
bool relayStatus(unsigned char id);
void relayToggle(unsigned char id, bool report, bool group_report);
void relayToggle(unsigned char id);
unsigned char relayCount();
const String& relayPayloadOn();
const String& relayPayloadOff();
const String& relayPayloadToggle();
const char* relayPayload(RelayStatus status);
void relaySetupDummy(unsigned char size, bool reconfigure = false);

+ 151
- 107
code/espurna/relay.ino View File

@ -11,42 +11,77 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <ArduinoJson.h>
#include <vector>
#include <functional>
#include <bitset>
#include "relay.h"
#include "broker.h"
#include "tuya.h"
typedef struct {
#include "relay_config.h"
struct relay_t {
// Default to dummy (virtual) relay configuration
relay_t(unsigned char pin, unsigned char type, unsigned char reset_pin) :
pin(pin),
type(type),
reset_pin(reset_pin),
delay_on(0),
delay_off(0),
pulse(RELAY_PULSE_NONE),
pulse_ms(0),
current_status(false),
target_status(false),
lock(RELAY_LOCK_DISABLED),
fw_start(0),
fw_count(0),
change_start(0),
change_delay(0),
report(false),
group_report(false)
{}
relay_t() :
relay_t(GPIO_NONE, RELAY_TYPE_NORMAL, GPIO_NONE)
{}
// ... unless there are pre-configured values
relay_t(unsigned char id) :
relay_t(_relayPin(id), _relayType(id), _relayResetPin(id))
{}
// Configuration variables
unsigned char pin; // GPIO pin for the relay
unsigned char type; // RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE, RELAY_TYPE_LATCHED or RELAY_TYPE_LATCHED_INVERSE
unsigned char reset_pin; // GPIO to reset the relay if RELAY_TYPE_LATCHED
unsigned long delay_on; // Delay to turn relay ON
unsigned long delay_off; // Delay to turn relay OFF
unsigned char pulse; // RELAY_PULSE_NONE, RELAY_PULSE_OFF or RELAY_PULSE_ON
unsigned long pulse_ms; // Pulse length in millis
unsigned char pin; // GPIO pin for the relay
unsigned char type; // RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE, RELAY_TYPE_LATCHED or RELAY_TYPE_LATCHED_INVERSE
unsigned char reset_pin; // GPIO to reset the relay if RELAY_TYPE_LATCHED
unsigned long delay_on; // Delay to turn relay ON
unsigned long delay_off; // Delay to turn relay OFF
unsigned char pulse; // RELAY_PULSE_NONE, RELAY_PULSE_OFF or RELAY_PULSE_ON
unsigned long pulse_ms; // Pulse length in millis
// Status variables
bool current_status; // Holds the current (physical) status of the relay
bool target_status; // Holds the target status
unsigned char lock; // Holds the value of target status, that cannot be changed afterwards. (0 for false, 1 for true, 2 to disable)
unsigned long fw_start; // Flood window start time
unsigned char fw_count; // Number of changes within the current flood window
unsigned long change_start; // Time when relay was scheduled to change
unsigned long change_delay; // Delay until the next change
bool report; // Whether to report to own topic
bool group_report; // Whether to report to group topic
bool current_status; // Holds the current (physical) status of the relay
bool target_status; // Holds the target status
unsigned char lock; // Holds the value of target status, that cannot be changed afterwards. (0 for false, 1 for true, 2 to disable)
unsigned long fw_start; // Flood window start time
unsigned char fw_count; // Number of changes within the current flood window
unsigned long change_start; // Time when relay was scheduled to change
unsigned long change_delay; // Delay until the next change
bool report; // Whether to report to own topic
bool group_report; // Whether to report to group topic
// Helping objects
Ticker pulseTicker; // Holds the pulse back timer
Ticker pulseTicker; // Holds the pulse back timer
};
} relay_t;
std::vector<relay_t> _relays;
bool _relayRecursive = false;
Ticker _relaySaveTicker;
uint8_t _relayDummy = DUMMY_RELAY_COUNT;
unsigned long _relay_flood_window = (1000 * RELAY_FLOOD_WINDOW);
@ -248,7 +283,7 @@ void _relayProviderStatus(unsigned char id, bool status) {
lightUpdate(true, true);
return;
}
#endif
@ -300,7 +335,7 @@ void _relayProcess(bool mode) {
if (target != mode) continue;
// Only process if the change delay has expired
if (millis() - _relays[id].change_start < _relays[id].change_delay) continue;
if (_relays[id].change_delay && (millis() - _relays[id].change_start < _relays[id].change_delay)) continue;
// Purge existing delay in case of cancelation
_relays[id].change_delay = 0;
@ -331,8 +366,8 @@ void _relayProcess(bool mode) {
// We will trigger a eeprom save only if
// we care about current relay status on boot
unsigned char boot_mode = getSetting("relayBoot", id, RELAY_BOOT_MODE).toInt();
bool save_eeprom = ((RELAY_BOOT_SAME == boot_mode) || (RELAY_BOOT_TOGGLE == boot_mode));
const auto boot_mode = getSetting("relayBoot", id, RELAY_BOOT_MODE).toInt();
const bool save_eeprom = ((RELAY_BOOT_SAME == boot_mode) || (RELAY_BOOT_TOGGLE == boot_mode));
_relay_save_timer.once_ms(RELAY_SAVE_DELAY, relaySave, save_eeprom);
}
@ -382,14 +417,42 @@ void setSpeed(unsigned char speed) {
// RELAY
// -----------------------------------------------------------------------------
void _relayMaskRtcmem(uint32_t mask) {
// State persistance persistance
RelayMask INLINE _relayMaskRtcmem() {
return RelayMask(Rtcmem->relay);
}
void INLINE _relayMaskRtcmem(uint32_t mask) {
Rtcmem->relay = mask;
}
uint32_t _relayMaskRtcmem() {
return Rtcmem->relay;
void INLINE _relayMaskRtcmem(const RelayMask& mask) {
_relayMaskRtcmem(mask.as_u32);
}
void INLINE _relayMaskRtcmem(const std::bitset<RELAYS_MAX>& bitset) {
_relayMaskRtcmem(bitset.to_ulong());
}
RelayMask INLINE _relayMaskSettings() {
return RelayMask(getSetting("relayBootMask"));
}
void INLINE _relayMaskSettings(uint32_t mask) {
setSetting("relayBootMask", u32toString(mask, 2));
}
void INLINE _relayMaskSettings(const RelayMask& mask) {
setSetting("relayBootMask", mask.as_string);
}
void INLINE _relayMaskSettings(const std::bitset<RELAYS_MAX>& bitset) {
_relayMaskSettings(bitset.to_ulong());
}
// Pulse timers (timer after ON or OFF event)
void relayPulse(unsigned char id) {
_relays[id].pulseTicker.detach();
@ -412,6 +475,8 @@ void relayPulse(unsigned char id) {
}
// General relay status control
bool relayStatus(unsigned char id, bool status, bool report, bool group_report) {
if (id >= _relays.size()) return false;
@ -563,21 +628,18 @@ void relaySync(unsigned char id) {
void relaySave(bool eeprom) {
auto mask = std::bitset<RELAY_SAVE_MASK_MAX>(0);
unsigned char count = relayCount();
if (count > RELAY_SAVE_MASK_MAX) count = RELAY_SAVE_MASK_MAX;
const unsigned char count = constrain(relayCount(), 0, RELAYS_MAX);
for (unsigned int i=0; i < count; ++i) {
mask.set(i, relayStatus(i));
auto statuses = std::bitset<RELAYS_MAX>(0);
for (unsigned int id = 0; id < count; ++id) {
statuses.set(id, relayStatus(id));
}
const uint32_t mask_value = mask.to_ulong();
DEBUG_MSG_P(PSTR("[RELAY] Setting relay mask: %u\n"), mask_value);
const RelayMask mask(statuses);
DEBUG_MSG_P(PSTR("[RELAY] Setting relay mask: %s\n"), mask.as_string.c_str());
// Persist only to rtcmem, unless requested to save to the eeprom
_relayMaskRtcmem(mask_value);
_relayMaskRtcmem(mask);
// The 'eeprom' flag controls whether we are commiting this change or not.
// It is useful to set it to 'false' if the relay change triggering the
@ -586,7 +648,7 @@ void relaySave(bool eeprom) {
// Nevertheless, we store the value in the EEPROM buffer so it will be written
// on the next commit.
if (eeprom) {
EEPROMr.write(EEPROM_RELAY_STATUS, mask_value);
_relayMaskSettings(mask);
// We are actually enqueuing the commit so it will be
// executed on the main loop, in case this is called from a system context callback
eepromCommit();
@ -651,6 +713,17 @@ RelayStatus relayParsePayload(const char * payload) {
// BACKWARDS COMPATIBILITY
void _relayBackwards() {
#if defined(EEPROM_RELAY_STATUS)
{
uint8_t mask = EEPROMr.read(EEPROM_RELAY_STATUS);
if (mask != 0xff) {
_relayMaskSettings(static_cast<uint32_t>(mask));
EEPROMr.write(EEPROM_RELAY_STATUS, 0xff);
eepromCommit();
}
}
#endif
for (unsigned int i=0; i<_relays.size(); i++) {
if (!hasSetting("mqttGroupInv", i)) continue;
setSetting("mqttGroupSync", i, getSetting("mqttGroupInv", i));
@ -662,18 +735,14 @@ void _relayBackwards() {
void _relayBoot() {
_relayRecursive = true;
bool trigger_save = false;
uint32_t stored_mask = 0;
if (rtcmemStatus()) {
stored_mask = _relayMaskRtcmem();
} else {
stored_mask = EEPROMr.read(EEPROM_RELAY_STATUS);
}
const auto stored_mask = rtcmemStatus()
? _relayMaskRtcmem()
: _relayMaskSettings();
DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %u\n"), stored_mask);
DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %s\n"), stored_mask.as_string.c_str());
auto mask = std::bitset<RELAY_SAVE_MASK_MAX>(stored_mask);
auto mask = std::bitset<RELAYS_MAX>(stored_mask.as_u32);
// Walk the relays
unsigned char lock;
@ -687,16 +756,11 @@ void _relayBoot() {
lock = RELAY_LOCK_DISABLED;
switch (boot_mode) {
case RELAY_BOOT_SAME:
if (i < 8) {
status = mask.test(i);
}
status = mask.test(i);
break;
case RELAY_BOOT_TOGGLE:
if (i < 8) {
status = !mask[i];
mask.flip(i);
trigger_save = true;
}
mask.flip(i);
status = mask[i];
break;
case RELAY_BOOT_LOCKED_ON:
status = true;
@ -715,7 +779,11 @@ void _relayBoot() {
_relays[i].current_status = !status;
_relays[i].target_status = status;
_relays[i].change_start = millis();
_relays[i].change_delay = status
? _relays[i].delay_on
: _relays[i].delay_off;
#if RELAY_PROVIDER == RELAY_PROVIDER_STM
// XXX hack for correctly restoring relay state on boot
@ -725,14 +793,6 @@ void _relayBoot() {
_relays[i].lock = lock;
}
// Save if there is any relay in the RELAY_BOOT_TOGGLE mode
if (trigger_save) {
_relayMaskRtcmem(mask.to_ulong());
EEPROMr.write(EEPROM_RELAY_STATUS, mask.to_ulong());
eepromCommit();
}
_relayRecursive = false;
@ -743,32 +803,6 @@ void _relayBoot() {
}
constexpr const unsigned long _relayDelayOn(unsigned char index) {
return (
(index == 0) ? RELAY1_DELAY_ON :
(index == 1) ? RELAY2_DELAY_ON :
(index == 2) ? RELAY3_DELAY_ON :
(index == 3) ? RELAY4_DELAY_ON :
(index == 4) ? RELAY5_DELAY_ON :
(index == 5) ? RELAY6_DELAY_ON :
(index == 6) ? RELAY7_DELAY_ON :
(index == 7) ? RELAY8_DELAY_ON : 0
);
}
constexpr const unsigned long _relayDelayOff(unsigned char index) {
return (
(index == 0) ? RELAY1_DELAY_OFF :
(index == 1) ? RELAY2_DELAY_OFF :
(index == 2) ? RELAY3_DELAY_OFF :
(index == 3) ? RELAY4_DELAY_OFF :
(index == 4) ? RELAY5_DELAY_OFF :
(index == 5) ? RELAY6_DELAY_OFF :
(index == 6) ? RELAY7_DELAY_OFF :
(index == 7) ? RELAY8_DELAY_OFF : 0
);
}
void _relayConfigure() {
for (unsigned int i=0; i<_relays.size(); i++) {
_relays[i].pulse = getSetting("relayPulse", i, RELAY_PULSE_MODE).toInt();
@ -1325,18 +1359,14 @@ void _relayLoop() {
#endif
}
// Dummy relays for AI Light, Magic Home LED Controller, H801, Sonoff Dual and Sonoff RF Bridge
// No delay_on or off for these devices to easily allow having more than
// 8 channels. This behaviour will be recovered with v2.
// Dummy relays for virtual light switches, Sonoff Dual, Sonoff RF Bridge and Tuya
void relaySetupDummy(unsigned char size, bool reconfigure) {
size = constrain(size, 0, RELAY_SAVE_MASK_MAX);
size = constrain(size + _relays.size(), _relays.size(), RELAYS_MAX);
if (size == _relays.size()) return;
_relayDummy = size;
_relays.assign(size, {
GPIO_NONE, RELAY_TYPE_NORMAL, GPIO_NONE
});
_relayDummy = size;
_relays.resize(size);
if (reconfigure) {
_relayConfigure();
@ -1348,34 +1378,48 @@ void relaySetupDummy(unsigned char size, bool reconfigure) {
}
void relaySetup() {
void _relaySetupAdhoc() {
size_t relays = 0;
// Ad-hoc relays
#if RELAY1_PIN != GPIO_NONE
_relays.push_back((relay_t) { RELAY1_PIN, RELAY1_TYPE, RELAY1_RESET_PIN });
++relays;
#endif
#if RELAY2_PIN != GPIO_NONE
_relays.push_back((relay_t) { RELAY2_PIN, RELAY2_TYPE, RELAY2_RESET_PIN });
++relays;
#endif
#if RELAY3_PIN != GPIO_NONE
_relays.push_back((relay_t) { RELAY3_PIN, RELAY3_TYPE, RELAY3_RESET_PIN });
++relays;
#endif
#if RELAY4_PIN != GPIO_NONE
_relays.push_back((relay_t) { RELAY4_PIN, RELAY4_TYPE, RELAY4_RESET_PIN });
++relays;
#endif
#if RELAY5_PIN != GPIO_NONE
_relays.push_back((relay_t) { RELAY5_PIN, RELAY5_TYPE, RELAY5_RESET_PIN });
++relays;
#endif
#if RELAY6_PIN != GPIO_NONE
_relays.push_back((relay_t) { RELAY6_PIN, RELAY6_TYPE, RELAY6_RESET_PIN });
++relays;
#endif
#if RELAY7_PIN != GPIO_NONE
_relays.push_back((relay_t) { RELAY7_PIN, RELAY7_TYPE, RELAY7_RESET_PIN });
++relays;
#endif
#if RELAY8_PIN != GPIO_NONE
_relays.push_back((relay_t) { RELAY8_PIN, RELAY8_TYPE, RELAY8_RESET_PIN });
++relays;
#endif
_relays.reserve(relays);
for (unsigned char id = 0; id < relays; ++id) {
_relays.emplace_back(id);
}
}
void relaySetup() {
// Ad-hoc relays
_relaySetupAdhoc();
// Dummy (virtual) relays
relaySetupDummy(getSetting("relayDummy", DUMMY_RELAY_COUNT).toInt());
_relaySetupProvider();


+ 73
- 0
code/espurna/relay_config.h View File

@ -0,0 +1,73 @@
/*
RELAY MODULE
*/
#pragma once
constexpr const unsigned long _relayDelayOn(unsigned char index) {
return (
(index == 0) ? RELAY1_DELAY_ON :
(index == 1) ? RELAY2_DELAY_ON :
(index == 2) ? RELAY3_DELAY_ON :
(index == 3) ? RELAY4_DELAY_ON :
(index == 4) ? RELAY5_DELAY_ON :
(index == 5) ? RELAY6_DELAY_ON :
(index == 6) ? RELAY7_DELAY_ON :
(index == 7) ? RELAY8_DELAY_ON : 0
);
}
constexpr const unsigned long _relayDelayOff(unsigned char index) {
return (
(index == 0) ? RELAY1_DELAY_OFF :
(index == 1) ? RELAY2_DELAY_OFF :
(index == 2) ? RELAY3_DELAY_OFF :
(index == 3) ? RELAY4_DELAY_OFF :
(index == 4) ? RELAY5_DELAY_OFF :
(index == 5) ? RELAY6_DELAY_OFF :
(index == 6) ? RELAY7_DELAY_OFF :
(index == 7) ? RELAY8_DELAY_OFF : 0
);
}
constexpr const unsigned char _relayPin(unsigned char index) {
return (
(index == 0) ? RELAY1_PIN :
(index == 1) ? RELAY2_PIN :
(index == 2) ? RELAY3_PIN :
(index == 3) ? RELAY4_PIN :
(index == 4) ? RELAY5_PIN :
(index == 5) ? RELAY6_PIN :
(index == 6) ? RELAY7_PIN :
(index == 7) ? RELAY8_PIN : GPIO_NONE
);
}
constexpr const unsigned char _relayType(unsigned char index) {
return (
(index == 0) ? RELAY1_TYPE :
(index == 1) ? RELAY2_TYPE :
(index == 2) ? RELAY3_TYPE :
(index == 3) ? RELAY4_TYPE :
(index == 4) ? RELAY5_TYPE :
(index == 5) ? RELAY6_TYPE :
(index == 6) ? RELAY7_TYPE :
(index == 7) ? RELAY8_TYPE : RELAY_TYPE_NORMAL
);
}
constexpr const unsigned char _relayResetPin(unsigned char index) {
return (
(index == 0) ? RELAY1_RESET_PIN :
(index == 1) ? RELAY2_RESET_PIN :
(index == 2) ? RELAY3_RESET_PIN :
(index == 3) ? RELAY4_RESET_PIN :
(index == 4) ? RELAY5_RESET_PIN :
(index == 5) ? RELAY6_RESET_PIN :
(index == 6) ? RELAY7_RESET_PIN :
(index == 7) ? RELAY8_RESET_PIN : GPIO_NONE
);
}

+ 2
- 0
code/espurna/rfbridge.ino View File

@ -8,6 +8,8 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if RF_SUPPORT
#include "relay.h"
#include <queue>
#include <Ticker.h>


+ 3
- 1
code/espurna/rpnrules.ino View File

@ -8,7 +8,9 @@ Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
#if RPN_RULES_SUPPORT
#include "rpnlib.h"
#include "relay.h"
#include <rpnlib.h>
// -----------------------------------------------------------------------------
// Custom commands


+ 2
- 0
code/espurna/scheduler.ino View File

@ -9,6 +9,8 @@ Adapted by Xose Pérez <xose dot perez at gmail dot com>
#if SCHEDULER_SUPPORT
#include "relay.h"
#include <TimeLib.h>
int _sch_restore = 0;


+ 1
- 0
code/espurna/sensor.ino View File

@ -8,6 +8,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if SENSOR_SUPPORT
#include "relay.h"
#include "broker.h"
#include <vector>


+ 4
- 2
code/espurna/terminal.ino View File

@ -8,12 +8,14 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if TERMINAL_SUPPORT
#include <vector>
#include "utils.h"
#include "libs/EmbedisWrap.h"
#include <Stream.h>
#include "libs/StreamInjector.h"
#include "libs/HeapStats.h"
#include <vector>
#include <Stream.h>
StreamInjector _serial = StreamInjector(TERMINAL_BUFFER_SIZE);
EmbedisWrap embedis(_serial, TERMINAL_BUFFER_SIZE);


+ 2
- 0
code/espurna/thermostat.ino View File

@ -8,6 +8,8 @@ Copyright (C) 2017 by Dmitry Blinov <dblinov76 at gmail dot com>
#if THERMOSTAT_SUPPORT
#include "relay.h"
#include <ArduinoJson.h>
#include <float.h>


+ 3
- 0
code/espurna/tuya.ino View File

@ -10,6 +10,9 @@ Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#if TUYA_SUPPORT
#include "relay.h"
#include "light.h"
#include <functional>
#include <queue>
#include <StreamString.h>


+ 57
- 0
code/espurna/utils.h View File

@ -0,0 +1,57 @@
/*
UTILS MODULE
Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
*/
#pragma once
extern "C" uint32_t _SPIFFS_start;
extern "C" uint32_t _SPIFFS_end;
String getIdentifier();
void setDefaultHostname();
void setBoardName();
String getBoardName();
String getAdminPass();
const String& getCoreVersion();
const String& getCoreRevision();
unsigned char getHeartbeatMode();
unsigned char getHeartbeatInterval();
void heartbeat();
String getEspurnaModules();
String getEspurnaOTAModules();
String getEspurnaSensors();
String getEspurnaWebUI();
String buildTime();
unsigned long getUptime();
bool haveRelaysOrSensors();
void infoMemory(const char * name, unsigned int total_memory, unsigned int free_memory);
void info();
bool sslCheckFingerPrint(const char * fingerprint);
bool sslFingerPrintArray(const char * fingerprint, unsigned char * bytearray);
bool sslFingerPrintChar(const char * fingerprint, char * destination);
bool eraseSDKConfig();
char * ltrim(char * s);
char * strnstr(const char * buffer, const char * token, size_t n);
bool isNumber(const char * s);
void nice_delay(unsigned long ms);
double roundTo(double num, unsigned char positions);
uint32_t u32fromString(const String& string, int base);
uint32_t u32fromString(const String& string);
String u32toString(uint32_t bitset, int base);

+ 53
- 9
code/espurna/utils.ino View File

@ -6,9 +6,11 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include "utils.h"
#include "libs/HeapStats.h"
#include <Ticker.h>
#include <limits>
#include "libs/HeapStats.h"
String getIdentifier() {
char buffer[20];
@ -64,7 +66,7 @@ const String& getCoreRevision() {
#ifdef ARDUINO_ESP8266_GIT_VER
revision = String(ARDUINO_ESP8266_GIT_VER, 16);
#else
revision = "";
revision = "(unspecified)";
#endif
}
return revision;
@ -192,12 +194,7 @@ namespace Heartbeat {
return defaultValue();
}
// invalidate the whole string when invalid chars are detected
char *value_endptr = nullptr;
const auto value = strtoul(cfg.c_str(), &value_endptr, 10);
if (value_endptr == cfg.c_str() || value_endptr[0] != '\0') {
return defaultValue();
}
const auto value = u32fromString(cfg);
// because we start shifting from 1, we could use the
// first bit as a flag to enable all of the messages
@ -250,7 +247,7 @@ void heartbeat() {
#if MQTT_SUPPORT
if (!serial && (_heartbeat_mode == HEARTBEAT_REPEAT || systemGetHeartbeat())) {
if (hb_cfg & Heartbeat::Interval)
mqttSend(MQTT_TOPIC_INTERVAL, String(getHeartbeatInterval() / 1000).c_str());
mqttSend(MQTT_TOPIC_INTERVAL, String(getHeartbeatInterval()).c_str());
if (hb_cfg & Heartbeat::App)
mqttSend(MQTT_TOPIC_APP, APP_NAME);
@ -677,3 +674,50 @@ char* strnstr(const char* buffer, const char* token, size_t n) {
return nullptr;
}
// TODO: force getSetting return type to handle settings
uint32_t u32fromString(const String& string, int base) {
const char *ptr = string.c_str();
char *value_endptr = nullptr;
// invalidate the whole string when invalid chars are detected
const auto value = strtoul(ptr, &value_endptr, base);
if (value_endptr == ptr || value_endptr[0] != '\0') {
return 0;
}
return value;
}
uint32_t u32fromString(const String& string) {
if (!string.length()) {
return 0;
}
int base = 10;
if (string.length() > 2) {
if (string.startsWith("0b")) {
base = 2;
} else if (string.startsWith("0o")) {
base = 8;
} else if (string.startsWith("0x")) {
base = 16;
}
}
return u32fromString((base == 10) ? string : string.substring(2), base);
}
String u32toString(uint32_t value, int base) {
String result;
result.reserve(32 + 2);
result += "0b";
char buffer[33] = {0};
ultoa(value, buffer, base);
result += buffer;
return result;
}

+ 2
- 0
code/espurna/web.ino View File

@ -8,6 +8,8 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#if WEB_SUPPORT
#include "utils.h"
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Hash.h>


Loading…
Cancel
Save