diff --git a/Device_Groups.md b/Device_Groups.md
index 40bca68a7..c109865af 100644
--- a/Device_Groups.md
+++ b/Device_Groups.md
@@ -11,7 +11,7 @@ To enable device groups, execute the command SetOption85 1.
## Device Groups Operation
-The device group name is the MQTT group topic set with the GroupTopic command. All devices in the same IP network with the same group topic are in the same group. Some modules may define additional device groups. For example, if Remote Device Mode is enabled, the PWM Dimmer module defines three devices groups.
+The device group name is set with the DevGroupName command. If the device group name is not set for a group, the MQTT group topic is used (with the device group number appended for device group numbers > 1). All devices in the same IP network with the same device group name are in the same group. Some modules may define additional device groups. For example, if Remote Device Mode is enabled, the PWM Dimmer module defines three devices groups.
The items that are sent to the group and the items that are received from the group are selected with the DevGroupShare command. By default all items are sent and received from the group. An example of when the DevGroupShare command would be used is when you have a group of lights that you control with a dimmer switch and home automation software. You want the dimmer switch to be able to control all items. The home automation software controls each light individually. When it controls the whole group, it actually sends command to each light in the group. If you use the home automation software to turn an individual light on or off or change it’s brightness, color or scheme, you do not want the change to be replicated to the other lights. In this case, you would set the incoming and outgoing item masks to 0xffffffff (all items) on the dimmer switch (DevGroupShare 0xffffffff,0xffffffff) and set the incoming item mask to 0xffffffff and outgoing item mask to 0 on all the lights (DevGroupShare 0xffffffff,0).
@@ -34,10 +34,10 @@ The items that are sent to the group and the items that are received from the gr
- GroupTopic<x>
+ | DevGroupName<x>
|
- 1 = reset device group <x> MQTT group topic to firmware default (MQTT_GRPTOPIC) and restart
-<value> = set device group <x> MQTT group topic (32 chars max) and restart
+ | 0 = clear device group <x> name and restart
+<value> = set device group <x>name and restart
|
\ No newline at end of file
diff --git a/tasmota/i18n.h b/tasmota/i18n.h
index 7f225838e..6a6f04cec 100644
--- a/tasmota/i18n.h
+++ b/tasmota/i18n.h
@@ -293,6 +293,7 @@
#define D_CMND_SPEEDUNIT "SpeedUnit"
#define D_CMND_I2CSCAN "I2CScan"
#define D_CMND_I2CDRIVER "I2CDriver"
+#define D_CMND_DEVGROUP_NAME "DevGroupName"
#define D_CMND_DEVGROUP_SHARE "DevGroupShare"
#define D_CMND_SERIALSEND "SerialSend"
#define D_CMND_SERIALDELIMITER "SerialDelimiter"
diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino
index 64fd45997..9898b5044 100644
--- a/tasmota/support_command.ino
+++ b/tasmota/support_command.ino
@@ -32,7 +32,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix
D_CMND_I2CSCAN "|" D_CMND_I2CDRIVER "|"
#endif
#ifdef USE_DEVICE_GROUPS
- D_CMND_DEVGROUP_SHARE "|"
+ D_CMND_DEVGROUP_NAME "|" D_CMND_DEVGROUP_SHARE "|"
#endif // USE_DEVICE_GROUPS
D_CMND_SENSOR "|" D_CMND_DRIVER;
@@ -51,7 +51,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = {
&CmndI2cScan, CmndI2cDriver,
#endif
#ifdef USE_DEVICE_GROUPS
- &CmndDevGroupShare,
+ &CmndDevGroupName, &CmndDevGroupShare,
#endif // USE_DEVICE_GROUPS
&CmndSensor, &CmndDriver };
@@ -1707,6 +1707,21 @@ void CmndI2cDriver(void)
#endif // USE_I2C
#ifdef USE_DEVICE_GROUPS
+void CmndDevGroupName(void)
+{
+ if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DEV_GROUP_NAMES)) {
+ if (XdrvMailbox.data_len > 0) {
+ if (XdrvMailbox.data_len > TOPSZ)
+ XdrvMailbox.data[TOPSZ - 1] = 0;
+ else if (1 == XdrvMailbox.data_len && ('"' == XdrvMailbox.data[0] || '0' == XdrvMailbox.data[0]))
+ XdrvMailbox.data[0] = 0;
+ SettingsUpdateText(SET_DEV_GROUP_NAME1 + XdrvMailbox.index - 1, XdrvMailbox.data);
+ restart_flag = 2;
+ }
+ ResponseCmndAll(SET_DEV_GROUP_NAME1, MAX_DEV_GROUP_NAMES);
+ }
+}
+
void CmndDevGroupShare(void)
{
uint32_t parm[2] = { Settings.device_group_share_in, Settings.device_group_share_out };
diff --git a/tasmota/support_device_groups.ino b/tasmota/support_device_groups.ino
index 4e8b48041..fd9c03be9 100644
--- a/tasmota/support_device_groups.ino
+++ b/tasmota/support_device_groups.ino
@@ -62,7 +62,7 @@ bool udp_was_connected = false;
void DeviceGroupsInit(void)
{
- // Initialize the device information for each device group. The group name is the MQTT group topic.
+ // Initialize the device information for each device group.
device_groups = (struct device_group *)calloc(device_group_count, sizeof(struct device_group));
if (device_groups == nullptr) {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: error allocating %u-element device group array"), device_group_count);
@@ -72,7 +72,18 @@ void DeviceGroupsInit(void)
for (uint32_t device_group_index = 0; device_group_index < device_group_count; device_group_index++) {
struct device_group * device_group = &device_groups[device_group_index];
- strcpy(device_group->group_name, SettingsText((device_group_index == 0 ? SET_MQTT_GRP_TOPIC : SET_MQTT_GRP_TOPIC2 + device_group_index - 1)));
+ strcpy(device_group->group_name, SettingsText(SET_DEV_GROUP_NAME1 + device_group_index));
+
+ // If the device group name is not set, use the MQTT group topic (with the device group index +
+ // 1 appended for device group indices > 0).
+ if (!device_group->group_name[0]) {
+ strcpy(device_group->group_name, SettingsText(SET_MQTT_GRP_TOPIC));
+ if (device_group_index) {
+ char str[10];
+ sprintf_P(str, PSTR("%u"), device_group_index + 1);
+ strcat(device_group->group_name, str);
+ }
+ }
device_group->message_header_length = sprintf_P(device_group->message, PSTR("%s%s HTTP/1.1\n\n"), kDeviceGroupMessage, device_group->group_name);
device_group->last_full_status_sequence = -1;
}
@@ -106,7 +117,7 @@ char * BeginDeviceGroupMessage(struct device_group * device_group, uint16_t flag
}
// Return true if we're configured to share the specified item.
-bool DeviceGroupItemShared(bool incoming, uint8_t item)
+bool DevGroupItemShared(bool incoming, uint8_t item)
{
uint8_t mask = 0;
switch (item) {
@@ -149,7 +160,7 @@ void SendDeviceGroupPacket(IPAddress ip, char * packet, int len, const char * la
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: error sending %s packet"), label);
}
-void _SendDeviceGroupMessage(uint8_t device_group_index, DeviceGroupMessageType message_type, ...)
+void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType message_type, ...)
{
// If device groups are not enabled, ignore this request.
if (!Settings.flag4.device_groups_enabled) return;
@@ -184,6 +195,7 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DeviceGroupMessageType
device_group->message_length = 0;
SendDeviceGroupMessage(device_group_index, DGR_MSGTYP_PARTIAL_UPDATE, DGR_ITEM_POWER, power);
XdrvMailbox.command_code = DGR_ITEM_STATUS;
+ XdrvMailbox.topic = (char *)&device_group_index;
XdrvCall(FUNC_DEVICE_GROUP_ITEM);
building_status_message = false;
@@ -319,7 +331,7 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DeviceGroupMessageType
// Itertate through the passed items adding them and their values to the message.
va_start(ap, message_type);
while ((item = va_arg(ap, int))) {
- shared = DeviceGroupItemShared(false, item);
+ shared = DevGroupItemShared(false, item);
if (shared) *message_ptr++ = item;
if (item <= DGR_ITEM_MAX_32BIT) {
value = va_arg(ap, int);
@@ -384,10 +396,8 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DeviceGroupMessageType
uint32_t now = millis();
if (message_type == DGR_MSGTYP_UPDATE_MORE_TO_COME) {
+ device_group->message_length = 0;
device_group->next_ack_check_time = 0;
-// for (struct device_group_member * device_group_member = device_group->device_group_members; device_group_member != nullptr; device_group_member = device_group_member->flink) {
-// device_group_member->acked_sequence = outgoing_sequence;
-// }
}
else {
device_group->ack_check_interval = 100;
@@ -410,7 +420,7 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length)
// Search for a device group with the target group name. If one isn't found, return.
struct device_group * device_group;
- uint32_t device_group_index = 0;
+ uint8_t device_group_index = 0;
for (;;) {
device_group = &device_groups[device_group_index];
if (!strcmp(message_group_name, device_group->group_name)) break;
@@ -518,15 +528,16 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length)
bool grpflg
bool usridx
uint16_t command_code Item code
- uint32_t index 0:15 Flags, 16:23 Device group index
+ uint32_t index 0:15 Flags, 16:31 Message sequence
uint32_t data_len String item value length
int32_t payload Integer item value
- char *topic
+ char *topic Pointer to device group index
char *data Pointer to non-integer item value
char *command nullptr
*/
XdrvMailbox.command = nullptr; // Indicates the source is a device group update
- XdrvMailbox.index = flags | device_group_index << 16;
+ XdrvMailbox.index = flags | message_sequence << 16;
+ XdrvMailbox.topic = (char *)&device_group_index;
if (flags & (DGR_FLAG_MORE_TO_COME | DGR_FLAG_DIRECT)) skip_light_fade = true;
for (;;) {
@@ -589,7 +600,7 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length)
}
}
- if (DeviceGroupItemShared(true, item)) {
+ if (DevGroupItemShared(true, item)) {
if (item == DGR_ITEM_POWER) {
if (device_group->local) {
uint8_t mask_devices = value >> 24;
@@ -744,7 +755,7 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex
if (device_group->next_ack_check_time < next_check_time) next_check_time = device_group->next_ack_check_time;
}
- // If it's time to send multicast announcement for this group, send it. This is to
+ // If it's time to send a multicast announcement for this group, send it. This is to
// announcement ourself to any members that have somehow not heard about us. We send it at
// the announcement interval plus a random number of milliseconds so that even if all the
// devices booted at the same time, they don't all multicast their announcements at the same
@@ -753,11 +764,10 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: next_announcement_time=%u, now=%u"), device_group->next_announcement_time, now);
#endif // DEVICE_GROUPS_DEBUG
if (device_group->next_announcement_time <= now) {
- device_group->message_length = BeginDeviceGroupMessage(device_group, DGR_FLAG_ANNOUNCEMENT) - device_group->message;
#ifdef DEVICE_GROUPS_DEBUG
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending %u-byte device group %s announcement"), device_group->message_length, device_group->group_name);
#endif // DEVICE_GROUPS_DEBUG
- SendDeviceGroupPacket(0, device_group->message, device_group->message_length, PSTR("Announcement"));
+ SendDeviceGroupPacket(0, device_group->message, BeginDeviceGroupMessage(device_group, DGR_FLAG_ANNOUNCEMENT, true) - device_group->message, PSTR("Announcement"));
device_group->next_announcement_time = now + DGR_ANNOUNCEMENT_INTERVAL + random(10000);
}
if (device_group->next_announcement_time < next_check_time) next_check_time = device_group->next_announcement_time;
diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h
index 48a853891..431a116ec 100644
--- a/tasmota/tasmota.h
+++ b/tasmota/tasmota.h
@@ -82,6 +82,7 @@ const uint8_t MAX_RULE_MEMS = 16; // Max number of saved vars
const uint8_t MAX_FRIENDLYNAMES = 8; // Max number of Friendly names
const uint8_t MAX_BUTTON_TEXT = 16; // Max number of GUI button labels
const uint8_t MAX_GROUP_TOPICS = 4; // Max number of Group Topics
+const uint8_t MAX_DEV_GROUP_NAMES = 4; // Max number of Device Group names
const uint8_t MAX_HUE_DEVICES = 15; // Max number of Philips Hue device per emulation
@@ -302,30 +303,30 @@ enum SettingsTextIndex { SET_OTAURL,
SET_BUTTON1, SET_BUTTON2, SET_BUTTON3, SET_BUTTON4, SET_BUTTON5, SET_BUTTON6, SET_BUTTON7, SET_BUTTON8,
SET_BUTTON9, SET_BUTTON10, SET_BUTTON11, SET_BUTTON12, SET_BUTTON13, SET_BUTTON14, SET_BUTTON15, SET_BUTTON16,
SET_MQTT_GRP_TOPIC2, SET_MQTT_GRP_TOPIC3, SET_MQTT_GRP_TOPIC4,
- SET_TEMPLATE_NAME,
+ SET_TEMPLATE_NAME, SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4,
SET_MAX };
-enum DeviceGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYP_REUPDATE };
+enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYP_REUPDATE };
-enum DeviceGroupMessageFlag { DGR_FLAG_RESET = 1, DGR_FLAG_STATUS_REQUEST = 2, DGR_FLAG_FULL_STATUS = 4, DGR_FLAG_ACK = 8, DGR_FLAG_MORE_TO_COME = 16, DGR_FLAG_DIRECT = 32, DGR_FLAG_ANNOUNCEMENT = 64 };
+enum DevGroupMessageFlag { DGR_FLAG_RESET = 1, DGR_FLAG_STATUS_REQUEST = 2, DGR_FLAG_FULL_STATUS = 4, DGR_FLAG_ACK = 8, DGR_FLAG_MORE_TO_COME = 16, DGR_FLAG_DIRECT = 32, DGR_FLAG_ANNOUNCEMENT = 64 };
-enum DeviceGroupItem { DGR_ITEM_EOL, DGR_ITEM_STATUS,
- DGR_ITEM_LIGHT_FADE, DGR_ITEM_LIGHT_SPEED, DGR_ITEM_LIGHT_BRI, DGR_ITEM_LIGHT_SCHEME, DGR_ITEM_LIGHT_FIXED_COLOR,
- DGR_ITEM_BRI_PRESET_LOW, DGR_ITEM_BRI_PRESET_HIGH, DGR_ITEM_BRI_POWER_ON,
- // Add new 8-bit items before this line
- DGR_ITEM_LAST_8BIT, DGR_ITEM_MAX_8BIT = 63,
- DGR_ITEM_ANALOG1, DGR_ITEM_ANALOG2, DGR_ITEM_ANALOG3, DGR_ITEM_ANALOG4, DGR_ITEM_ANALOG5,
- // Add new 16-bit items before this line
- DGR_ITEM_LAST_16BIT, DGR_ITEM_MAX_16BIT = 127,
- DGR_ITEM_POWER, DGR_ITEM_DIMMER_RANGE,
- // Add new 32-bit items before this line
- DGR_ITEM_LAST_32BIT, DGR_ITEM_MAX_32BIT = 191,
- // Add new string items before this line
- DGR_ITEM_LAST_STRING, DGR_ITEM_MAX_STRING = 223,
- DGR_ITEM_LIGHT_CHANNELS };
+enum DevGroupItem { DGR_ITEM_EOL, DGR_ITEM_STATUS,
+ DGR_ITEM_LIGHT_FADE, DGR_ITEM_LIGHT_SPEED, DGR_ITEM_LIGHT_BRI, DGR_ITEM_LIGHT_SCHEME, DGR_ITEM_LIGHT_FIXED_COLOR,
+ DGR_ITEM_BRI_PRESET_LOW, DGR_ITEM_BRI_PRESET_HIGH, DGR_ITEM_BRI_POWER_ON,
+ // Add new 8-bit items before this line
+ DGR_ITEM_LAST_8BIT, DGR_ITEM_MAX_8BIT = 63,
+ DGR_ITEM_ANALOG1, DGR_ITEM_ANALOG2, DGR_ITEM_ANALOG3, DGR_ITEM_ANALOG4, DGR_ITEM_ANALOG5,
+ // Add new 16-bit items before this line
+ DGR_ITEM_LAST_16BIT, DGR_ITEM_MAX_16BIT = 127,
+ DGR_ITEM_POWER, DGR_ITEM_DIMMER_RANGE,
+ // Add new 32-bit items before this line
+ DGR_ITEM_LAST_32BIT, DGR_ITEM_MAX_32BIT = 191,
+ // Add new string items before this line
+ DGR_ITEM_LAST_STRING, DGR_ITEM_MAX_STRING = 223,
+ DGR_ITEM_LIGHT_CHANNELS };
-enum DeviceGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE_LIGHT_FADE = 4, DGR_SHARE_LIGHT_SCHEME = 8,
- DGR_SHARE_LIGHT_COLOR = 16, DGR_SHARE_DIMMER_SETTINGS = 32 };
+enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE_LIGHT_FADE = 4, DGR_SHARE_LIGHT_SCHEME = 8,
+ DGR_SHARE_LIGHT_COLOR = 16, DGR_SHARE_DIMMER_SETTINGS = 32 };
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,
diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino
index 8de0616b7..9b83a6879 100644
--- a/tasmota/xdrv_04_light.ino
+++ b/tasmota/xdrv_04_light.ino
@@ -2131,14 +2131,14 @@ void LightSendDeviceGroupStatus(bool force)
}
}
-void LightHandleDeviceGroupItem(void)
+void LightHandleDevGroupItem(void)
{
static bool send_state = false;
static bool restore_power = false;
bool more_to_come;
uint32_t value = XdrvMailbox.payload;
#ifdef USE_PWM_DIMMER_REMOTE
- if (XdrvMailbox.index & 0xff0000) return; // Ignore updates from other device groups
+ if (*XdrvMailbox.topic) return; // Ignore updates from other device groups
#endif // USE_PWM_DIMMER_REMOTE
switch (XdrvMailbox.command_code) {
case DGR_ITEM_EOL:
@@ -2774,7 +2774,7 @@ bool Xdrv04(uint8_t function)
break;
#ifdef USE_DEVICE_GROUPS
case FUNC_DEVICE_GROUP_ITEM:
- LightHandleDeviceGroupItem();
+ LightHandleDevGroupItem();
break;
#endif // USE_DEVICE_GROUPS
case FUNC_SET_POWER:
diff --git a/tasmota/xdrv_35_pwm_dimmer.ino b/tasmota/xdrv_35_pwm_dimmer.ino
index 0e0594a8b..24195a080 100644
--- a/tasmota/xdrv_35_pwm_dimmer.ino
+++ b/tasmota/xdrv_35_pwm_dimmer.ino
@@ -101,6 +101,7 @@ void PWMModulePreInit(void)
if (Settings.flag4.remote_device_mode) {
Settings.flag4.device_groups_enabled = true;
+ device_group_count = 0;
for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) {
if (pin[GPIO_KEY1 + button_index] < 99) device_group_count++;
}
@@ -169,11 +170,11 @@ void PWMDimmerSetPower(void)
}
#ifdef USE_DEVICE_GROUPS
-void PWMDimmerHandleDeviceGroupItem(void)
+void PWMDimmerHandleDevGroupItem(void)
{
uint32_t value = XdrvMailbox.payload;
#ifdef USE_PWM_DIMMER_REMOTE
- uint8_t device_group_index = XdrvMailbox.index >> 16 & 0xff;
+ uint8_t device_group_index = *(uint8_t *)XdrvMailbox.topic;
bool device_is_local = device_groups[device_group_index].local;
struct remote_pwm_dimmer * remote_pwm_dimmer = &remote_pwm_dimmers[device_group_index];
#endif // USE_PWM_DIMMER_REMOTE
@@ -763,7 +764,7 @@ bool Xdrv35(uint8_t function)
#ifdef USE_DEVICE_GROUPS
case FUNC_DEVICE_GROUP_ITEM:
- PWMDimmerHandleDeviceGroupItem();
+ PWMDimmerHandleDevGroupItem();
break;
#endif // USE_DEVICE_GROUPS