"),
- ((9==i)||(10==i)) ? WebColor(COL_TEXT_WARNING) : WebColor(COL_TEXT), i, (0==i) ? " style='width:150px'" : "", i, i);
+ ((9==i)||(10==i)) ? WebColor(COL_TEXT_WARNING) : WebColor(COL_TEXT), i, (0==i) ? PSTR(" style='width:150px'") : "", i, i);
WSContentSend_P(PSTR("
"), i);
}
}
@@ -1824,7 +1824,7 @@ void HandleLoggingConfiguration(void)
idx);
for (uint32_t i = LOG_LEVEL_NONE; i <= LOG_LEVEL_DEBUG_MORE; i++) {
WSContentSend_P(PSTR(""),
- (i == llevel) ? " selected" : "", i, i,
+ (i == llevel) ? PSTR(" selected") : "", i, i,
GetTextIndexed(stemp1, sizeof(stemp1), i, kLoggingLevels));
}
WSContentSend_P(PSTR("
"));
@@ -1880,8 +1880,8 @@ void HandleOtherConfiguration(void)
TemplateJson();
char stemp[strlen(TasmotaGlobal.mqtt_data) +1];
strlcpy(stemp, TasmotaGlobal.mqtt_data, sizeof(stemp)); // Get JSON template
- WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? " checked disabled" : "",
- (Settings.flag.mqtt_enabled) ? " checked" : "", // SetOption3 - Enable MQTT
+ WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? PSTR(" checked disabled") : "",
+ (Settings.flag.mqtt_enabled) ? PSTR(" checked") : "", // SetOption3 - Enable MQTT
SettingsText(SET_FRIENDLYNAME1), SettingsText(SET_DEVICENAME));
uint32_t maxfn = (TasmotaGlobal.devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!TasmotaGlobal.devices_present) ? 1 : TasmotaGlobal.devices_present;
@@ -1911,9 +1911,9 @@ void HandleOtherConfiguration(void)
if (i < EMUL_MAX) {
WSContentSend_P(PSTR("%s %s "), // Different id only used for labels
i, i,
- (i == Settings.flag2.emulation) ? " checked" : "",
+ (i == Settings.flag2.emulation) ? PSTR(" checked") : "",
GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions),
- (i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE);
+ (i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? PSTR(D_SINGLE_DEVICE) : PSTR(D_MULTI_DEVICE));
}
}
WSContentSend_P(PSTR(""));
@@ -2086,7 +2086,7 @@ void HandleInformation(void)
#ifdef ESP32
#ifdef USE_ETHERNET
if (static_cast(EthernetLocalIP()) != 0) {
- WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? ".local" : "");
+ WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? PSTR(".local") : "");
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (eth)}2%s"), EthernetLocalIP().toString().c_str());
WSContentSend_P(PSTR("}1}2"));
@@ -2096,7 +2096,7 @@ void HandleInformation(void)
if (Settings.flag4.network_wifi) {
int32_t rssi = WiFi.RSSI();
WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings.sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi);
- WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), TasmotaGlobal.hostname, (Mdns.begun) ? ".local" : "");
+ WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), TasmotaGlobal.hostname, (Mdns.begun) ? PSTR(".local") : "");
#if LWIP_IPV6
String ipv6_addr = WifiGetIPv6();
if (ipv6_addr != "") {
@@ -2169,15 +2169,15 @@ void HandleInformation(void)
#ifdef ESP8266
WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP.getFlashChipId());
#endif
- WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP.getFlashChipRealSize() / 1024);
- WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%dkB"), ESP.getFlashChipSize() / 1024);
- WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%dkB"), ESP_getSketchSize() / 1024);
- WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%dkB"), ESP.getFreeSketchSpace() / 1024);
- WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%dkB"), freeMem / 1024);
+ WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%d kB"), ESP.getFlashChipRealSize() / 1024);
+ WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%d kB"), ESP.getFlashChipSize() / 1024);
+ WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%d kB"), ESP_getSketchSize() / 1024);
+ WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%d kB"), ESP.getFreeSketchSpace() / 1024);
+ WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%d kB"), freeMem / 1024);
#ifdef ESP32
if (psramFound()) {
- WSContentSend_P(PSTR("}1" D_PSR_MAX_MEMORY "}2%dkB"), ESP.getPsramSize() / 1024);
- WSContentSend_P(PSTR("}1" D_PSR_FREE_MEMORY "}2%dkB"), ESP.getFreePsram() / 1024);
+ WSContentSend_P(PSTR("}1" D_PSR_MAX_MEMORY "}2%d kB"), ESP.getPsramSize() / 1024);
+ WSContentSend_P(PSTR("}1" D_PSR_FREE_MEMORY "}2%d kB"), ESP.getFreePsram() / 1024);
}
#endif
WSContentSend_P(PSTR(""));
@@ -2522,7 +2522,7 @@ void HandleUploadLoop(void) {
return;
}
if (upload.totalSize && !(upload.totalSize % 102400)) {
- AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Progress %dkB"), upload.totalSize / 1024);
+ AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Progress %d kB"), upload.totalSize / 1024);
}
}
@@ -2788,7 +2788,7 @@ bool CaptivePortal(void)
if ((WifiIsInManagerMode()) && !ValidIpAddress(Webserver->hostHeader().c_str())) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED));
- Webserver->sendHeader(F("Location"), String("http://") + Webserver->client().localIP().toString(), true);
+ Webserver->sendHeader(F("Location"), String(F("http://")) + Webserver->client().localIP().toString(), true);
WSSend(302, CT_PLAIN, ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
Webserver->client().stop(); // Stop is needed because we sent no content length
return true;
diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino
index dcd21930f..9a0acba75 100644
--- a/tasmota/xdrv_02_mqtt.ino
+++ b/tasmota/xdrv_02_mqtt.ino
@@ -679,8 +679,13 @@ void MqttReconnect(void) {
if (MqttClient.connect(TasmotaGlobal.mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, lwt_retain, TasmotaGlobal.mqtt_data, MQTT_CLEAN_SESSION)) {
#ifdef USE_MQTT_TLS
if (Mqtt.mqtt_tls) {
+#ifdef ESP8266
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connected in %d ms, max ThunkStack used %d"),
millis() - mqtt_connect_time, tlsClient->getMaxThunkStackUse());
+#elif defined(ESP32)
+ AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connected in %d ms, stack low mark %d"),
+ millis() - mqtt_connect_time, uxTaskGetStackHighWaterMark(nullptr));
+#endif
if (!tlsClient->getMFLNStatus()) {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "MFLN not supported by TLS server"));
}
@@ -1275,7 +1280,7 @@ void HandleMqttConfiguration(void)
SettingsText(SET_MQTT_HOST),
Settings.mqtt_port,
#ifdef USE_MQTT_TLS
- Mqtt.mqtt_tls ? " checked" : "", // SetOption102 - Enable MQTT TLS
+ Mqtt.mqtt_tls ? PSTR(" checked") : "", // SetOption102 - Enable MQTT TLS
#endif // USE_MQTT_TLS
Format(str, MQTT_CLIENT_ID, sizeof(str)), MQTT_CLIENT_ID, SettingsText(SET_MQTT_CLIENT));
WSContentSend_P(HTTP_FORM_MQTT2,
diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino
index 7c7ba932e..f57431203 100644
--- a/tasmota/xdrv_03_energy.ino
+++ b/tasmota/xdrv_03_energy.ino
@@ -537,6 +537,7 @@ void EnergyEverySecond(void)
}
if (!data_valid) {
Energy.start_energy = 0;
+ AddLog_P(LOG_LEVEL_DEBUG, PSTR("NRG: Energy reset by " STR(ENERGY_WATCHDOG) " seconds invalid data"));
XnrgCall(FUNC_ENERGY_RESET);
}
diff --git a/tasmota/xdrv_09_timers.ino b/tasmota/xdrv_09_timers.ino
index c40045a31..0f6292e13 100644
--- a/tasmota/xdrv_09_timers.ino
+++ b/tasmota/xdrv_09_timers.ino
@@ -305,7 +305,7 @@ void PrepShowTimer(uint32_t index)
char days[8] = { 0 };
for (uint32_t i = 0; i < 7; i++) {
uint8_t mask = 1 << i;
- snprintf(days, sizeof(days), "%s%d", days, ((xtimer.days & mask) > 0));
+ snprintf(days, sizeof(days), PSTR("%s%d"), days, ((xtimer.days & mask) > 0));
}
char soutput[80];
@@ -857,7 +857,7 @@ void HandleTimerConfiguration(void)
WSContentSend_P(HTTP_TIMER_SCRIPT5, MAX_TIMERS, TasmotaGlobal.devices_present);
WSContentSend_P(HTTP_TIMER_SCRIPT6, TasmotaGlobal.devices_present);
WSContentSendStyle_P(HTTP_TIMER_STYLE, WebColor(COL_FORM));
- WSContentSend_P(HTTP_FORM_TIMER1, (Settings.flag3.timers_enable) ? " checked" : ""); // CMND_TIMERS
+ WSContentSend_P(HTTP_FORM_TIMER1, (Settings.flag3.timers_enable) ? PSTR(" checked") : ""); // CMND_TIMERS
for (uint32_t i = 0; i < MAX_TIMERS; i++) {
WSContentSend_P(PSTR("%s%u"), (i > 0) ? "," : "", Settings.timer[i].data);
}
diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino
index 8f1a3e2be..cd07098f8 100755
--- a/tasmota/xdrv_10_scripter.ino
+++ b/tasmota/xdrv_10_scripter.ino
@@ -4550,53 +4550,59 @@ int16_t Run_script_sub(const char *type, int8_t tlen, JsonParserObject *jo) {
if (*ctype=='#') {
// check for parameter
ctype += tlen;
- if (*ctype=='(' && *(lp+tlen)=='(') {
- float fparam;
- numeric = 1;
- glob_script_mem.glob_error = 0;
- GetNumericArgument((char*)ctype, OPER_EQU, &fparam, 0);
- if (glob_script_mem.glob_error==1) {
- // was string, not number
- numeric = 0;
- // get the string
- GetStringArgument((char*)ctype + 1, OPER_EQU, cmpstr, 0);
- }
- lp += tlen;
- if (*lp=='(') {
- // fetch destination
- lp++;
- lp = isvar(lp, &vtype, &ind, 0, 0, 0);
- if (vtype!=VAR_NV) {
- // found variable as result
- uint8_t index = glob_script_mem.type[ind.index].index;
- if ((vtype&STYPE)==0) {
- // numeric result
- dfvar = &glob_script_mem.fvars[index];
- if (numeric) {
- *dfvar = fparam;
- } else {
- // mismatch
- *dfvar = CharToFloat(cmpstr);
- }
- } else {
- // string result
- sindex = index;
- if (!numeric) {
- strlcpy(glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize), cmpstr, glob_script_mem.max_ssize);
- } else {
- // mismatch
- dtostrfd(fparam, 6, glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize));
- }
+ char nxttok = '(';
+ char *argptr = ctype+tlen;
+
+ lp += tlen;
+ do {
+ if (*ctype==nxttok && *lp==nxttok) {
+ float fparam;
+ numeric = 1;
+ glob_script_mem.glob_error = 0;
+ argptr = GetNumericArgument((char*)ctype + 1, OPER_EQU, &fparam, 0);
+ if (glob_script_mem.glob_error==1) {
+ // was string, not number
+ numeric = 0;
+ // get the string
+ argptr = GetStringArgument((char*)ctype + 1, OPER_EQU, cmpstr, 0);
+ }
+ if (*lp==nxttok) {
+ // fetch destination
+ lp++;
+ lp = isvar(lp, &vtype, &ind, 0, 0, 0);
+ if (vtype!=VAR_NV) {
+ // found variable as result
+ uint8_t index = glob_script_mem.type[ind.index].index;
+ if ((vtype&STYPE)==0) {
+ // numeric result
+ dfvar = &glob_script_mem.fvars[index];
+ if (numeric) {
+ *dfvar = fparam;
+ } else {
+ // mismatch
+ *dfvar = CharToFloat(cmpstr);
+ }
+ } else {
+ // string result
+ sindex = index;
+ if (!numeric) {
+ strlcpy(glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize), cmpstr, glob_script_mem.max_ssize);
+ } else {
+ // mismatch
+ dtostrfd(fparam, 6, glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize));
+ }
+ }
}
}
+ } else {
+ if (*ctype==nxttok || (*lp!=SCRIPT_EOL && *lp!='?')) {
+ // revert
+ section = 0;
+ }
}
- } else {
- lp += tlen;
- if (*ctype=='(' || (*lp!=SCRIPT_EOL && *lp!='?')) {
- // revert
- section = 0;
- }
- }
+ nxttok = ' ';
+ ctype = argptr;
+ } while (*lp==' ' && (section == 1) );
}
}
}
@@ -4973,9 +4979,9 @@ void HandleScriptConfiguration(void) {
#ifdef xSCRIPT_STRIP_COMMENTS
uint16_t ssize = glob_script_mem.script_size;
if (bitRead(Settings.rule_enabled, 1)) ssize *= 2;
- WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? " checked" : "",ssize);
+ WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? PSTR(" checked") : "",ssize);
#else
- WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? " checked" : "",glob_script_mem.script_size);
+ WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? PSTR(" checked") : "",glob_script_mem.script_size);
#endif
// script is to large for WSContentSend_P
diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino
index 8ef33c91f..bf4664886 100644
--- a/tasmota/xdrv_12_home_assistant.ino
+++ b/tasmota/xdrv_12_home_assistant.ino
@@ -197,7 +197,7 @@ const char HASS_DISCOVER_DEVICE[] PROGMEM = // Basic par
"\"tp\":[\"%s\",\"%s\",\"%s\"]," // Topics for command, stat and tele
"\"rl\":[%s],\"swc\":[%s],\"swn\":[%s],\"btn\":[%s]," // Inputs / Outputs
"\"so\":{\"4\":%d,\"11\":%d,\"13\":%d,\"17\":%d,\"20\":%d," // SetOptions
- "\"30\":%d,\"68\":%d,\"73\":%d,\"82\":%d,\"114\":%d},"
+ "\"30\":%d,\"68\":%d,\"73\":%d,\"82\":%d,\"114\":%d,\"117\":%d},"
"\"lk\":%d,\"lt_st\":%d,\"sho\":[%s],\"ver\":1}"; // Light SubType, Shutter Options and Discovery version
typedef struct HASS {
@@ -341,7 +341,7 @@ void NewHAssDiscovery(void)
TasmotaGlobal.version, TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_FULLTOPIC), SUB_PREFIX, PUB_PREFIX, PUB_PREFIX2, Hass.RelLst, stemp3, stemp4,
stemp5, Settings.flag.mqtt_response, Settings.flag.button_swap, Settings.flag.button_single, Settings.flag.decimal_text, Settings.flag.not_power_linked,
Settings.flag.hass_light, Settings.flag3.pwm_multi_channels, Settings.flag3.mqtt_buttons, Settings.flag4.alexa_ct_range, Settings.flag5.mqtt_switches,
- light_controller.isCTRGBLinked(), Light.subtype, stemp6);
+ Settings.flag5.fade_fixed_duration, light_controller.isCTRGBLinked(), Light.subtype, stemp6);
}
MqttPublish(stopic, true);
diff --git a/tasmota/xdrv_20_hue.ino b/tasmota/xdrv_20_hue.ino
index 84e9ed508..4da625847 100644
--- a/tasmota/xdrv_20_hue.ino
+++ b/tasmota/xdrv_20_hue.ino
@@ -175,7 +175,7 @@ String HueBridgeId(void)
String temp = WiFi.macAddress();
temp.replace(":", "");
String bridgeid = temp.substring(0, 6);
- bridgeid += "FFFE";
+ bridgeid += F("FFFE");
bridgeid += temp.substring(6);
return bridgeid; // 5CCF7FFFFE139F3D
}
@@ -225,8 +225,6 @@ void HueRespondToMSearch(void)
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"),
message, udp_remote_ip.toString().c_str(), udp_remote_port);
-
- udp_response_mutex = false;
}
/*********************************************************************************************\
diff --git a/tasmota/xdrv_21_wemo.ino b/tasmota/xdrv_21_wemo.ino
index 96e937d21..18f793824 100644
--- a/tasmota/xdrv_21_wemo.ino
+++ b/tasmota/xdrv_21_wemo.ino
@@ -76,8 +76,6 @@ void WemoRespondToMSearch(int echo_type)
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"),
echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port);
-
- udp_response_mutex = false;
}
/*********************************************************************************************\
diff --git a/tasmota/xdrv_21_wemo_multi.ino b/tasmota/xdrv_21_wemo_multi.ino
index ec3fb7d42..1a0b3ac6c 100644
--- a/tasmota/xdrv_21_wemo_multi.ino
+++ b/tasmota/xdrv_21_wemo_multi.ino
@@ -422,8 +422,6 @@ void WemoRespondToMSearch(int echo_type) {
for (uint32_t i = 0; i < numOfWemoSwitch; i++) {
wemoDevice[i]->WemoRespondToMSearch(echo_type);
}
-
- udp_response_mutex = false;
}
/*********************************************************************************************\
diff --git a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino
index 80a69441c..ec7d773e4 100644
--- a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino
+++ b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino
@@ -681,9 +681,9 @@ void Z_Device::jsonAddConfig(Z_attribute_list & attr_list) const {
for (auto & data_elt : data) {
char key[8];
if (data_elt.validConfig()) {
- snprintf_P(key, sizeof(key), "?%02X.%1X", data_elt.getEndpoint(), data_elt.getConfig());
+ snprintf_P(key, sizeof(key), PSTR("?%02X.%1X"), data_elt.getEndpoint(), data_elt.getConfig());
} else {
- snprintf_P(key, sizeof(key), "?%02X", data_elt.getEndpoint());
+ snprintf_P(key, sizeof(key), PSTR("?%02X"), data_elt.getEndpoint());
}
key[0] = Z_Data::DataTypeToChar(data_elt.getType());
arr_data.addStr(key);
diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino
index 5cfb19d06..fe4d219c0 100644
--- a/tasmota/xdrv_23_zigbee_5_converters.ino
+++ b/tasmota/xdrv_23_zigbee_5_converters.ino
@@ -1903,7 +1903,7 @@ void ZCLFrame::syntheticAqaraVibration(class Z_attribute_list &attr_list, class
y = buf2.get16(2);
x = buf2.get16(4);
char temp[32];
- snprintf_P(temp, sizeof(temp), "[%i,%i,%i]", x, y, z);
+ snprintf_P(temp, sizeof(temp), PSTR("[%i,%i,%i]"), x, y, z);
attr.setStrRaw(temp);
// calculate angles
float X = x;
@@ -1912,7 +1912,7 @@ void ZCLFrame::syntheticAqaraVibration(class Z_attribute_list &attr_list, class
int32_t Angle_X = 0.5f + atanf(X/sqrtf(z*z+y*y)) * f_180pi;
int32_t Angle_Y = 0.5f + atanf(Y/sqrtf(x*x+z*z)) * f_180pi;
int32_t Angle_Z = 0.5f + atanf(Z/sqrtf(x*x+y*y)) * f_180pi;
- snprintf_P(temp, sizeof(temp), "[%i,%i,%i]", Angle_X, Angle_Y, Angle_Z);
+ snprintf_P(temp, sizeof(temp), PSTR("[%i,%i,%i]"), Angle_X, Angle_Y, Angle_Z);
attr_list.addAttributePMEM(PSTR("AqaraAngles")).setStrRaw(temp);
}
}
diff --git a/tasmota/xdrv_23_zigbee_7_0_statemachine.ino b/tasmota/xdrv_23_zigbee_7_0_statemachine.ino
index 7c00cfb42..cc23c7a92 100644
--- a/tasmota/xdrv_23_zigbee_7_0_statemachine.ino
+++ b/tasmota/xdrv_23_zigbee_7_0_statemachine.ino
@@ -785,7 +785,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_WAIT_UNTIL(5000, ZBR_RSTACK) // wait for RSTACK message
// Init device and probe version
- ZI_SEND(ZBS_VERSION) ZI_WAIT_RECV_FUNC(1000, ZBR_VERSION, &EZ_ReceiveCheckVersion) // check EXT PAN ID
+ ZI_SEND(ZBS_VERSION) ZI_WAIT_RECV_FUNC(5000, ZBR_VERSION, &EZ_ReceiveCheckVersion) // check EXT PAN ID
// configure EFR32
ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredCoord)
diff --git a/tasmota/xdrv_23_zigbee_7_5_map.ino b/tasmota/xdrv_23_zigbee_7_5_map.ino
index 790720320..c9013b665 100644
--- a/tasmota/xdrv_23_zigbee_7_5_map.ino
+++ b/tasmota/xdrv_23_zigbee_7_5_map.ino
@@ -171,7 +171,7 @@ void Z_Mapper::dumpInternals(void) const {
char hex[8];
snprintf(hex, sizeof(hex), PSTR("%d"), edge.lqi);
- WSContentSend_P("{from:\"0x%04X\",to:\"0x%04X\",label:\"%s\",color:\"#%03X\"},",
+ WSContentSend_P(PSTR("{from:\"0x%04X\",to:\"0x%04X\",label:\"%s\",color:\"#%03X\"},"),
edge.node_1, edge.node_2, (edge.lqi > 0) ? hex : "", lqi_color);
}
WSContentSend_P(PSTR("],"));
diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino
index ce690c4db..ec9a454ac 100644
--- a/tasmota/xdrv_23_zigbee_A_impl.ino
+++ b/tasmota/xdrv_23_zigbee_A_impl.ino
@@ -2081,7 +2081,7 @@ void ZigbeeShow(bool json)
if (zigbee.permit_end_time) {
// PermitJoin in progress
- WSContentSend_P(msg[ZB_WEB_PERMITJOIN_ACTIVE], D_ZIGBEE_PERMITJOIN_ACTIVE);
+ WSContentSend_P(msg[ZB_WEB_PERMITJOIN_ACTIVE], PSTR(D_ZIGBEE_PERMITJOIN_ACTIVE));
}
#endif
}
diff --git a/tasmota/xdrv_28_pcf8574.ino b/tasmota/xdrv_28_pcf8574.ino
index 58bb5239c..b79f3caa6 100644
--- a/tasmota/xdrv_28_pcf8574.ino
+++ b/tasmota/xdrv_28_pcf8574.ino
@@ -168,7 +168,7 @@ void HandlePcf8574(void)
WSContentStart_P(D_CONFIGURE_PCF8574);
WSContentSendStyle();
- WSContentSend_P(HTTP_FORM_I2C_PCF8574_1, (Settings.flag3.pcf8574_ports_inverted) ? " checked" : ""); // SetOption81 - Invert all ports on PCF8574 devices
+ WSContentSend_P(HTTP_FORM_I2C_PCF8574_1, (Settings.flag3.pcf8574_ports_inverted) ? PSTR(" checked") : ""); // SetOption81 - Invert all ports on PCF8574 devices
WSContentSend_P(HTTP_TABLE100);
for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) {
for (uint32_t idx2 = 0; idx2 < 8; idx2++) { // 8 ports on PCF8574
@@ -177,8 +177,8 @@ void HandlePcf8574(void)
idx +1, idx2,
idx2 + 8*idx,
idx2 + 8*idx,
- ((helper & Settings.pcf8574_config[idx]) >> idx2 == 0) ? " selected " : " ",
- ((helper & Settings.pcf8574_config[idx]) >> idx2 == 1) ? " selected " : " "
+ ((helper & Settings.pcf8574_config[idx]) >> idx2 == 0) ? PSTR(" selected ") : " ",
+ ((helper & Settings.pcf8574_config[idx]) >> idx2 == 1) ? PSTR(" selected ") : " "
);
}
}
diff --git a/tasmota/xdrv_43_mlx90640.ino b/tasmota/xdrv_43_mlx90640.ino
index 18255c079..53cbcfe07 100644
--- a/tasmota/xdrv_43_mlx90640.ino
+++ b/tasmota/xdrv_43_mlx90640.ino
@@ -418,12 +418,12 @@ void MLX90640HandleWebGuiResponse(void){
if(_line==0){_buf[0]=1000+MLX90640.Ta;} //ambient temperature modulation hack
else{_buf[0]=(float)_line;}
memcpy((char*)&_buf[1],(char*)&MLX90640.To[_line*64],64*4);
- Webserver->send(200,PSTR("application/octet-stream"),(const char*)&_buf,65*4);
+ Webserver->send_P(200,PSTR("application/octet-stream"),(const char*)&_buf,65*4);
return;
}
WebGetArg("up", tmp, sizeof(tmp)); // update POI to browser
if (strlen(tmp)==1) {
- Webserver->send(200,PSTR("application/octet-stream"),(const char*)&MLX90640.pois,MLX90640_POI_NUM*2);
+ Webserver->send_P(200,PSTR("application/octet-stream"),(const char*)&MLX90640.pois,MLX90640_POI_NUM*2);
return;
}
else if (strlen(tmp)>2) { // receive updated POI from browser
diff --git a/tasmota/xdrv_48_timeprop.ino b/tasmota/xdrv_48_timeprop.ino
index bddf2653f..5589868de 100644
--- a/tasmota/xdrv_48_timeprop.ino
+++ b/tasmota/xdrv_48_timeprop.ino
@@ -18,6 +18,7 @@
*/
#ifdef USE_TIMEPROP
+#ifndef FIRMWARE_MINIMAL
/*********************************************************************************************\
* Code to drive one or more relays in a time proportioned manner give a
* required power value.
@@ -79,7 +80,23 @@
#define TIMEPROP_RELAYS 1, 2 // which relay to control 1:8
* Publish values between 0 and 1 to the topic(s) described above
-\*********************************************************************************************/
+ *
+**/
+
+
+
+#define D_CMND_TIMEPROP "timeprop_"
+#define D_CMND_TIMEPROP_SETPOWER "setpower_" // add index no on end (0:8) and data is power 0:1
+
+#include "Timeprop.h"
+
+enum TimepropCommands { CMND_TIMEPROP_SETPOWER };
+const char kTimepropCommands[] PROGMEM = D_CMND_TIMEPROP_SETPOWER;
+
+static Timeprop timeprops[TIMEPROP_NUM_OUTPUTS];
+static int relayNos[TIMEPROP_NUM_OUTPUTS] = {TIMEPROP_RELAYS};
+static long currentRelayStates = 0; // current actual relay states. Bit 0 first relay
+
#ifndef TIMEPROP_NUM_OUTPUTS
#define TIMEPROP_NUM_OUTPUTS 1 // how many outputs to control (with separate alogorithm for each)
@@ -103,8 +120,6 @@
#define TIMEPROP_RELAYS 1 // which relay to control 1:8
#endif
-#include "Timeprop.h"
-
struct {
Timeprop timeprops[TIMEPROP_NUM_OUTPUTS];
int relay_nos[TIMEPROP_NUM_OUTPUTS] = {TIMEPROP_RELAYS};
@@ -162,7 +177,51 @@ void TimepropXdrvPower(void) {
/* char *data; */
/* } XdrvMailbox; */
-// To get here post with topic cmnd/timeprop_setpower_n where n is index into Tprop.timeprops 0:7
+// To get here post with topic cmnd/timeprop_setpower_n where n is index into timeprops 0:7
+bool TimepropCommand()
+{
+ char command [CMDSZ];
+ bool serviced = true;
+ uint8_t ua_prefix_len = strlen(D_CMND_TIMEPROP); // to detect prefix of command
+ /*
+ snprintf_P(log_data, sizeof(log_data), "Command called: "
+ "index: %d data_len: %d payload: %d topic: %s data: %s\n",
+ XdrvMailbox.index,
+ XdrvMailbox.data_len,
+ XdrvMailbox.payload,
+ (XdrvMailbox.payload >= 0 ? XdrvMailbox.topic : ""),
+ (XdrvMailbox.data_len >= 0 ? XdrvMailbox.data : ""));
+
+ AddLog(LOG_LEVEL_INFO);
+ */
+ if (0 == strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_TIMEPROP), ua_prefix_len)) {
+ // command starts with timeprop_
+ int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + ua_prefix_len, kTimepropCommands);
+ if (CMND_TIMEPROP_SETPOWER == command_code) {
+ /*
+ snprintf_P(log_data, sizeof(log_data), "Timeprop command timeprop_setpower: "
+ "index: %d data_len: %d payload: %d topic: %s data: %s",
+ XdrvMailbox.index,
+ XdrvMailbox.data_len,
+ XdrvMailbox.payload,
+ (XdrvMailbox.payload >= 0 ? XdrvMailbox.topic : ""),
+ (XdrvMailbox.data_len >= 0 ? XdrvMailbox.data : ""));
+ AddLog(LOG_LEVEL_INFO);
+ */
+ if (XdrvMailbox.index >=0 && XdrvMailbox.index < TIMEPROP_NUM_OUTPUTS) {
+ timeprops[XdrvMailbox.index].setPower( atof(XdrvMailbox.data), Tprop.current_time_secs );
+ }
+ snprintf_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"" D_CMND_TIMEPROP D_CMND_TIMEPROP_SETPOWER "%d\":\"%s\"}"),
+ XdrvMailbox.index, XdrvMailbox.data);
+ }
+ else {
+ serviced = false;
+ }
+ } else {
+ serviced = false;
+ }
+ return serviced;
+}
/*********************************************************************************************\
* Interface
@@ -180,6 +239,9 @@ bool Xdrv48(byte function) {
case FUNC_EVERY_SECOND:
TimepropEverySecond();
break;
+ case FUNC_COMMAND:
+ result = TimepropCommand();
+ break;
case FUNC_SET_POWER:
TimepropXdrvPower();
break;
@@ -187,4 +249,5 @@ bool Xdrv48(byte function) {
return result;
}
+#endif // FIRMWARE_MINIMAL
#endif // USE_TIMEPROP
diff --git a/tasmota/xdrv_49_pid.ino b/tasmota/xdrv_49_pid.ino
index 7da87ac7d..15097106b 100644
--- a/tasmota/xdrv_49_pid.ino
+++ b/tasmota/xdrv_49_pid.ino
@@ -18,6 +18,7 @@
*/
#ifdef USE_PID
+#ifndef FIRMWARE_MINIMAL
/*********************************************************************************************\
* Uses the library https://github.com/colinl/process-control.git from Github
* In user_config_override.h include code as follows:
@@ -117,11 +118,6 @@
#define PID_REPORT_MORE_SETTINGS // If defined, the SENSOR output will provide more extensive json
// output in the PID section
-// #define PID_BACKWARD_COMPATIBLE // Preserve the backward compatible reporting of PID power via
- // `%topic%/PID {"power":"0.000"}` This is now available in
- // `%topic$/SENSOR {..., "PID":{"PidPower":0.00}}`
- // Don't use unless you know that you need it
-
* Help with using the PID algorithm and with loop tuning can be found at
* http://blog.clanlaw.org.uk/2018/01/09/PID-tuning-with-node-red-contrib-pid.html
* This is directed towards using the algorithm in the node-red node node-red-contrib-pid but the algorithm here is based on
@@ -271,26 +267,27 @@ void CmndSetPv(void) {
// this runs it at the next second
Pid.run_pid_now = true;
}
+ ResponseCmndFloat(atof(XdrvMailbox.data), 1);
}
void CmndSetSp(void) {
Pid.pid.setSp(atof(XdrvMailbox.data));
- ResponseCmndNumber(atof(XdrvMailbox.data));
+ ResponseCmndFloat(atof(XdrvMailbox.data), 1);
}
void CmndSetPb(void) {
Pid.pid.setPb(atof(XdrvMailbox.data));
- ResponseCmndNumber(atof(XdrvMailbox.data));
+ ResponseCmndFloat(atof(XdrvMailbox.data), 1);
}
void CmndSetTi(void) {
Pid.pid.setTi(atof(XdrvMailbox.data));
- ResponseCmndNumber(atof(XdrvMailbox.data));
+ ResponseCmndFloat(atof(XdrvMailbox.data), 1);
}
void CmndSetTd(void) {
Pid.pid.setTd(atof(XdrvMailbox.data));
- ResponseCmndNumber(atof(XdrvMailbox.data));
+ ResponseCmndFloat(atof(XdrvMailbox.data), 1);
}
void CmndSetInitialInt(void) {
@@ -300,7 +297,7 @@ void CmndSetInitialInt(void) {
void CmndSetDSmooth(void) {
Pid.pid.setDSmooth(atof(XdrvMailbox.data));
- ResponseCmndNumber(atof(XdrvMailbox.data));
+ ResponseCmndFloat(atof(XdrvMailbox.data), 1);
}
void CmndSetAuto(void) {
@@ -310,7 +307,7 @@ void CmndSetAuto(void) {
void CmndSetManualPower(void) {
Pid.pid.setManualPower(atof(XdrvMailbox.data));
- ResponseCmndNumber(atof(XdrvMailbox.data));
+ ResponseCmndFloat(atof(XdrvMailbox.data), 1);
}
void CmndSetMaxInterval(void) {
@@ -391,14 +388,14 @@ void PIDShowValues(void) {
void PIDRun(void) {
double power = Pid.pid.tick(Pid.current_time_secs);
-#ifdef PID_BACKWARD_COMPATIBLE
+#ifdef PID_DONT_USE_PID_TOPIC
// This part is left inside to regularly publish the PID Power via
// `%topic%/PID {"power":"0.000"}`
char str_buf[FLOATSZ];
dtostrfd(power, 3, str_buf);
snprintf_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s\":\"%s\"}"), "power", str_buf);
MqttPublishPrefixTopic_P(TELE, "PID", false);
-#endif // PID_BACKWARD_COMPATIBLE
+#endif // PID_DONT_USE_PID_TOPIC
#if defined PID_SHUTTER
// send output as a position from 0-100 to defined shutter
@@ -443,4 +440,5 @@ bool Xdrv49(byte function) {
}
return result;
}
+#endif //FIRMWARE_MINIMAL
#endif // USE_PID
diff --git a/tasmota/xdrv_50_filesystem.ino b/tasmota/xdrv_50_filesystem.ino
index 56d4ecfd8..0b7fc53d2 100644
--- a/tasmota/xdrv_50_filesystem.ino
+++ b/tasmota/xdrv_50_filesystem.ino
@@ -72,25 +72,28 @@ ufsfree free size in kB
#include "FS.h"
#endif // ESP32
-// global file system pointer
+// Global file system pointer
FS *ufsp;
-// flash file system pointer on esp32
+// Flash file system pointer
FS *ffsp;
-// local pointer for file managment
+// Local pointer for file managment
FS *dfsp;
char ufs_path[48];
File ufs_upload_file;
uint8_t ufs_dir;
-// 0 = none, 1 = SD, 2 = ffat, 3 = littlefs
+// 0 = None, 1 = SD, 2 = ffat, 3 = littlefs
uint8_t ufs_type;
uint8_t ffs_type;
bool download_busy;
+
+
+
/*********************************************************************************************/
-// init flash file system
+// Init flash file system
void UfsInitOnce(void) {
ufs_type = 0;
ffsp = 0;
@@ -130,21 +133,13 @@ void UfsInitOnce(void) {
void UfsInit(void) {
UfsInitOnce();
if (ufs_type) {
- AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: Type %d mounted with %d kB free"), ufs_type, UfsInfo(1, 0));
+ AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: FlashFS mounted with %d kB free"), UfsInfo(1, 0));
}
}
-
#ifdef USE_SDCARD
void UfsCheckSDCardInit(void) {
-
-#ifdef ESP8266
- if (PinUsed(GPIO_SPI_CLK) && PinUsed(GPIO_SPI_MOSI) && PinUsed(GPIO_SPI_MISO)) {
-#endif // ESP8266
-
-#ifdef ESP32
if (TasmotaGlobal.spi_enabled) {
-#endif // ESP32
int8_t cs = SDCARD_CS_PIN;
if (PinUsed(GPIO_SDCARD_CS)) {
cs = Pin(GPIO_SDCARD_CS);
@@ -172,10 +167,10 @@ void UfsCheckSDCardInit(void) {
// make sd card the global filesystem
#ifdef ESP8266
// on esp8266 sdcard info takes several seconds !!!, so we ommit it here
- AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: SDCARD mounted"));
+ AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: SDCard mounted"));
#endif // ESP8266
#ifdef ESP32
- AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: SDCARD mounted with %d kB free"), UfsInfo(1, 0));
+ AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: SDCard mounted with %d kB free"), UfsInfo(1, 0));
#endif // ESP32
}
}
@@ -274,38 +269,12 @@ uint8_t UfsReject(char *name) {
return 0;
}
-// Format number with thousand marker - Not international as '.' is decimal on most countries
-void UfsForm1000(uint32_t number, char *dp, char sc) {
- char str[32];
- sprintf(str, "%d", number);
- char *sp = str;
- uint32_t inum = strlen(sp)/3;
- uint32_t fnum = strlen(sp)%3;
- if (!fnum) { inum--; }
- for (uint32_t count = 0; count <= inum; count++) {
- if (fnum) {
- memcpy(dp, sp, fnum);
- dp += fnum;
- sp += fnum;
- fnum = 0;
- } else {
- memcpy(dp, sp, 3);
- dp += 3;
- sp += 3;
- }
- if (count != inum) {
- *dp++ = sc;
- }
- }
- *dp = 0;
-}
-
/*********************************************************************************************\
* Tfs low level functions
\*********************************************************************************************/
bool TfsFileExists(const char *fname){
- if (!ufs_type) { return false; }
+ if (!ffs_type) { return false; }
bool yes = ffsp->exists(fname);
if (!yes) {
@@ -315,7 +284,7 @@ bool TfsFileExists(const char *fname){
}
bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) {
- if (!ufs_type) { return false; }
+ if (!ffs_type) { return false; }
File file = ffsp->open(fname, "w");
if (!file) {
@@ -329,7 +298,7 @@ bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) {
}
bool TfsInitFile(const char *fname, uint32_t len, uint8_t init_value) {
- if (!ufs_type) { return false; }
+ if (!ffs_type) { return false; }
File file = ffsp->open(fname, "w");
if (!file) {
@@ -345,7 +314,7 @@ bool TfsInitFile(const char *fname, uint32_t len, uint8_t init_value) {
}
bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
- if (!ufs_type) { return false; }
+ if (!ffs_type) { return false; }
if (!TfsFileExists(fname)) { return false; }
File file = ffsp->open(fname, "r");
@@ -360,7 +329,7 @@ bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
}
bool TfsDeleteFile(const char *fname) {
- if (!ufs_type) { return false; }
+ if (!ffs_type) { return false; }
if (!ffsp->remove(fname)) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Delete failed"));
@@ -380,24 +349,48 @@ void (* const kUFSCommand[])(void) PROGMEM = {
&UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete};
void UFSInfo(void) {
- Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}}"), ufs_type, UfsInfo(0, 0), UfsInfo(1, 0));
+ Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}"), ufs_type, UfsInfo(0, 0), UfsInfo(1, 0));
+ if (ffs_type && (ffs_type != ufs_type)) {
+ ResponseAppend_P(PSTR(",{\"Type\":%d,\"Size\":%d,\"Free\":%d}"), ffs_type, UfsInfo(0, 1), UfsInfo(1, 1));
+ }
+ ResponseJsonEnd();
}
void UFSType(void) {
- ResponseCmndNumber(ufs_type);
+ if (ffs_type && (ffs_type != ufs_type)) {
+ Response_P(PSTR("{\"%s\":[%d,%d]}"), XdrvMailbox.command, ufs_type, ffs_type);
+ } else {
+ ResponseCmndNumber(ufs_type);
+ }
}
void UFSSize(void) {
- ResponseCmndNumber(UfsInfo(0, 0));
+ if (ffs_type && (ffs_type != ufs_type)) {
+ Response_P(PSTR("{\"%s\":[%d,%d]}"), XdrvMailbox.command, UfsInfo(0, 0), UfsInfo(0, 1));
+ } else {
+ ResponseCmndNumber(UfsInfo(0, 0));
+ }
}
void UFSFree(void) {
- ResponseCmndNumber(UfsInfo(1, 0));
+ if (ffs_type && (ffs_type != ufs_type)) {
+ Response_P(PSTR("{\"%s\":[%d,%d]}"), XdrvMailbox.command, UfsInfo(1, 0), UfsInfo(1, 1));
+ } else {
+ ResponseCmndNumber(UfsInfo(1, 0));
+ }
}
void UFSDelete(void) {
+ // UfsDelete sdcard or flashfs file if only one of them available
+ // UfsDelete2 flashfs file if available
if (XdrvMailbox.data_len > 0) {
- if (!TfsDeleteFile(XdrvMailbox.data)) {
+ bool result = false;
+ if (ffs_type && (ffs_type != ufs_type) && (2 == XdrvMailbox.index)) {
+ result = TfsDeleteFile(XdrvMailbox.data);
+ } else {
+ result = (ufs_type && ufsp->remove(XdrvMailbox.data));
+ }
+ if (!result) {
ResponseCmndChar(D_JSON_FAILED);
} else {
ResponseCmndDone();
@@ -418,7 +411,7 @@ const char UFS_FORM_FILE_UPLOAD[] PROGMEM =
"