diff --git a/tasmota/support_device_groups.ino b/tasmota/support_device_groups.ino index 3a9258a60..6ed072490 100644 --- a/tasmota/support_device_groups.ino +++ b/tasmota/support_device_groups.ino @@ -155,6 +155,9 @@ bool DeviceGroupItemShared(bool incoming, uint8_t item) case DGR_ITEM_BRI_PRESET_HIGH: mask = DGR_SHARE_DIMMER_SETTINGS; break; + case DGR_ITEM_EVENT: + mask = DGR_SHARE_EVENT; + break; } return (!mask || ((incoming ? Settings.device_group_share_in : Settings.device_group_share_out) & mask)); } @@ -225,24 +228,29 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes else { #ifdef USE_DEVICE_GROUPS_SEND + bool escaped; bool use_command; + char chr; char oper; uint32_t old_value; - char * delim_ptr; + char * out_ptr; #endif // USE_DEVICE_GROUPS_SEND + struct item { + uint8_t item; + uint32_t value; + void * value_ptr; + } item_array[32]; bool shared; uint8_t item; uint32_t value; char * value_ptr; + struct item * item_ptr; va_list ap; #ifdef DEVICE_GROUPS_DEBUG AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Building device group %s packet"), device_group->group_name); #endif // DEVICE_GROUPS_DEBUG -#ifdef USE_DEVICE_GROUPS_SEND - use_command = (message_type == DGR_MSGTYPE_UPDATE_COMMAND); -#endif // USE_DEVICE_GROUPS_SEND value = 0; if (message_type == DGR_MSGTYP_UPDATE_MORE_TO_COME) value |= DGR_FLAG_MORE_TO_COME; @@ -253,73 +261,96 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes #endif // DEVICE_GROUPS_DEBUG message_ptr = BeginDeviceGroupMessage(device_group, value, building_status_message || message_type == DGR_MSGTYP_PARTIAL_UPDATE); + // Build an array of all the items and values in this update. + memset(item_array, 0, sizeof(item_array)); + item_ptr = item_array; +#ifdef USE_DEVICE_GROUPS_SEND + use_command = (message_type == DGR_MSGTYPE_UPDATE_COMMAND); + if (use_command) { + value_ptr = XdrvMailbox.data; + while ((item = strtoul(value_ptr, &value_ptr, 0))) { + item_ptr->item = item; + if (*value_ptr == '=') { + value_ptr++; + if (item <= DGR_ITEM_MAX_32BIT) { + oper = 0; + if (*value_ptr == '@') { + oper = value_ptr[1]; + value_ptr += 2; + } + value = strtoul(value_ptr, &value_ptr, 0); + if (oper) { + old_value = (item <= DGR_ITEM_MAX_8BIT ? device_group->values_8bit[item] : (item <= DGR_ITEM_MAX_16BIT ? device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] : device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1])); + value = (oper == '+' ? old_value + value : (oper == '-' ? old_value - value : (oper == '^' ? old_value ^ (value ? value : 0xffffffff) : old_value))); + } + item_ptr->value = value; + } + else if (item <= DGR_ITEM_MAX_STRING) { + item_ptr->value_ptr = out_ptr = value_ptr; + escaped = false; + while ((chr = *value_ptr++)) { + if (chr == ' ' && !escaped) break; + if (!(escaped = (chr == '\\' && !escaped))) *out_ptr++ = chr; + } + *out_ptr = 0; + } + else { + switch (item) { + case DGR_ITEM_LIGHT_CHANNELS: + item_ptr->value_ptr = out_ptr = value_ptr; + for (int i = 0; i < 5; i++) { + *out_ptr = strtoul(value_ptr, &value_ptr, 0); + if (*value_ptr == ',') value_ptr++; + } + break; + } + } + } + item_ptr++; + } + } + else { +#endif // USE_DEVICE_GROUPS_SEND + va_start(ap, message_type); + while ((item = va_arg(ap, int))) { + item_ptr->item = item; + if (item <= DGR_ITEM_MAX_32BIT) + item_ptr->value = va_arg(ap, int); + else if (item <= DGR_ITEM_MAX_STRING) + item_ptr->value_ptr = va_arg(ap, char *); + else { + switch (item) { + case DGR_ITEM_LIGHT_CHANNELS: + item_ptr->value_ptr = va_arg(ap, uint8_t *); + break; + } + } + item_ptr++; + } + va_end(ap); +#ifdef USE_DEVICE_GROUPS_SEND + } +#endif // USE_DEVICE_GROUPS_SEND + // If we're still building this update or all group members haven't acknowledged the previous // update yet, update the message to include these new updates. First we need to rebuild the // previous update message to remove any items and their values that are included in this new // update. if (device_group->message_length) { - uint8_t item_array[32]; - int item_index = 0; int kept_item_count = 0; - // Build an array of all the items in this new update. -#ifdef USE_DEVICE_GROUPS_SEND - if (use_command) - value_ptr = XdrvMailbox.data; - else -#endif // USE_DEVICE_GROUPS_SEND - va_start(ap, message_type); -#ifdef USE_DEVICE_GROUPS_SEND - while (use_command ? (item = strtoul(value_ptr, &delim_ptr, 0)) : (item = va_arg(ap, int))) { -#else // USE_DEVICE_GROUPS_SEND - while ((item = va_arg(ap, int))) { -#endif // !USE_DEVICE_GROUPS_SEND - item_array[item_index++] = item; -#ifdef USE_DEVICE_GROUPS_SEND - if (use_command) { - if (!*delim_ptr) break; - if (*delim_ptr == '=') { - delim_ptr = strchr(delim_ptr, ' '); - if (!delim_ptr) break; - } - value_ptr = delim_ptr + 1; - } - else { -#endif // USE_DEVICE_GROUPS_SEND - if (item <= DGR_ITEM_MAX_32BIT) - va_arg(ap, int); - else if (item <= DGR_ITEM_MAX_STRING) - va_arg(ap, char *); - else { - switch (item) { - case DGR_ITEM_LIGHT_CHANNELS: - va_arg(ap, uint8_t *); - break; - } - } -#ifdef USE_DEVICE_GROUPS_SEND - } -#endif // USE_DEVICE_GROUPS_SEND - } -#ifdef USE_DEVICE_GROUPS_SEND - if (!use_command) va_end(ap); -#else // USE_DEVICE_GROUPS_SEND - va_end(ap); -#endif // !USE_DEVICE_GROUPS_SEND - item_array[item_index] = 0; - // Rebuild the previous update message, removing any items whose values are included in this // new update. char * previous_message_ptr = message_ptr; while (item = *previous_message_ptr++) { // Search for this item in the new update. - for (item_index = 0; item_array[item_index]; item_index++) { - if (item_array[item_index] == item) break; + for (item_ptr = item_array; item_ptr->item; item_ptr++) { + if (item_ptr->item == item) break; } // If this item was found in the new update skip over it and it's value. - if (item_array[item_index]) { + if (item_ptr->item) { if (item <= DGR_ITEM_MAX_32BIT) { previous_message_ptr++; if (item > DGR_ITEM_MAX_8BIT) { @@ -330,8 +361,9 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes } } } - else if (item <= DGR_ITEM_MAX_STRING) - previous_message_ptr += *previous_message_ptr++; + else if (item <= DGR_ITEM_MAX_STRING) { + previous_message_ptr += strlen(previous_message_ptr) + 1; + } else { switch (item) { case DGR_ITEM_LIGHT_CHANNELS: @@ -355,7 +387,7 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes } } else if (item <= DGR_ITEM_MAX_STRING) { - *message_ptr++ = value = *previous_message_ptr++; + value = strlen(previous_message_ptr) + 1; memmove(message_ptr, previous_message_ptr, value); previous_message_ptr += value; message_ptr += value; @@ -378,58 +410,20 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes } // Itertate through the passed items adding them and their values to the message. -#ifdef USE_DEVICE_GROUPS_SEND - if (use_command) - value_ptr = XdrvMailbox.data; - else -#endif // USE_DEVICE_GROUPS_SEND - va_start(ap, message_type); -#ifdef USE_DEVICE_GROUPS_SEND - while (use_command ? (item = strtoul(value_ptr, &delim_ptr, 0)) : (item = va_arg(ap, int))) { -#else // !USE_DEVICE_GROUPS_SEND - while ((item = va_arg(ap, int))) { -#endif // !USE_DEVICE_GROUPS_SEND + for (item_ptr = item_array; (item = item_ptr->item); item_ptr++) { - // Find out if this item is shared with the group and add the item code to the message if yes. + // If this item is shared with the group add it to the message. shared = true; if (!device_group_index) shared = DeviceGroupItemShared(false, item); - if (shared) *message_ptr++ = item; + if (shared) { + *message_ptr++ = item; -#ifdef USE_DEVICE_GROUPS_SEND - // If we're processing a command, get a pointer to the value if one was specified. - if (use_command) value_ptr = (*delim_ptr == '=' ? delim_ptr + 1 : nullptr); -#endif // USE_DEVICE_GROUPS_SEND - - // For numeric items, get the specified value. - if (item <= DGR_ITEM_MAX_32BIT) { - -#ifdef USE_DEVICE_GROUPS_SEND - // If we're processing a command, get the final value after processing any specified - // operators. - if (use_command) { - value = 0; - if (value_ptr) { - oper = 0; - if (*value_ptr == '@') { - oper = value_ptr[1]; - value_ptr += 2; - } - value = strtoul(value_ptr, nullptr, 0); - if (oper) { - old_value = (item <= DGR_ITEM_MAX_8BIT ? device_group->values_8bit[item] : (item <= DGR_ITEM_MAX_16BIT ? device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] : device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1])); - value = (oper == '+' ? old_value + value : (oper == '-' ? old_value - value : (oper == '^' ? old_value ^ (value ? value : 0xffffffff) : old_value))); - } - } - } - else -#endif // USE_DEVICE_GROUPS_SEND - value = va_arg(ap, int); - - // If the item is shared, add it to the message. - if (shared) { -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%u"), item, value); -#endif // DEVICE_GROUPS_DEBUG + // For integer items, add the value to the message. + if (item <= DGR_ITEM_MAX_32BIT) { + value = item_ptr->value; +//#ifdef DEVICE_GROUPS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(">%u=%u"), item, value); +//#endif // DEVICE_GROUPS_DEBUG *message_ptr++ = value & 0xff; if (item > DGR_ITEM_MAX_8BIT) { #ifdef USE_DEVICE_GROUPS_SEND @@ -469,77 +463,36 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes } #endif // USE_DEVICE_GROUPS_SEND } - } - // For string items, add the string to the message prefixed by the length. - else if (item <= DGR_ITEM_MAX_STRING) { -#ifdef USE_DEVICE_GROUPS_SEND - if (!use_command) -#endif // USE_DEVICE_GROUPS_SEND - value_ptr = va_arg(ap, char *); - if (shared) { - value = (value_ptr ? strlen((const char *)value_ptr) : 0); -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%s"), item, value_ptr); -#endif // DEVICE_GROUPS_DEBUG - *message_ptr++ = value; - memcpy(message_ptr, value_ptr, value); - message_ptr += value; + // For string items, add the null-terminated string to the message. + else if (item <= DGR_ITEM_MAX_STRING) { + if (item_ptr->value_ptr) { + value = strlen((const char *)item_ptr->value_ptr); + memcpy(message_ptr, item_ptr->value_ptr, value); + message_ptr += value; + } + *message_ptr++ = 0; +//#ifdef DEVICE_GROUPS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(">%u='%s'"), item, item_ptr->value_ptr); +//#endif // DEVICE_GROUPS_DEBUG } - } - // For special items, handle them individually. - else { - switch (item) { - case DGR_ITEM_LIGHT_CHANNELS: -#ifdef USE_DEVICE_GROUPS_SEND - if (use_command) { - if (shared) { - for (int i = 0; i < 5; i++) { - value = 0; - if (value_ptr) { - value = strtoul(value_ptr, &value_ptr, 0); - value_ptr = (*value_ptr == ',' ? value_ptr + 1 : nullptr); - } - *message_ptr++ = value; - } + // For special items, handle them individually. + else { + switch (item) { + case DGR_ITEM_LIGHT_CHANNELS: + value_ptr = (char *)item_ptr->value_ptr; + for (int i = 0; i < 5; i++) { + *message_ptr++ = (value_ptr ? *value_ptr++ : 0); } - } - else { -#endif // USE_DEVICE_GROUPS_SEND - value_ptr = va_arg(ap, char *); - if (shared) { - memmove(message_ptr, value_ptr, 5); - message_ptr += 5; - } -#ifdef USE_DEVICE_GROUPS_SEND - } -#endif // USE_DEVICE_GROUPS_SEND -#ifdef DEVICE_GROUPS_DEBUG - if (shared) AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%u,%u,%u,%u,%u"), item, *(message_ptr - 5), *(message_ptr - 4), *(message_ptr - 3), *(message_ptr - 2), *(message_ptr - 1)); -#endif // DEVICE_GROUPS_DEBUG - break; +//#ifdef DEVICE_GROUPS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(">%u=%u,%u,%u,%u,%u"), item, *(message_ptr - 5), *(message_ptr - 4), *(message_ptr - 3), *(message_ptr - 2), *(message_ptr - 1)); +//#endif // DEVICE_GROUPS_DEBUG + break; + } } } - -#ifdef USE_DEVICE_GROUPS_SEND - // If we're processing a command, advance to the next item. If there are no more, break out of - // the loop. - if (use_command) { - if (!*delim_ptr) break; - if (*delim_ptr == '=') { - delim_ptr = strchr(delim_ptr, ' '); - if (!delim_ptr) break; - } - value_ptr = delim_ptr + 1; - } -#endif // USE_DEVICE_GROUPS_SEND } -#ifdef USE_DEVICE_GROUPS_SEND - if (!use_command) va_end(ap); -#else // USE_DEVICE_GROUPS_SEND - va_end(ap); -#endif // !USE_DEVICE_GROUPS_SEND // Add the EOL item code and calculate the message length. *message_ptr++ = 0; @@ -715,6 +668,7 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length) case DGR_ITEM_BRI_PRESET_HIGH: case DGR_ITEM_BRI_POWER_ON: case DGR_ITEM_POWER: + case DGR_ITEM_EVENT: case DGR_ITEM_LIGHT_CHANNELS: break; default: @@ -746,27 +700,27 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length) } #endif // USE_DEVICE_GROUPS_SEND -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("= packet_length - (message_ptr - packet)) goto badmsg; // Malformed message -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(" 0) { strlcpy(Rules.event_data, XdrvMailbox.data, sizeof(Rules.event_data)); } - ResponseCmndDone(); + if (XdrvMailbox.command) ResponseCmndDone(); } void CmndVariable(void)