Skip to content

Commit

Permalink
fix: Fix group with only multi endpoints devices not being controllab…
Browse files Browse the repository at this point in the history
…le (#25156)
  • Loading branch information
Koenkk authored Dec 14, 2024
1 parent 39c007d commit 7242889
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 22 deletions.
3 changes: 2 additions & 1 deletion lib/extension/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ export default class Publish extends Extension {
/* istanbul ignore next */
// Match any key if the toZigbee converter defines no key.
const converter = converters.find(
(c) => (!c.key || c.key.includes(key)) && (!c.endpoints || (endpointName && c.endpoints.includes(endpointName))),
(c) =>
(!c.key || c.key.includes(key)) && (re instanceof Group || !c.endpoints || (endpointName && c.endpoints.includes(endpointName))),
);

if (parsedTopic.type === 'set' && converter && usedConverters[endpointOrGroupID].includes(converter)) {
Expand Down
1 change: 1 addition & 0 deletions test/extensions/availability.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ returnDevices.push(
devices.ZNCZ02LM.ieeeAddr,
devices.GLEDOPTO_2ID.ieeeAddr,
devices.QBKG03LM.ieeeAddr,
devices.hue_twilight.ieeeAddr,
);

describe('Extension: Availability', () => {
Expand Down
98 changes: 79 additions & 19 deletions test/extensions/bridge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ describe('Extension: Bridge', () => {
const zhVersion = await utils.getDependencyVersion('zigbee-herdsman');
const zhcVersion = await utils.getDependencyVersion('zigbee-herdsman-converters');
const directory = settings.get().advanced.log_directory;
// console.log(mockMQTT.publish.mock.calls.find((c) => c[0] === 'zigbee2mqtt/bridge/info')[1])
// console.log(mockMQTT.publishAsync.mock.calls.find((c) => c[0] === 'zigbee2mqtt/bridge/info')![1]);
expect(mockMQTT.publishAsync).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/info',
stringify({
Expand Down Expand Up @@ -118,36 +118,78 @@ describe('Extension: Bridge', () => {
blocklist: [],
device_options: {},
devices: {
'0x000b57fffec6a5b2': {description: 'this is my bulb', friendly_name: 'bulb', retain: true},
'0x000b57cdfec6a5b3': {friendly_name: 'hue_twilight'},
'0x000b57fffec6a5b2': {
description: 'this is my bulb',
friendly_name: 'bulb',
retain: true,
},
'0x000b57fffec6a5b3': {friendly_name: 'bulb_color', retain: false},
'0x000b57fffec6a5b4': {friendly_name: 'bulb_color_2', retain: false},
'0x000b57fffec6a5b4': {
friendly_name: 'bulb_color_2',
retain: false,
},
'0x000b57fffec6a5b7': {friendly_name: 'bulb_2', retain: false},
'0x0017880104a44559': {friendly_name: 'J1_cover'},
'0x0017880104e43559': {friendly_name: 'U202DST600ZB'},
'0x0017880104e44559': {friendly_name: '3157100_thermostat'},
'0x0017880104e45517': {friendly_name: 'remote', retain: true},
'0x0017880104e45520': {friendly_name: 'button', retain: false},
'0x0017880104e45521': {friendly_name: 'button_double_key', retain: false},
'0x0017880104e45522': {friendly_name: 'weather_sensor', qos: 1, retain: false},
'0x0017880104e45523': {friendly_name: 'occupancy_sensor', retain: false},
'0x0017880104e45521': {
friendly_name: 'button_double_key',
retain: false,
},
'0x0017880104e45522': {
friendly_name: 'weather_sensor',
qos: 1,
retain: false,
},
'0x0017880104e45523': {
friendly_name: 'occupancy_sensor',
retain: false,
},
'0x0017880104e45524': {friendly_name: 'power_plug', retain: false},
'0x0017880104e45526': {friendly_name: 'GL-S-007ZS'},
'0x0017880104e45529': {friendly_name: 'unsupported2', retain: false},
'0x0017880104e45530': {friendly_name: 'button_double_key_interviewing', retain: false},
'0x0017880104e45529': {
friendly_name: 'unsupported2',
retain: false,
},
'0x0017880104e45530': {
friendly_name: 'button_double_key_interviewing',
retain: false,
},
'0x0017880104e45540': {friendly_name: 'ikea_onoff'},
'0x0017880104e45541': {friendly_name: 'wall_switch', retain: false},
'0x0017880104e45542': {friendly_name: 'wall_switch_double', retain: false},
'0x0017880104e45543': {friendly_name: 'led_controller_1', retain: false},
'0x0017880104e45544': {friendly_name: 'led_controller_2', retain: false},
'0x0017880104e45545': {friendly_name: 'dimmer_wall_switch', retain: false},
'0x0017880104e45542': {
friendly_name: 'wall_switch_double',
retain: false,
},
'0x0017880104e45543': {
friendly_name: 'led_controller_1',
retain: false,
},
'0x0017880104e45544': {
friendly_name: 'led_controller_2',
retain: false,
},
'0x0017880104e45545': {
friendly_name: 'dimmer_wall_switch',
retain: false,
},
'0x0017880104e45547': {friendly_name: 'curtain', retain: false},
'0x0017880104e45548': {friendly_name: 'fan', retain: false},
'0x0017880104e45549': {friendly_name: 'siren', retain: false},
'0x0017880104e45550': {friendly_name: 'thermostat', retain: false},
'0x0017880104e45551': {friendly_name: 'smart vent', retain: false},
'0x0017880104e45552': {friendly_name: 'j1', retain: false},
'0x0017880104e45553': {friendly_name: 'bulb_enddevice', retain: false},
'0x0017880104e45559': {friendly_name: 'cc2530_router', retain: false},
'0x0017880104e45553': {
friendly_name: 'bulb_enddevice',
retain: false,
},
'0x0017880104e45559': {
friendly_name: 'cc2530_router',
retain: false,
},
'0x0017880104e45560': {friendly_name: 'livolo', retain: false},
'0x0017880104e45561': {friendly_name: 'temperature_sensor'},
'0x0017880104e45562': {friendly_name: 'heating_actuator'},
Expand All @@ -160,7 +202,10 @@ describe('Extension: Bridge', () => {
'0x90fd9ffffe4b64aa': {friendly_name: 'SP600_OLD'},
'0x90fd9ffffe4b64ab': {friendly_name: 'SP600_NEW'},
'0x90fd9ffffe4b64ac': {friendly_name: 'MKS-CM-W5'},
'0x90fd9ffffe4b64ae': {friendly_name: 'tradfri_remote', retain: false},
'0x90fd9ffffe4b64ae': {
friendly_name: 'tradfri_remote',
retain: false,
},
'0x90fd9ffffe4b64af': {friendly_name: 'roller_shutter'},
'0x90fd9ffffe4b64ax': {friendly_name: 'ZNLDP12LM'},
'0xf4ce368a38be56a1': {
Expand All @@ -187,6 +232,7 @@ describe('Extension: Bridge', () => {
12: {friendly_name: 'thermostat_group', retain: false},
14: {friendly_name: 'switch_group', retain: false},
15071: {friendly_name: 'group_tradfri_remote', retain: false},
19: {friendly_name: 'hue_twilight_group'},
2: {friendly_name: 'group_2', retain: false},
21: {friendly_name: 'gledopto_group'},
9: {friendly_name: 'ha_discovery_group'},
Expand All @@ -195,8 +241,16 @@ describe('Extension: Bridge', () => {
map_options: {
graphviz: {
colors: {
fill: {coordinator: '#e04e5d', enddevice: '#fff8ce', router: '#4ea3e0'},
font: {coordinator: '#ffffff', enddevice: '#000000', router: '#ffffff'},
fill: {
coordinator: '#e04e5d',
enddevice: '#fff8ce',
router: '#4ea3e0',
},
font: {
coordinator: '#ffffff',
enddevice: '#000000',
router: '#ffffff',
},
line: {active: '#009900', inactive: '#994444'},
},
},
Expand All @@ -209,10 +263,10 @@ describe('Extension: Bridge', () => {
server: 'mqtt://localhost',
},
ota: {
default_maximum_data_size: 50,
disable_automatic_update_check: false,
update_check_interval: 1440,
image_block_response_delay: 250,
default_maximum_data_size: 50,
update_check_interval: 1440,
},
passlist: [],
serial: {disable_led: false, port: '/dev/dummy'},
Expand Down Expand Up @@ -2174,6 +2228,12 @@ describe('Extension: Bridge', () => {
],
scenes: [{id: 4, name: 'Scene 4'}],
},
{
friendly_name: 'hue_twilight_group',
id: 19,
members: [{endpoint: 11, ieee_address: '0x000b57cdfec6a5b3'}],
scenes: [],
},
]),
{retain: true, qos: 0},
);
Expand Down
17 changes: 15 additions & 2 deletions test/extensions/publish.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,19 @@ describe('Extension: Publish', () => {
);
});

it('Should publish messages to group with just 1 Hue Twilight in int (convers have an `endpoint` on it)', async () => {
// https://github.com/Koenkk/zigbee2mqtt/issues/24792
const group = groups.hue_twilight_group;
await mockMQTTEvents.message('zigbee2mqtt/hue_twilight_group/set', stringify({state: 'ON'}));
await flushPromises();
console.log(mockLogger.warning.mock.calls);
expect(group.command).toHaveBeenCalledTimes(1);
expect(group.command).toHaveBeenCalledWith('genOnOff', 'on', {}, {});
expect(mockMQTT.publishAsync).toHaveBeenCalledTimes(2);
expect(mockMQTT.publishAsync.mock.calls[1][0]).toStrictEqual('zigbee2mqtt/hue_twilight_group');
expect(JSON.parse(mockMQTT.publishAsync.mock.calls[1][1])).toStrictEqual({state: 'ON'});
});

it('Should publish messages to groups with on and brightness', async () => {
const group = groups.group_1;
group.members.push(devices.bulb_color.getEndpoint(1)!);
Expand Down Expand Up @@ -483,10 +496,10 @@ describe('Extension: Publish', () => {

it('Should create and publish to group which is in configuration.yaml but not in zigbee-herdsman', async () => {
settings.addGroup('group_12312', '12312');
expect(Object.values(groups).length).toBe(10);
expect(Object.values(groups).length).toBe(11);
await mockMQTTEvents.message('zigbee2mqtt/group_12312/set', stringify({state: 'ON'}));
await flushPromises();
expect(Object.values(groups).length).toBe(11);
expect(Object.values(groups).length).toBe(12);
// group contains no device
// @ts-expect-error runtime mock
expect(groups.group_12312.command).toHaveBeenCalledTimes(0);
Expand Down
6 changes: 6 additions & 0 deletions test/mocks/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ export function writeDefaultConfiguration(config: unknown = undefined): void {
'0x0017880104e45562': {
friendly_name: 'heating_actuator',
},
'0x000b57cdfec6a5b3': {
friendly_name: 'hue_twilight',
},
},
groups: {
1: {
Expand Down Expand Up @@ -233,6 +236,9 @@ export function writeDefaultConfiguration(config: unknown = undefined): void {
9: {
friendly_name: 'ha_discovery_group',
},
19: {
friendly_name: 'hue_twilight_group',
},
},
};

Expand Down
22 changes: 22 additions & 0 deletions test/mocks/zigbeeHerdsman.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,26 @@ const bulb_2 = new Device(
'Mains (single phase)',
'TRADFRI bulb E27 WS opal 980lm',
);
const hue_twilight = new Device(
'Router',
'0x000b57cdfec6a5b3',
40399,
4107,
[
new Endpoint(1, [0, 3, 4, 5, 6, 8, 768, 2821, 4096], [5, 25, 32, 4096], '0x000b57cdfec6a5b3', [], {
lightingColorCtrl: {colorCapabilities: 254},
}),
new Endpoint(11, [0, 3, 4, 5, 6, 8, 768, 2821, 4096], [5, 25, 32, 4096], '0x000b57cdfec6a5b3', [], {
lightingColorCtrl: {colorCapabilities: 254},
}),
new Endpoint(12, [0, 3, 4, 5, 6, 8, 768, 2821, 4096], [5, 25, 32, 4096], '0x000b57cdfec6a5b3', [], {
lightingColorCtrl: {colorCapabilities: 254},
}),
],
true,
'Mains (single phase)',
'LGT003',
);
const TS0601_thermostat = new Device(
'EndDevice',
'0x0017882104a44559',
Expand Down Expand Up @@ -488,6 +508,7 @@ export const groups = {
gledopto_group: new Group(21, [GLEDOPTO_2ID.endpoints[3]]),
default_bind_group: new Group(901, []),
ha_discovery_group: new Group(9, [bulb_color_2.endpoints[0], bulb_2.endpoints[0], QBKG03LM.endpoints[2]]),
hue_twilight_group: new Group(19, [hue_twilight.endpoints[1]]),
};

const groupMembersBackup = Object.fromEntries(Object.entries(groups).map((v) => [v[0], [...v[1].members]]));
Expand Down Expand Up @@ -545,6 +566,7 @@ export const devices = {
),
bulb_color: bulb_color,
bulb_2: bulb_2,
hue_twilight,
bulb_color_2: bulb_color_2,
remote: new Device(
'EndDevice',
Expand Down

0 comments on commit 7242889

Please sign in to comment.