Changed command `TimedPower` refactored from String to LList

This commit is contained in:
Theo Arends 2024-01-21 14:29:44 +01:00
parent 4a4fe27cee
commit 95f76d623f
5 changed files with 40 additions and 60 deletions

View File

@ -17,7 +17,7 @@ All notable changes to this project will be documented in this file.
- Berry solidification of strings longer than 255 bytes (#20529) - Berry solidification of strings longer than 255 bytes (#20529)
- Berry syntax coloring for Notepad++ by FransO (#20541) - Berry syntax coloring for Notepad++ by FransO (#20541)
- Berry/Zigbee web hook per device for customized status display (#20542) - Berry/Zigbee web hook per device for customized status display (#20542)
- Zigbee ``ZbEmulation`` to selectively exclude some devices from Hue/Alexa emulation - Zigbee ``ZbEmulation`` to selectively exclude some devices from Hue/Alexa emulation (#20552)
### Breaking Changed ### Breaking Changed
@ -28,6 +28,7 @@ All notable changes to this project will be documented in this file.
- ESP8266 platform update from 2024.01.00 to 2024.01.01 (#20539) - ESP8266 platform update from 2024.01.00 to 2024.01.01 (#20539)
- ESP8266 Framework (Arduino Core) from v2.7.5 to v2.7.6 (#20539) - ESP8266 Framework (Arduino Core) from v2.7.5 to v2.7.6 (#20539)
- Refactor Pio filesystem download script (#20544) - Refactor Pio filesystem download script (#20544)
- Command ``TimedPower`` refactored from String to LList
### Fixed ### Fixed
- Scripter memory leak in `>w x` (#20473) - Scripter memory leak in `>w x` (#20473)

View File

@ -149,6 +149,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
- Berry solidification of strings longer than 255 bytes [#20529](https://github.com/arendst/Tasmota/issues/20529) - Berry solidification of strings longer than 255 bytes [#20529](https://github.com/arendst/Tasmota/issues/20529)
- Berry syntax coloring for Notepad++ by FransO [#20541](https://github.com/arendst/Tasmota/issues/20541) - Berry syntax coloring for Notepad++ by FransO [#20541](https://github.com/arendst/Tasmota/issues/20541)
- Berry/Zigbee web hook per device for customized status display [#20542](https://github.com/arendst/Tasmota/issues/20542) - Berry/Zigbee web hook per device for customized status display [#20542](https://github.com/arendst/Tasmota/issues/20542)
- Zigbee ``ZbEmulation`` to selectively exclude some devices from Hue/Alexa emulation [#20552](https://github.com/arendst/Tasmota/issues/20552)
- LVGL `lv.str_arr` [#20480](https://github.com/arendst/Tasmota/issues/20480) - LVGL `lv.str_arr` [#20480](https://github.com/arendst/Tasmota/issues/20480)
- LVGL option to add `lv.keyboard` extra widget [#20496](https://github.com/arendst/Tasmota/issues/20496) - LVGL option to add `lv.keyboard` extra widget [#20496](https://github.com/arendst/Tasmota/issues/20496)
- HASPmota `haspmota.page_show()` to change page [#20333](https://github.com/arendst/Tasmota/issues/20333) - HASPmota `haspmota.page_show()` to change page [#20333](https://github.com/arendst/Tasmota/issues/20333)

View File

@ -221,7 +221,6 @@ const uint16_t MAX_LOGSZ = 700; // Max number of characters in log l
const uint8_t SENSOR_MAX_MISS = 5; // Max number of missed sensor reads before deciding it's offline const uint8_t SENSOR_MAX_MISS = 5; // Max number of missed sensor reads before deciding it's offline
const uint32_t MIN_BACKLOG_DELAY = 200; // Minimal backlog delay in mSeconds const uint32_t MIN_BACKLOG_DELAY = 200; // Minimal backlog delay in mSeconds
const uint8_t MAX_TIMED_CMND = 16; // Max number of timed commands
const uint32_t SOFT_BAUDRATE = 9600; // Default software serial baudrate const uint32_t SOFT_BAUDRATE = 9600; // Default software serial baudrate
const uint32_t APP_BAUDRATE = 115200; // Default serial baudrate const uint32_t APP_BAUDRATE = 115200; // Default serial baudrate

View File

@ -294,11 +294,6 @@ HardwareSerial TasConsole = Serial; // Only serial interface
char EmptyStr[1] = { 0 }; // Provide a pointer destination to an empty char string char EmptyStr[1] = { 0 }; // Provide a pointer destination to an empty char string
typedef struct {
uint32_t time;
String command;
} tTimedCmnd;
struct TasmotaGlobal_t { struct TasmotaGlobal_t {
uint32_t global_update; // Timestamp of last global temperature and humidity update uint32_t global_update; // Timestamp of last global temperature and humidity update
uint32_t baudrate; // Current Serial baudrate uint32_t baudrate; // Current Serial baudrate
@ -413,8 +408,6 @@ struct TasmotaGlobal_t {
uint8_t pwm_dimmer_led_bri; // Adjusted brightness LED level uint8_t pwm_dimmer_led_bri; // Adjusted brightness LED level
#endif // USE_PWM_DIMMER #endif // USE_PWM_DIMMER
tTimedCmnd timed_cmnd[MAX_TIMED_CMND]; // Timed command buffer
#ifdef MQTT_DATA_STRING #ifdef MQTT_DATA_STRING
String mqtt_data; // Buffer filled by Response functions String mqtt_data; // Buffer filled by Response functions
#else #else

View File

@ -655,44 +655,38 @@ void CmndPower(void)
/********************************************************************************************/ /********************************************************************************************/
typedef struct {
uint32_t time;
char* command;
} tTimedCmnd;
LList<tTimedCmnd> timed_cmnd; // Timed command buffer
bool SetTimedCmnd(uint32_t time, const char *command) { bool SetTimedCmnd(uint32_t time, const char *command) {
uint32_t now = millis(); // Remove command if present
// Try to use the same slot if command is already present for (auto &elem : timed_cmnd) {
for (uint32_t i = 0; i < MAX_TIMED_CMND; i++) { if (strcmp(command, elem.command) == 0) { // Equal
if (TasmotaGlobal.timed_cmnd[i].time != 0) { free(elem.command);
if (!strcmp(command, TasmotaGlobal.timed_cmnd[i].command.c_str())) { timed_cmnd.remove(&elem);
// Stored command already present break;
TasmotaGlobal.timed_cmnd[i].time = now + time;
if (0 == TasmotaGlobal.timed_cmnd[i].time) { // Skip empty slot flag
TasmotaGlobal.timed_cmnd[i].time++;
}
return true;
}
} }
} }
// Try to find an empty slot and add command // Add command
for (uint32_t i = 0; i < MAX_TIMED_CMND; i++) { char* cmnd = (char*)malloc(strlen(command) +1);
if (0 == TasmotaGlobal.timed_cmnd[i].time) { // Free slot if (cmnd) {
TasmotaGlobal.timed_cmnd[i].command = command; strcpy(cmnd, command);
TasmotaGlobal.timed_cmnd[i].time = now + time; tTimedCmnd &elem = timed_cmnd.addToLast();
if (0 == TasmotaGlobal.timed_cmnd[i].time) { // Skip empty slot flag elem.time = millis() + time;
TasmotaGlobal.timed_cmnd[i].time++; elem.command = cmnd;
} return true;
return true;
}
} }
AddLog(LOG_LEVEL_INFO, PSTR("TIM: No more timer slots left"));
return false; return false;
} }
void ResetTimedCmnd(const char *command) { void ResetTimedCmnd(const char *command) {
for (uint32_t i = 0; i < MAX_TIMED_CMND; i++) { for (auto &elem : timed_cmnd) {
if (TasmotaGlobal.timed_cmnd[i].time != 0) { if (strncmp(command, elem.command, strlen(command)) == 0) { // StartsWith
if (!strncmp(command, TasmotaGlobal.timed_cmnd[i].command.c_str(), strlen(command))) { free(elem.command);
// Stored command starts with command timed_cmnd.remove(&elem);
TasmotaGlobal.timed_cmnd[i].time = 0;
TasmotaGlobal.timed_cmnd[i].command = (const char*) nullptr; // Force deallocation of the String internal memory
}
} }
} }
} }
@ -701,31 +695,23 @@ void ShowTimedCmnd(const char *command) {
bool found = false; bool found = false;
uint32_t now = millis(); uint32_t now = millis();
Response_P(PSTR("{\"%s\":"), XdrvMailbox.command); Response_P(PSTR("{\"%s\":"), XdrvMailbox.command);
for (uint32_t i = 0; i < MAX_TIMED_CMND; i++) { for (auto &elem : timed_cmnd) {
if (TasmotaGlobal.timed_cmnd[i].time != 0) { if (strncmp(command, elem.command, strlen(command)) == 0) { // StartsWith
if (!strncmp(command, TasmotaGlobal.timed_cmnd[i].command.c_str(), strlen(command))) { ResponseAppend_P(PSTR("%s{\"" D_JSON_REMAINING "\":%d,\"" D_JSON_COMMAND "\":\"%s\"}"),
// Stored command starts with command (found) ? "," : "[", elem.time - now, elem.command);
ResponseAppend_P(PSTR("%s"), (found) ? "," : "["); found = true;
found = true;
ResponseAppend_P(PSTR("{\"" D_JSON_REMAINING "\":%d,\"" D_JSON_COMMAND "\":\"%s\"}"), TasmotaGlobal.timed_cmnd[i].time - now, TasmotaGlobal.timed_cmnd[i].command.c_str());
}
} }
} }
if (found) { ResponseAppend_P((found) ? PSTR("]}") : PSTR("\"" D_JSON_EMPTY "\"}"));
ResponseAppend_P(PSTR("]}"));
} else {
ResponseAppend_P(PSTR("\"" D_JSON_EMPTY "\"}"));
}
} }
void LoopTimedCmnd(void) { void LoopTimedCmnd(void) {
uint32_t now = millis(); for (auto &elem : timed_cmnd) {
for (uint32_t i = 0; i < MAX_TIMED_CMND; i++) { if (TimeReached(elem.time)) {
if ((TasmotaGlobal.timed_cmnd[i].time > 0) && (now > TasmotaGlobal.timed_cmnd[i].time)) { char* command = elem.command;
TasmotaGlobal.timed_cmnd[i].time = 0; timed_cmnd.remove(&elem);
String cmd = TasmotaGlobal.timed_cmnd[i].command; ExecuteCommand(command, SRC_TIMER);
TasmotaGlobal.timed_cmnd[i].command = (const char*) nullptr; // Force deallocation of the String internal memory free(command);
ExecuteCommand((char*)cmd.c_str(), SRC_TIMER);
} }
} }
} }
@ -763,7 +749,7 @@ void CmndTimedPower(void) {
const uint8_t end_state[] = { POWER_ON, POWER_OFF, POWER_TOGGLE, POWER_BLINK_STOP }; const uint8_t end_state[] = { POWER_ON, POWER_OFF, POWER_TOGGLE, POWER_BLINK_STOP };
char cmnd[CMDSZ]; char cmnd[CMDSZ];
snprintf_P(cmnd, sizeof(cmnd), PSTR(D_CMND_POWER "%d %d"), XdrvMailbox.index, end_state[start_state]); snprintf_P(cmnd, sizeof(cmnd), PSTR(D_CMND_POWER "%d %d"), XdrvMailbox.index, end_state[start_state]);
if (SetTimedCmnd(time, cmnd)) { // Skip if no more timers left (MAX_TIMED_CMND) if (SetTimedCmnd(time, cmnd)) { // Skip if no more room for timers
XdrvMailbox.payload = start_state; XdrvMailbox.payload = start_state;
CmndPower(); CmndPower();
} }