Add command `SspmLog<relay> [x]`

Add command ``SspmLog<relay> [x]`` to retrieve relay power state change and cause logging
This commit is contained in:
Theo Arends 2022-01-24 15:38:58 +01:00
parent dcfdb78935
commit bb5cf22d0a
3 changed files with 76 additions and 32 deletions

View File

@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
- Command ``SspmDisplay 1`` to display Sonoff SPM energy data in GUI for relays powered on only - Command ``SspmDisplay 1`` to display Sonoff SPM energy data in GUI for relays powered on only
- Command ``SspmHistory<relay>`` to retrieve daily energy of last six month (as defined by ARM firmware) - Command ``SspmHistory<relay>`` to retrieve daily energy of last six month (as defined by ARM firmware)
- Command ``SspmIAmHere<relay>`` to (faintly) blink Sonoff SPM-4Relay module error light of requested relay - Command ``SspmIAmHere<relay>`` to (faintly) blink Sonoff SPM-4Relay module error light of requested relay
- Command ``SspmLog<relay> [x]`` to retrieve relay power state change and cause logging
- Command ``SspmScan`` to rescan Sonoff SPM modbus - Command ``SspmScan`` to rescan Sonoff SPM modbus
### Changed ### Changed

View File

@ -107,6 +107,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
- Command ``SspmDisplay 1`` to display Sonoff SPM energy data in GUI for relays powered on only - Command ``SspmDisplay 1`` to display Sonoff SPM energy data in GUI for relays powered on only
- Command ``SspmHistory<relay>`` to retrieve daily energy of last six month (as defined by ARM firmware) - Command ``SspmHistory<relay>`` to retrieve daily energy of last six month (as defined by ARM firmware)
- Command ``SspmIAmHere<relay>`` to (faintly) blink Sonoff SPM-4Relay module error light of requested relay - Command ``SspmIAmHere<relay>`` to (faintly) blink Sonoff SPM-4Relay module error light of requested relay
- Command ``SspmLog<relay> [x]`` to retrieve relay power state change and cause logging
- Command ``SspmMap 2,1,..`` to map Sonoff SPM scanned module to physical module [#14281](https://github.com/arendst/Tasmota/issues/14281) - Command ``SspmMap 2,1,..`` to map Sonoff SPM scanned module to physical module [#14281](https://github.com/arendst/Tasmota/issues/14281)
- Command ``SspmScan`` to rescan Sonoff SPM modbus - Command ``SspmScan`` to rescan Sonoff SPM modbus
- Command ``SetOption44 1..100`` to set base tolerance percentage for matching incoming IR messages (default 25, max 100) [#14555](https://github.com/arendst/Tasmota/issues/14555) - Command ``SetOption44 1..100`` to set base tolerance percentage for matching incoming IR messages (default 25, max 100) [#14555](https://github.com/arendst/Tasmota/issues/14555)

View File

@ -22,13 +22,13 @@
#ifdef ESP32 #ifdef ESP32
#ifdef USE_SONOFF_SPM #ifdef USE_SONOFF_SPM
/*********************************************************************************************\ /*********************************************************************************************\
* Sonoff Stackable Power Manager (Current state: PROOF OF CONCEPT) * Sonoff Stackable Power Manager
*
* {"NAME":"Sonoff SPM","GPIO":[0,0,0,0,3200,5536,0,0,0,0,0,0,3232,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,544,0,0,32,0,0,0,0],"FLAG":0,"BASE":1}
* *
* Initial POC template: * Initial POC template:
* {"NAME":"Sonoff SPM (POC1)","GPIO":[1,1,1,1,3200,1,1,1,1,1,1,1,3232,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,544,1,1,32,1,0,0,1],"FLAG":0,"BASE":1} * {"NAME":"Sonoff SPM (POC1)","GPIO":[1,1,1,1,3200,1,1,1,1,1,1,1,3232,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,544,1,1,32,1,0,0,1],"FLAG":0,"BASE":1}
* Add ethernet support: * Add ethernet support:
* {"NAME":"Sonoff SPM (POC2)","GPIO":[1,0,1,0,3200,5536,0,0,1,1,1,0,3232,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,544,1,1,32,1,0,0,1],"FLAG":0,"BASE":1}
* Remove all user selectable GPIOs:
* {"NAME":"Sonoff SPM (POC2)","GPIO":[0,0,0,0,3200,5536,0,0,0,0,0,0,3232,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,544,0,0,32,0,0,0,0],"FLAG":0,"BASE":1} * {"NAME":"Sonoff SPM (POC2)","GPIO":[0,0,0,0,3200,5536,0,0,0,0,0,0,3232,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,544,0,0,32,0,0,0,0],"FLAG":0,"BASE":1}
* *
* Things to know: * Things to know:
@ -37,6 +37,8 @@
* Green led is controlled by ARM processor indicating SD-Card access. * Green led is controlled by ARM processor indicating SD-Card access.
* ESP32 is used as interface between eWelink and ARM processor in SPM-Main unit communicating over proprietary serial protocol. * ESP32 is used as interface between eWelink and ARM processor in SPM-Main unit communicating over proprietary serial protocol.
* Power on sequence for two SPM-4Relay modules is 00-00-15-10-(0F)-(13)-(13)-(19)-0C-09-04-09-04-0B-0B * Power on sequence for two SPM-4Relay modules is 00-00-15-10-(0F)-(13)-(13)-(19)-0C-09-04-09-04-0B-0B
* Up to six months of daily energy are stored onthe SD-Card. Previous data is lost.
* Tasmota support is based on Sonoff SPM v1.0.0 ARM firmware.
* *
* Tasmota POC1: * Tasmota POC1:
* Up to 7 SPM-4Relay units supporting up to 28 relays. * Up to 7 SPM-4Relay units supporting up to 28 relays.
@ -51,9 +53,11 @@
* Yellow led blinks 2 seconds if an ARM-ESP comms CRC error is detected. * Yellow led blinks 2 seconds if an ARM-ESP comms CRC error is detected.
* Persistence for module mapping * Persistence for module mapping
* Supported commands: * Supported commands:
* SspmMap 2,3,1,.. - Map scanned module number to physical module number using positional numbering
* SspmDisplay 0|1 - Select alternative GUI rotating display either all or powered on only * SspmDisplay 0|1 - Select alternative GUI rotating display either all or powered on only
* SspmHistory<relay> - Retrieve daily energy of last six month (as defined by ARM firmware)
* SspmIAmHere<relay> - Blink ERROR in SPM-4Relay where relay resides * SspmIAmHere<relay> - Blink ERROR in SPM-4Relay where relay resides
* SspmLog<relay> [x] - Retrieve relay power state change and cause logging
* SspmMap 2,3,1,.. - Map scanned module number to physical module number using positional numbering
* SspmScan - Rescan ARM modbus taking around 20 seconds * SspmScan - Rescan ARM modbus taking around 20 seconds
* SspmReset 1 - Reset ARM and restart ESP * SspmReset 1 - Reset ARM and restart ESP
* *
@ -159,6 +163,8 @@ enum SspmMachineStates { SPM_NONE, // Do nothing
SPM_UPDATE_CHANNELS // Update Energy for powered on channels SPM_UPDATE_CHANNELS // Update Energy for powered on channels
}; };
const char kSSPMTriggers[] PROGMEM = "Tasmota|Device|Overload|Overtemp";
#include <TasmotaSerial.h> #include <TasmotaSerial.h>
TasmotaSerial *SspmSerial; TasmotaSerial *SspmSerial;
@ -200,8 +206,8 @@ typedef struct {
uint8_t mstate; uint8_t mstate;
uint8_t last_button; uint8_t last_button;
uint8_t error_led_blinks; uint8_t error_led_blinks;
uint8_t history_module; uint8_t history_relay;
uint8_t history_channel; uint8_t log_relay;
bool map_change; bool map_change;
bool discovery_triggered; bool discovery_triggered;
} TSspm; } TSspm;
@ -851,18 +857,24 @@ void SSPMHandleReceivedData(void) {
uint32_t channel = SspmBuffer[32]; uint32_t channel = SspmBuffer[32];
uint32_t module = SSPMGetModuleNumberFromMap(SspmBuffer[20] << 8 | SspmBuffer[21]); uint32_t module = SSPMGetModuleNumberFromMap(SspmBuffer[20] << 8 | SspmBuffer[21]);
if ((Sspm->history_channel == channel) && (Sspm->history_module == module)) { if (Sspm->history_relay < 255) {
// uint32_t now = SspmBuffer[33] << 8 | SspmBuffer[34]; uint32_t history_module = Sspm->history_relay >> 2;
uint32_t start = SspmBuffer[37] << 8 | SspmBuffer[38]; uint32_t history_channel = Sspm->history_relay & 0x03; // Channel relays are NOT bit masked this time
Response_P(PSTR("{\"SSPMHistory\":{\"From\":\"%d-%02d-%02d\",\"DailyEnergy\":["), if ((history_channel == channel) && (history_module == module)) {
start, SspmBuffer[39], SspmBuffer[40]); // uint32_t now = SspmBuffer[33] << 8 | SspmBuffer[34];
uint32_t start = SspmBuffer[37] << 8 | SspmBuffer[38];
Response_P(PSTR("{\"SSPMHistory%d\":{\"From\":\"%d-%02d-%02d\",\"DailyEnergy\":["),
Sspm->history_relay +1, start, SspmBuffer[39], SspmBuffer[40]);
} else {
Sspm->history_relay = 255;
}
} }
for (uint32_t i = 0; i < entries; i++) { for (uint32_t i = 0; i < entries; i++) {
float today_energy = SspmBuffer[41 + (i*2)] + (float)SspmBuffer[42 + (i*2)] / 100; // x.xxkWh float today_energy = SspmBuffer[41 + (i*2)] + (float)SspmBuffer[42 + (i*2)] / 100; // x.xxkWh
if (112.30 == today_energy) { today_energy = 0; } // Unknown why sometimes 0x701E (=112.30kWh) pops up if (112.30 == today_energy) { today_energy = 0; } // Unknown why sometimes 0x701E (=112.30kWh) pops up
if ((Sspm->history_channel == channel) && (Sspm->history_module == module)) { if (Sspm->history_relay < 255) {
ResponseAppend_P(PSTR("%s%*_f"), (i)?",":"", Settings->flag2.energy_resolution, &today_energy); ResponseAppend_P(PSTR("%s%*_f"), (i)?",":"", Settings->flag2.energy_resolution, &today_energy);
} }
@ -875,10 +887,10 @@ void SSPMHandleReceivedData(void) {
Sspm->energy_yesterday[module][channel] = energy_yesterday; Sspm->energy_yesterday[module][channel] = energy_yesterday;
Sspm->energy_total[module][channel] = energy_total; // x.xxkWh Sspm->energy_total[module][channel] = energy_total; // x.xxkWh
if ((Sspm->history_channel == channel) && (Sspm->history_module == module)) { if (Sspm->history_relay < 255) {
ResponseAppend_P(PSTR("]}}")); ResponseAppend_P(PSTR("]}}"));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR("SSPMHistory")); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR("SSPMHistory"));
Sspm->history_channel = 5; // Disable display energy history Sspm->history_relay = 255; // Disable display energy history
} }
Sspm->allow_updates = 1; Sspm->allow_updates = 1;
@ -900,14 +912,9 @@ void SSPMHandleReceivedData(void) {
|----------------------- Month = 11 = November |----------------------- Month = 11 = November
----------------------------- Year 07 e5 = 2021 ----------------------------- Year 07 e5 = 2021
07 e5 0b 06 0f 1f 08 00 00 01 07 e5 0b 06 0f 1f 08 00 00 01
07 e5 0b 06 0f 1f 04 02 00 01
07 e5 0b 06 0f 1e 32 01 00 01
07 e5 0b 06 0f 1e 1e 01 01 01 07 e5 0b 06 0f 1e 1e 01 01 01
07 e5 0b 06 0f 18 38 02 01 01
07 e5 0b 06 0f 12 38 00 01 01
07 e5 0b 06 0e 37 36 03 00 00 07 e5 0b 06 0e 37 36 03 00 00
07 e5 0b 06 0e 37 36 01 00 00 07 e5 0b 06 0e 37 36 01 00 00
07 e5 0b 06 0e 37 1e 03 01 00
07 e5 0b 06 0e 36 37 01 01 00 07 e5 0b 06 0e 36 37 01 01 00
... ...
07 e5 0b 06 0d 30 2d 03 00 01 09 89 fe 07 e5 0b 06 0d 30 2d 03 00 01 09 89 fe
@ -916,7 +923,40 @@ void SSPMHandleReceivedData(void) {
AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 1A 00 01 03 E5 45 EB AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 1A 00 01 03 E5 45 EB
| | | |
*/ */
if (Sspm->log_relay < 255) {
uint32_t module = Sspm->log_relay >> 2;
uint32_t channel = Sspm->log_relay & 0x03; // Channel relays are NOT bit masked this time
Response_P(PSTR("{\"SSPMLog%d\":"), Sspm->log_relay +1);
if (Sspm->expected_bytes < 15) {
ResponseAppend_P(PSTR("\"Error%d\"}"), SspmBuffer[19]);
} else if (module != SSPMGetModuleNumberFromMap(SspmBuffer[20] << 8 | SspmBuffer[21])) {
ResponseAppend_P(PSTR("\"Wrong module\"}"));
} else {
uint32_t entries = SspmBuffer[32];
uint32_t offset = 33;
bool more = false;
for (uint32_t i = 0; i < entries; i++) {
if (SspmBuffer[offset +7] == channel) {
uint32_t year = SspmBuffer[offset] << 8 | SspmBuffer[offset +1];
char stemp[10]; // One of "App|Device|Overload|Overtemp"
ResponseAppend_P(PSTR("%s{\"Time\":\"%d-%02d-%02dT%02d:%02d:%02d\",\"Trigger\":\"%s\",\"State\":\"%s\"}"),
(more)?",":"[", year, SspmBuffer[offset +2], SspmBuffer[offset +3],
SspmBuffer[offset +4], SspmBuffer[offset +5], SspmBuffer[offset +6],
GetTextIndexed(stemp, sizeof(stemp), SspmBuffer[offset +9] & 0x03, kSSPMTriggers),
GetStateText(SspmBuffer[offset +8]));
more = true;
}
offset += 10;
}
if (more) {
ResponseAppend_P(PSTR("]}"));
}else {
ResponseAppend_P(PSTR("\"None\"}"));
}
}
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR("SSPMLog"));
Sspm->log_relay = 255; // Disable display energy history
}
break; break;
case SSPM_FUNC_ENERGY_PERIOD: case SSPM_FUNC_ENERGY_PERIOD:
/* 0x1B /* 0x1B
@ -1146,9 +1186,7 @@ void SSPMSerialInput(void) {
/*********************************************************************************************/ /*********************************************************************************************/
void SSPMInit(void) { void SSPMInit(void) {
if (!ValidTemplate(PSTR("Sonoff SPM (POC1)")) && if (!ValidTemplate(PSTR("Sonoff SPM")) || !PinUsed(GPIO_RXD) || !PinUsed(GPIO_TXD)) { return; }
!ValidTemplate(PSTR("Sonoff SPM (POC2)"))) { return; }
if (!PinUsed(GPIO_RXD) || !PinUsed(GPIO_TXD)) { return; }
Sspm = (TSspm*)calloc(sizeof(TSspm), 1); // Need calloc to reset registers to 0/false Sspm = (TSspm*)calloc(sizeof(TSspm), 1); // Need calloc to reset registers to 0/false
if (!Sspm) { return; } if (!Sspm) { return; }
@ -1187,7 +1225,8 @@ void SSPMInit(void) {
#endif #endif
#endif #endif
Sspm->history_channel = 5; // Disable display energy history Sspm->history_relay = 255; // Disable display energy history
Sspm->log_relay = 255; // Disable display logging
Sspm->old_power = TasmotaGlobal.power; Sspm->old_power = TasmotaGlobal.power;
Sspm->mstate = SPM_WAIT; // Start init sequence Sspm->mstate = SPM_WAIT; // Start init sequence
} }
@ -1485,11 +1524,14 @@ void (* const SSPMCommand[])(void) PROGMEM = {
&CmndSSPMLog, &CmndSSPMEnergy, &CmndSSPMHistory, &CmndSSPMScan, &CmndSSPMIamHere, &CmndSSPMDisplay, &CmndSSPMReset, &CmndSSPMMap }; &CmndSSPMLog, &CmndSSPMEnergy, &CmndSSPMHistory, &CmndSSPMScan, &CmndSSPMIamHere, &CmndSSPMDisplay, &CmndSSPMReset, &CmndSSPMMap };
void CmndSSPMLog(void) { void CmndSSPMLog(void) {
// Report 29 log entries // SspmLog<relay> - Report from up to 29 latest log entries
// SspmLog<relay> 10 - Report from up to 10 latest log entries
// SspmLog<relay> 100 - Report from up to 29 log entries
if ((XdrvMailbox.index < 1) || (XdrvMailbox.index > TasmotaGlobal.devices_present)) { XdrvMailbox.index = 1; } if ((XdrvMailbox.index < 1) || (XdrvMailbox.index > TasmotaGlobal.devices_present)) { XdrvMailbox.index = 1; }
XdrvMailbox.payload &= 0xFFFF; // Max 65000 entries if ((XdrvMailbox.payload < 1) || (XdrvMailbox.payload > 65000)) { XdrvMailbox.payload = 28; }
SSPMSendGetLog(XdrvMailbox.index -1, XdrvMailbox.payload +1); Sspm->log_relay = XdrvMailbox.index -1;
ResponseCmndDone(); SSPMSendGetLog(Sspm->log_relay, XdrvMailbox.payload +1);
ResponseClear();
} }
void CmndSSPMEnergy(void) { void CmndSSPMEnergy(void) {
@ -1499,11 +1541,11 @@ void CmndSSPMEnergy(void) {
} }
void CmndSSPMHistory(void) { void CmndSSPMHistory(void) {
// Retreive daily history of one relay up to six month
// SspmHistory<relay>
if ((XdrvMailbox.index < 1) || (XdrvMailbox.index > TasmotaGlobal.devices_present)) { XdrvMailbox.index = 1; } if ((XdrvMailbox.index < 1) || (XdrvMailbox.index > TasmotaGlobal.devices_present)) { XdrvMailbox.index = 1; }
uint32_t relay = XdrvMailbox.index -1; Sspm->history_relay = XdrvMailbox.index -1;
Sspm->history_module = relay >> 2; SSPMSendGetEnergyTotal(Sspm->history_relay);
Sspm->history_channel = relay & 0x03; // Channel relays are NOT bit masked this time
SSPMSendGetEnergyTotal(XdrvMailbox.index -1);
ResponseClear(); ResponseClear();
} }