diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index c19bc6e5..06f85a0f 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -88,6 +88,11 @@ // 0 means no pulses, 1 means normally off, 2 normally on #define RELAY_PULSE_MODE RELAY_PULSE_NONE +// Relay requests flood protection window - in seconds +#define RELAY_FLOOD_WINDOW 3 +// Allowed actual relay changes inside requests flood protection window +#define RELAY_FLOOD_CHANGES 5 + //-------------------------------------------------------------------------------- // I18N //-------------------------------------------------------------------------------- diff --git a/code/espurna/espurna.ino b/code/espurna/espurna.ino index 30122dea..1cd1cbde 100644 --- a/code/espurna/espurna.ino +++ b/code/espurna/espurna.ino @@ -207,6 +207,7 @@ void loop() { hardwareLoop(); buttonLoop(); + relayLoop(); ledLoop(); wifiLoop(); otaLoop(); diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino index 9bf55e62..02a30f9b 100644 --- a/code/espurna/relay.ino +++ b/code/espurna/relay.ino @@ -16,6 +16,13 @@ typedef struct { unsigned char pin; bool reverse; unsigned char led; + + unsigned int floodWindowStart; + unsigned char floodWindowChanges; + + unsigned int scheduledStatusTime; + bool scheduledStatus; + bool scheduledReport; } relay_t; std::vector _relays; Ticker pulseTicker; @@ -152,32 +159,30 @@ bool relayStatus(unsigned char id, bool status, bool report) { bool changed = false; if (relayStatus(id) != status) { + unsigned int floodWindowEnd = _relays[id].floodWindowStart + 1000 * RELAY_FLOOD_WINDOW; + unsigned int currentTime = millis(); - DEBUG_MSG_P(PSTR("[RELAY] %d => %s\n"), id, status ? "ON" : "OFF"); - changed = true; - - relayProviderStatus(id, status); + _relays[id].floodWindowChanges++; + _relays[id].scheduledStatusTime = currentTime; - if (_relays[id].led > 0) { - ledStatus(_relays[id].led - 1, status); + if (currentTime >= floodWindowEnd || currentTime < _relays[id].floodWindowStart) { + _relays[id].floodWindowStart = currentTime; + _relays[id].floodWindowChanges = 1; + } else if (_relays[id].floodWindowChanges >= RELAY_FLOOD_CHANGES) { + _relays[id].scheduledStatusTime = floodWindowEnd; } - if (report) relayMQTT(id); - if (!recursive) { - relayPulse(id); - relaySync(id); - relaySave(); - relayWS(); - } + _relays[id].scheduledStatus = status; + _relays[id].scheduledReport = (report ? true : _relays[id].scheduledReport); - #if ENABLE_DOMOTICZ - relayDomoticzSend(id); - #endif + DEBUG_MSG_P(PSTR("[RELAY] scheduled %d => %s in %u ms\n"), + id, status ? "ON" : "OFF", + (_relays[id].scheduledStatusTime - currentTime)); + changed = true; } return changed; - } bool relayStatus(unsigned char id, bool status) { @@ -485,3 +490,38 @@ void relaySetup() { DEBUG_MSG_P(PSTR("[RELAY] Number of relays: %d\n"), _relays.size()); } + +void relayLoop(void) +{ + unsigned char id; + + for (id = 0; id < _relays.size(); id++) { + unsigned int currentTime = millis(); + bool status = _relays[id].scheduledStatus; + + if (relayStatus(id) != status && currentTime >= _relays[id].scheduledStatusTime) { + + DEBUG_MSG_P(PSTR("[RELAY] %d => %s\n"), id, status ? "ON" : "OFF"); + + relayProviderStatus(id, status); + + if (_relays[id].led > 0) { + ledStatus(_relays[id].led - 1, status); + } + + if (_relays[id].scheduledReport) relayMQTT(id); + if (!recursive) { + relayPulse(id); + relaySync(id); + relaySave(); + relayWS(); + } + + #if ENABLE_DOMOTICZ + relayDomoticzSend(id); + #endif + + _relays[id].scheduledReport = false; + } + } +}