mirror of https://github.com/arendst/Tasmota.git
Rewrite Sonoff SPM state machine
- Rewrite Sonoff SPM state machine for easier maintenance - Fix handling user output when initiating a scan
This commit is contained in:
parent
25f23b2406
commit
efb77a6547
|
@ -30,7 +30,7 @@
|
|||
* Bulk of the action is handled by ARM processors present in every unit communicating over modbus RS-485.
|
||||
* Each SPM-4Relay has 4 bistable relays with their own CSE7761 energy monitoring device handled by an ARM processor.
|
||||
* Green led is controlled by ARM processor indicating SD-Card access.
|
||||
* ESP32 is used as interface between Welink 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.
|
||||
* Inductive/Capacitive loads are not reported correctly.
|
||||
* Power on sequence for two SPM-4Relay modules is 00-00-15-10-(0F)-(13)-(13)-(19)-0C-09-04-09-04-0B-0B
|
||||
*
|
||||
|
@ -124,10 +124,19 @@
|
|||
|
||||
#define SSPM_MODULE_NAME_SIZE 12
|
||||
|
||||
enum SspmInitSteps { SPM_NONE, SPM_WAIT, SPM_RESET, SPM_POLL, SPM_POLL_ACK, SPM_SEND_FUNC_UNITS, SPM_STEP_WAIT2,
|
||||
SPM_DEVICES_FOUND,
|
||||
SPM_GET_ENERGY_TOTALS,
|
||||
SPM_ALLOW_LOOP};
|
||||
enum SspmMachineStates { SPM_NONE, // Do nothing
|
||||
SPM_WAIT, // Wait 100ms
|
||||
SPM_RESET, // Toggle ARM reset pin
|
||||
SPM_POLL_ARM, // Wait for first acknowledge from ARM after reset
|
||||
SPM_POLL_ARM_2, // Wait for second acknowledge from ARM after reset
|
||||
SPM_SEND_FUNC_UNITS, // Get number of units
|
||||
SPM_START_SCAN, // Start module scan sequence
|
||||
SPM_WAIT_FOR_SCAN, // Wait for scan sequence to complete
|
||||
SPM_SCAN_COMPLETE, // Scan complete
|
||||
SPM_GET_ENERGY_TOTALS, // Init available Energy totals registers
|
||||
SPM_UPDATE_CHANNELS, // Update Energy for powered on channels
|
||||
SPM_UPDATE_TOTALS // Update Energy totals for powered on channels
|
||||
};
|
||||
|
||||
#include <TasmotaSerial.h>
|
||||
TasmotaSerial *SspmSerial;
|
||||
|
@ -156,7 +165,7 @@ typedef struct {
|
|||
uint8_t counter;
|
||||
uint8_t command_sequence;
|
||||
uint8_t loop_step;
|
||||
uint8_t init_step;
|
||||
uint8_t mstate;
|
||||
uint8_t last_button;
|
||||
bool discovery_triggered;
|
||||
} TSspm;
|
||||
|
@ -528,7 +537,7 @@ void SSPMHandleReceivedData(void) {
|
|||
|Er| |St|
|
||||
*/
|
||||
if ((1 == Sspm->expected_bytes) && (0 == SspmBuffer[19])) {
|
||||
Sspm->init_step++;
|
||||
Sspm->mstate++; // Cycle to
|
||||
}
|
||||
break;
|
||||
case SSPM_FUNC_GET_OPS:
|
||||
|
@ -591,15 +600,14 @@ void SSPMHandleReceivedData(void) {
|
|||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("SPM: Relay scan done"));
|
||||
|
||||
Sspm->init_step = SPM_DEVICES_FOUND;
|
||||
// Sspm->get_energy_relay = 1;
|
||||
// Sspm->allow_updates = 1; // Enable requests from 100mSec loop
|
||||
Sspm->mstate = SPM_SCAN_COMPLETE;
|
||||
}
|
||||
break;
|
||||
case SSPM_FUNC_SET_TIME:
|
||||
/* 0x0C
|
||||
AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 0c 00 01 00 04 3e 62
|
||||
*/
|
||||
TasmotaGlobal.devices_present = 0;
|
||||
SSPMSendGetModuleState(Sspm->module_selected -1);
|
||||
break;
|
||||
case SSPM_FUNC_INIT_SCAN:
|
||||
|
@ -607,7 +615,6 @@ void SSPMHandleReceivedData(void) {
|
|||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
||||
AA 55 01 ff ff ff ff ff ff ff ff ff ff ff ff 80 10 00 01 00 02 e5 03
|
||||
*/
|
||||
Sspm->module_max = 0;
|
||||
break;
|
||||
case SSPM_FUNC_UNITS:
|
||||
/* 0x15
|
||||
|
@ -615,7 +622,7 @@ void SSPMHandleReceivedData(void) {
|
|||
AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 15 00 04 00 01 00 00 01 81 b1
|
||||
|?? ?? ?? ??|
|
||||
*/
|
||||
SSPMSendInitScan();
|
||||
Sspm->mstate = SPM_START_SCAN;
|
||||
break;
|
||||
case SSPM_FUNC_GET_ENERGY_TOTAL:
|
||||
/* 0x16
|
||||
|
@ -746,7 +753,6 @@ void SSPMHandleReceivedData(void) {
|
|||
/* 0x0F
|
||||
AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 00 01 02 01 9d f8
|
||||
*/
|
||||
// Sspm->module_max = 0;
|
||||
SSPMSendAck(command_sequence);
|
||||
break;
|
||||
case SSPM_FUNC_SCAN_RESULT:
|
||||
|
@ -851,7 +857,7 @@ void SSPMInit(void) {
|
|||
}
|
||||
|
||||
Sspm->old_power = TasmotaGlobal.power;
|
||||
Sspm->init_step = SPM_WAIT; // Start init sequence
|
||||
Sspm->mstate = SPM_WAIT; // Start init sequence
|
||||
}
|
||||
|
||||
void SSPMEvery100ms(void) {
|
||||
|
@ -865,17 +871,18 @@ void SSPMEvery100ms(void) {
|
|||
}
|
||||
|
||||
// Fix race condition if the ARM doesn't respond
|
||||
if ((Sspm->init_step > SPM_NONE) && (Sspm->init_step < SPM_SEND_FUNC_UNITS)) {
|
||||
if ((Sspm->mstate > SPM_NONE) && (Sspm->mstate < SPM_SEND_FUNC_UNITS)) {
|
||||
Sspm->counter++;
|
||||
if (Sspm->counter > 20) {
|
||||
Sspm->init_step = SPM_NONE;
|
||||
Sspm->mstate = SPM_NONE;
|
||||
}
|
||||
}
|
||||
switch (Sspm->init_step) {
|
||||
switch (Sspm->mstate) {
|
||||
case SPM_NONE:
|
||||
return;
|
||||
case SPM_WAIT:
|
||||
Sspm->init_step++;
|
||||
// 100ms wait
|
||||
Sspm->mstate = SPM_RESET;
|
||||
break;
|
||||
case SPM_RESET:
|
||||
// Reset ARM
|
||||
|
@ -883,22 +890,34 @@ void SSPMEvery100ms(void) {
|
|||
delay(18);
|
||||
digitalWrite(SSPM_GPIO_ARM_RESET, 1);
|
||||
delay(18);
|
||||
Sspm->init_step++;
|
||||
case SPM_POLL:
|
||||
Sspm->mstate = SPM_POLL_ARM;
|
||||
case SPM_POLL_ARM:
|
||||
// Wait for first acknowledge from ARM after reset
|
||||
SSPMSendCmnd(SSPM_FUNC_FIND);
|
||||
break;
|
||||
case SPM_POLL_ACK:
|
||||
case SPM_POLL_ARM_2:
|
||||
// Wait for second acknowledge from ARM after reset
|
||||
SSPMSendCmnd(SSPM_FUNC_FIND);
|
||||
break;
|
||||
case SPM_SEND_FUNC_UNITS:
|
||||
Sspm->init_step++;
|
||||
// Get number of units
|
||||
SSPMSendCmnd(SSPM_FUNC_UNITS);
|
||||
break;
|
||||
case SPM_DEVICES_FOUND:
|
||||
TasmotaGlobal.discovery_counter = 1; // force TasDiscovery()
|
||||
case SPM_START_SCAN:
|
||||
// Start scan module sequence
|
||||
Sspm->module_max = 0;
|
||||
SSPMSendInitScan();
|
||||
Sspm->mstate = SPM_WAIT_FOR_SCAN;
|
||||
break;
|
||||
case SPM_WAIT_FOR_SCAN:
|
||||
// Wait for scan sequence to complete
|
||||
break;
|
||||
case SPM_SCAN_COMPLETE:
|
||||
// Scan sequence finished
|
||||
TasmotaGlobal.discovery_counter = 1; // Force TasDiscovery()
|
||||
Sspm->get_energy_relay = 1;
|
||||
Sspm->allow_updates = 1; // Enable requests from 100mSec loop
|
||||
Sspm->init_step++;
|
||||
Sspm->allow_updates = 1; // Enable requests from 100mSec loop
|
||||
Sspm->mstate = SPM_GET_ENERGY_TOTALS;
|
||||
break;
|
||||
case SPM_GET_ENERGY_TOTALS:
|
||||
// Retrieve Energy total status from up to 128 relays
|
||||
|
@ -908,47 +927,54 @@ void SSPMEvery100ms(void) {
|
|||
Sspm->get_energy_relay++;
|
||||
if (Sspm->get_energy_relay > TasmotaGlobal.devices_present) {
|
||||
Sspm->get_energy_relay = 1;
|
||||
Sspm->init_step++;
|
||||
Sspm->mstate = SPM_UPDATE_CHANNELS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPM_ALLOW_LOOP:
|
||||
// Retrieve Energy status from up to 128 relays
|
||||
case SPM_UPDATE_CHANNELS:
|
||||
// Retrieve Energy status from up to 128 powered on relays
|
||||
if (Sspm->allow_updates && (Sspm->get_energy_relay > 0)) {
|
||||
power_t powered_on = TasmotaGlobal.power >> (Sspm->get_energy_relay -1);
|
||||
if (0 == Sspm->loop_step) {
|
||||
// Get energy total only once in any 256 requests to safe comms
|
||||
if (powered_on &1) {
|
||||
SSPMSetLock(4);
|
||||
SSPMSendGetEnergyTotal(Sspm->get_energy_relay -1);
|
||||
}
|
||||
Sspm->get_energy_relay++;
|
||||
if (Sspm->get_energy_relay > TasmotaGlobal.devices_present) {
|
||||
Sspm->get_energy_relay = 1;
|
||||
Sspm->loop_step++;
|
||||
}
|
||||
if (powered_on &1) {
|
||||
SSPMSetLock(4);
|
||||
SSPMSendGetEnergy(Sspm->get_energy_relay -1);
|
||||
} else {
|
||||
if (powered_on &1) {
|
||||
SSPMSetLock(4);
|
||||
SSPMSendGetEnergy(Sspm->get_energy_relay -1);
|
||||
} else {
|
||||
uint32_t relay_set = (Sspm->get_energy_relay -1) >> 2;
|
||||
uint32_t relay_num = (Sspm->get_energy_relay -1) &3;
|
||||
if (Sspm->voltage[relay_set][relay_num]) {
|
||||
Sspm->voltage[relay_set][relay_num] = 0;
|
||||
Sspm->current[relay_set][relay_num] = 0;
|
||||
Sspm->active_power[relay_set][relay_num] = 0;
|
||||
Sspm->apparent_power[relay_set][relay_num] = 0;
|
||||
Sspm->reactive_power[relay_set][relay_num] = 0;
|
||||
Sspm->power_factor[relay_set][relay_num] = 0;
|
||||
}
|
||||
}
|
||||
Sspm->loop_step++; // Rolls over after 256 so allows for scanning at least all relays twice
|
||||
Sspm->get_energy_relay++;
|
||||
if ((Sspm->get_energy_relay > TasmotaGlobal.devices_present) || !Sspm->loop_step) {
|
||||
Sspm->get_energy_relay = 1;
|
||||
uint32_t relay_set = (Sspm->get_energy_relay -1) >> 2;
|
||||
uint32_t relay_num = (Sspm->get_energy_relay -1) &3;
|
||||
if (Sspm->voltage[relay_set][relay_num]) {
|
||||
Sspm->voltage[relay_set][relay_num] = 0;
|
||||
Sspm->current[relay_set][relay_num] = 0;
|
||||
Sspm->active_power[relay_set][relay_num] = 0;
|
||||
Sspm->apparent_power[relay_set][relay_num] = 0;
|
||||
Sspm->reactive_power[relay_set][relay_num] = 0;
|
||||
Sspm->power_factor[relay_set][relay_num] = 0;
|
||||
}
|
||||
}
|
||||
Sspm->get_energy_relay++;
|
||||
if (Sspm->get_energy_relay > TasmotaGlobal.devices_present) {
|
||||
Sspm->get_energy_relay = 1;
|
||||
}
|
||||
Sspm->loop_step++; // Rolls over after 256 so allows for scanning at least all relays twice
|
||||
if (!Sspm->loop_step) {
|
||||
Sspm->get_energy_relay = 1;
|
||||
Sspm->mstate = SPM_UPDATE_TOTALS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPM_UPDATE_TOTALS:
|
||||
// Retrieve Energy totals from up to 128 powered on relays
|
||||
if (Sspm->allow_updates && (Sspm->get_energy_relay > 0)) {
|
||||
power_t powered_on = TasmotaGlobal.power >> (Sspm->get_energy_relay -1);
|
||||
// Get energy total only once in any 256 requests to safe comms
|
||||
if (powered_on &1) {
|
||||
SSPMSetLock(4);
|
||||
SSPMSendGetEnergyTotal(Sspm->get_energy_relay -1);
|
||||
}
|
||||
Sspm->get_energy_relay++;
|
||||
if (Sspm->get_energy_relay > TasmotaGlobal.devices_present) {
|
||||
Sspm->get_energy_relay = 1;
|
||||
Sspm->mstate = SPM_UPDATE_CHANNELS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -973,7 +999,7 @@ bool SSPMButton(void) {
|
|||
bool result = false;
|
||||
uint32_t button = XdrvMailbox.payload;
|
||||
if ((PRESSED == button) && (NOT_PRESSED == Sspm->last_button)) { // Button pressed
|
||||
SSPMSendInitScan();
|
||||
Sspm->mstate = SPM_START_SCAN;
|
||||
result = true; // Disable further button processing
|
||||
}
|
||||
Sspm->last_button = button;
|
||||
|
@ -1025,10 +1051,9 @@ void SSPMEnergyShow(bool json) {
|
|||
ResponseAppend_P(PSTR("]}"));
|
||||
} else {
|
||||
Sspm->rotate++;
|
||||
if ((Sspm->rotate >> 2) == Sspm->module_max) {
|
||||
if (Sspm->rotate >= TasmotaGlobal.devices_present) {
|
||||
Sspm->rotate = 0;
|
||||
}
|
||||
|
||||
uint32_t module = Sspm->rotate >> 2;
|
||||
uint32_t relay_base = module * 4;
|
||||
WSContentSend_P(PSTR("{s}" D_SENSOR_RELAY "{m}L%02d / L%02d / L%02d / L%02d{e}"), relay_base +1, relay_base +2, relay_base +3, relay_base +4);
|
||||
|
@ -1077,9 +1102,8 @@ void CmndSSPMEnergyHistory(void) {
|
|||
}
|
||||
|
||||
void CmndSSPMScan(void) {
|
||||
SSPMSendInitScan();
|
||||
|
||||
ResponseCmndDone();
|
||||
Sspm->mstate = SPM_START_SCAN;
|
||||
ResponseCmndChar(PSTR(D_JSON_STARTED));
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
|
Loading…
Reference in New Issue