Skip to content

Commit

Permalink
Change command handling
Browse files Browse the repository at this point in the history
 * 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)
  • Loading branch information
arendst committed Oct 2, 2019
1 parent 97de80b commit 8c34b9e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 40 deletions.
3 changes: 3 additions & 0 deletions sonoff/_changelog.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
73 changes: 39 additions & 34 deletions sonoff/support_command.ino
Original file line number Diff line number Diff line change
Expand Up @@ -81,64 +81,71 @@ 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);

char stemp1[TOPSZ];
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) {
Expand All @@ -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 "\"}"));
Expand Down Expand Up @@ -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
}
}
}
Expand Down
17 changes: 11 additions & 6 deletions sonoff/xdrv_02_mqtt.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand All @@ -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 {
Expand All @@ -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);
Expand Down

4 comments on commit 8c34b9e

@meingraham
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is var1 = 1 (space before & after comparator =) allowed?

@meingraham
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arendst? @laurentdong? Buehler?

@arendst
Copy link
Owner Author

@arendst arendst commented on 8c34b9e Oct 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than that a space is not needed anymore between the command and the value there is no change.

So var1 = 1 should do the same as var1= 1 or var1=1

@meingraham
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll update the wiki to remove the requirement for no spaces. Of course, to make best use of the 511 bytes, you still want to optimize, but, if you don't, no spaces is not a strict requirement.

Please sign in to comment.