diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 9139cb622755..8345f9e523cb 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -8,6 +8,9 @@ * Add command to MCP230xx: sensor29 pin,0/1/2 for OFF/ON/TOGGLE * Add initial support for PCF8574 I2C I/O Expander (currently output only) by Stefan Bode * Add command SetOption71 0/1 to switch between different Modbus Active Energy registers on DDS238-2 energy meters (#6531) + * Change command SetOption43 to make it more general. Now supports PS_16_DZ driver too (#6547) + * Change command handling by moving buffers up in chain solving MQTTlog support (#6524) + * Change detection of non-MQTT commands by allowing non-space characters as delimiter (#6540) * * 6.6.0.13 20190922 * Add command EnergyReset4 x,x to initialize total usage for two tarrifs diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index 9e2fd5fcba1a..182796519069 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -81,55 +81,61 @@ void ResponseCmndIdxChar(const char* value) /********************************************************************************************/ -void ExecuteCommand(char *cmnd, uint32_t source) +void ExecuteCommand(const char *cmnd, uint32_t source) { - char *start; - char *token; - + // cmnd: "status 0" = stopic "status" and svalue " 0" + // cmnd: "var1 =1" = stopic "var1" and svalue " =1" + // cmnd: "var1=1" = stopic "var1" and svalue "=1" #ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("ExecuteCommand")); #endif ShowSource(source); - token = strtok(cmnd, " "); - if (token != nullptr) { - start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble - if (start) { token = start +1; } + const char *pos = cmnd; + while (*pos && isspace(*pos)) { + pos++; // Skip all spaces + } + + const char *start = pos; + // Get a command. Commands can only use letters, digits and underscores + while (*pos && (isalpha(*pos) || isdigit(*pos) || '_' == *pos || '/' == *pos)) { + if ('/' == *pos) { // Skip possible cmnd/sonoff/ preamble + start = pos + 1; + } + pos++; + } + if ('\0' == *start || pos <= start) { + return; // Did not find any command to execute } - uint32_t size = (token != nullptr) ? strlen(token) : 0; - char stopic[size +2]; // / + \0 - snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == nullptr) ? "" : token); - token = strtok(nullptr, ""); - size = (token != nullptr) ? strlen(token) : 0; - char svalue[size +1]; - strlcpy(svalue, (token == nullptr) ? "" : token, sizeof(svalue)); // Fixed 5.8.0b - CommandHandler(stopic, (uint8_t*)svalue, strlen(svalue)); + uint32_t size = pos - start; + char stopic[size + 2]; // with leader '/' and end '\0' + stopic[0] = '/'; + memcpy(stopic+1, start, size); + stopic[size+1] = '\0'; + + char svalue[strlen(pos) +1]; // pos point to the start of parameters + strlcpy(svalue, pos, sizeof(svalue)); + CommandHandler(stopic, svalue, strlen(svalue)); } /********************************************************************************************/ -// topic: /power1 data: toggle = Console command -// topic: cmnd/sonoff/power1 data: toggle = Mqtt command using topic -// topic: cmnd/sonoffs/power1 data: toggle = Mqtt command using a group topic -// topic: cmnd/DVES_83BB10_fb/power1 data: toggle = Mqtt command using fallback topic +// topicBuf: /power1 dataBuf: toggle = Console command +// topicBuf: cmnd/sonoff/power1 dataBuf: toggle = Mqtt command using topic +// topicBuf: cmnd/sonoffs/power1 dataBuf: toggle = Mqtt command using a group topic +// topicBuf: cmnd/DVES_83BB10_fb/power1 dataBuf: toggle = Mqtt command using fallback topic -void CommandHandler(char* topic, uint8_t* data, uint32_t data_len) +void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) { #ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("CommandHandler")); #endif - char topicBuf[TOPSZ]; - strlcpy(topicBuf, topic, sizeof(topicBuf)); - - uint32_t i = 0; - for (i = 0; i < data_len; i++) { - if (!isspace(data[i])) { break; } // Skip leading spaces in data + while (*dataBuf && isspace(*dataBuf)) { + dataBuf++; // Skip leading spaces in data + data_len--; } - data_len -= i; - char dataBuf[data_len+1]; - memcpy(dataBuf, data +i, sizeof(dataBuf)); bool grpflg = (strstr(topicBuf, Settings.mqtt_grptopic) != nullptr); @@ -137,8 +143,9 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len) GetFallbackTopic_P(stemp1, CMND, ""); // Full Fallback topic = cmnd/DVES_xxxxxxxx_fb/ fallback_topic_flag = (!strncmp(topicBuf, stemp1, strlen(stemp1))); - char *type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type) + char *type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type) + uint32_t i = 0; uint32_t index = 1; bool user_index = false; if (type != nullptr) { @@ -156,7 +163,7 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len) type[i] = '\0'; } - DEBUG_CORE_LOG(PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf); if (type != nullptr) { Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}")); @@ -686,11 +693,9 @@ void CmndSetoption(void) IrReceiveUpdateThreshold(); break; #endif -#ifdef USE_TUYA_MCU case P_DIMMER_MAX: restart_flag = 2; // Need a restart to update GUI break; -#endif } } } diff --git a/sonoff/xdrv_02_mqtt.ino b/sonoff/xdrv_02_mqtt.ino index 81fd45b6f8a9..edc844448a38 100644 --- a/sonoff/xdrv_02_mqtt.ino +++ b/sonoff/xdrv_02_mqtt.ino @@ -251,7 +251,7 @@ bool MqttPublishLib(const char* topic, bool retained) return result; } -void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) +void MqttDataHandler(char* mqtt_topic, uint8_t* mqtt_data, unsigned int data_len) { #ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("MqttDataHandler")); @@ -262,8 +262,8 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) // Do not execute multiple times if Prefix1 equals Prefix2 if (!strcmp(Settings.mqtt_prefix[0], Settings.mqtt_prefix[1])) { - char *str = strstr(topic, Settings.mqtt_prefix[0]); - if ((str == topic) && mqtt_cmnd_publish) { + char *str = strstr(mqtt_topic, Settings.mqtt_prefix[0]); + if ((str == mqtt_topic) && mqtt_cmnd_publish) { if (mqtt_cmnd_publish > 3) { mqtt_cmnd_publish -= 3; } else { @@ -273,10 +273,15 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) } } - data[data_len] = 0; + // Save MQTT data ASAP as it's data is discarded by PubSubClient with next publish as used in MQTTlog + char topic[TOPSZ]; + strlcpy(topic, mqtt_topic, sizeof(topic)); + mqtt_data[data_len] = 0; + char data[data_len +1]; + memcpy(data, mqtt_data, sizeof(data)); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_MQTT D_RECEIVED_TOPIC " %s, " D_DATA_SIZE " %d, " D_DATA " %s"), topic, data_len, data); -// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(dataBuf); } + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_MQTT D_RECEIVED_TOPIC " \"%s\", " D_DATA_SIZE " %d, " D_DATA " \"%s\""), topic, data_len, data); +// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(data); } // MQTT pre-processing XdrvMailbox.index = strlen(topic);