Skip to content

Commit

Permalink
fix: Remove group from Home Assistant when removed (#23492)
Browse files Browse the repository at this point in the history
* Fire event when group gets removed

* Add a unit test for the new behavior

* Make prettier happy

* Add missing return type

* Merge device and group removal events

* Unbreak bridgeLegacy.ts

* Update homeassistant.ts

* Update bridge.ts

* Update bridge.ts

---------

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
  • Loading branch information
LaurentvdBos and Koenkk authored Aug 4, 2024
1 parent e132316 commit d0f5733
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 13 deletions.
4 changes: 2 additions & 2 deletions lib/eventBus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ export default class EventBus {
this.on('deviceRenamed', callback, key);
}

public emitDeviceRemoved(data: eventdata.DeviceRemoved): void {
public emitEntityRemoved(data: eventdata.EntityRemoved): void {
this.emitter.emit('deviceRemoved', data);
}
public onDeviceRemoved(key: ListenerKey, callback: (data: eventdata.DeviceRemoved) => void): void {
public onEntityRemoved(key: ListenerKey, callback: (data: eventdata.EntityRemoved) => void): void {
this.on('deviceRemoved', callback, key);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/extension/availability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export default class Availability extends Extension {
}
});

this.eventBus.onDeviceRemoved(this, (data) => clearTimeout(this.timers[data.ieeeAddr]));
this.eventBus.onEntityRemoved(this, (data) => data.type == 'device' && clearTimeout(this.timers[data.id]));
this.eventBus.onDeviceLeave(this, (data) => clearTimeout(this.timers[data.ieeeAddr]));
this.eventBus.onDeviceAnnounce(this, (data) => this.retrieveState(data.device));
this.eventBus.onLastSeenChanged(this, this.onLastSeenChanged);
Expand Down
5 changes: 3 additions & 2 deletions lib/extension/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,6 @@ export default class Bridge extends Extension {

try {
logger.info(`Removing ${entityType} '${entity.name}'${blockForceLog}`);
const ieeeAddr = entity.isDevice() && entity.ieeeAddr;
const name = entity.name;

if (entity instanceof Device) {
Expand All @@ -641,7 +640,9 @@ export default class Bridge extends Extension {

// Fire event
if (entity instanceof Device) {
this.eventBus.emitDeviceRemoved({ieeeAddr, name});
this.eventBus.emitEntityRemoved({id: entityID, name, type: 'device'});
} else {
this.eventBus.emitEntityRemoved({id: entityID, name, type: 'group'});
}

// Remove from configuration.yaml
Expand Down
12 changes: 6 additions & 6 deletions lib/extension/homeassistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export default class HomeAssistant extends Extension {
this.discoveryOrigin = {name: 'Zigbee2MQTT', sw: this.zigbee2MQTTVersion, url: 'https://www.zigbee2mqtt.io'};
this.bridge = this.getBridgeEntity(await this.zigbee.getCoordinatorVersion());
this.bridgeIdentifier = this.getDevicePayload(this.bridge).identifiers[0];
this.eventBus.onDeviceRemoved(this, this.onDeviceRemoved);
this.eventBus.onEntityRemoved(this, this.onEntityRemoved);
this.eventBus.onMQTTMessage(this, this.onMQTTMessage);
this.eventBus.onEntityRenamed(this, this.onEntityRenamed);
this.eventBus.onPublishEntityState(this, this.onPublishEntityState);
Expand Down Expand Up @@ -244,8 +244,8 @@ export default class HomeAssistant extends Extension {
this.eventBus.emitPublishAvailability();
}

private getDiscovered(entity: Device | Group | Bridge | string): Discovered {
const ID = typeof entity === 'string' ? entity : entity.ID;
private getDiscovered(entity: Device | Group | Bridge | string | number): Discovered {
const ID = typeof entity === 'string' || typeof entity === 'number' ? entity : entity.ID;
if (!(ID in this.discovered)) {
this.discovered[ID] = {messages: {}, triggers: new Set(), mockProperties: new Set(), discovered: false};
}
Expand Down Expand Up @@ -1194,15 +1194,15 @@ export default class HomeAssistant extends Extension {
return discoveryEntries;
}

@bind async onDeviceRemoved(data: eventdata.DeviceRemoved): Promise<void> {
@bind async onEntityRemoved(data: eventdata.EntityRemoved): Promise<void> {
logger.debug(`Clearing Home Assistant discovery for '${data.name}'`);
const discovered = this.getDiscovered(data.ieeeAddr);
const discovered = this.getDiscovered(data.id);

for (const topic of Object.keys(discovered.messages)) {
await this.mqtt.publish(topic, null, {retain: true, qos: 1}, this.discoveryTopic, false, false);
}

delete this.discovered[data.ieeeAddr];
delete this.discovered[data.id];
}

@bind async onGroupMembersChanged(data: eventdata.GroupMembersChanged): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion lib/extension/legacy/bridgeLegacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ export default class BridgeLegacy extends Extension {

const cleanup = async (): Promise<void> => {
// Fire event
this.eventBus.emitDeviceRemoved({ieeeAddr, name});
this.eventBus.emitEntityRemoved({id: ieeeAddr, name: name, type: 'device'});

// Remove from configuration.yaml
settings.removeDevice(entity.ieeeAddr);
Expand Down
2 changes: 1 addition & 1 deletion lib/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ declare global {

namespace eventdata {
type EntityRenamed = {entity: Device | Group; homeAssisantRename: boolean; from: string; to: string};
type DeviceRemoved = {ieeeAddr: string; name: string};
type EntityRemoved = {id: number | string; name: string; type: 'device' | 'group'};
type MQTTMessage = {topic: string; message: string};
type MQTTMessagePublished = {topic: string; payload: string; options: {retain: boolean; qos: number}};
type StateChange = {
Expand Down
13 changes: 13 additions & 0 deletions test/homeassistant.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1443,6 +1443,19 @@ describe('HomeAssistant extension', () => {
);
});

it('Should clear discovery when group is removed', async () => {
MQTT.publish.mockClear();
MQTT.events.message('zigbee2mqtt/bridge/request/group/remove', stringify({id: 'ha_discovery_group'}));
await flushPromises();

expect(MQTT.publish).toHaveBeenCalledWith(
'homeassistant/light/1221051039810110150109113116116_9/light/config',
null,
{retain: true, qos: 1},
expect.any(Function),
);
});

it('Should refresh discovery when device is renamed', async () => {
await MQTT.events.message(
'homeassistant/device_automation/0x0017880104e45522/action_double/config',
Expand Down

0 comments on commit d0f5733

Please sign in to comment.