mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-06-22 13:11:43 +00:00
92 lines
4.1 KiB
TypeScript
92 lines
4.1 KiB
TypeScript
import {onEvent, type OnEvent as ZhcOnEvent} from "zigbee-herdsman-converters";
|
|
|
|
import utils from "../util/utils";
|
|
import Extension from "./extension";
|
|
|
|
/**
|
|
* This extension calls the zigbee-herdsman-converters onEvent.
|
|
*/
|
|
export default class OnEvent extends Extension {
|
|
readonly #startCalled: Set<string> = new Set();
|
|
|
|
#getOnEventBaseData(device: Device): ZhcOnEvent.BaseData {
|
|
const deviceExposesChanged = (): void => this.eventBus.emitExposesAndDevicesChanged(device);
|
|
const state = this.state.get(device);
|
|
const options = device.options as KeyValue;
|
|
return {deviceExposesChanged, device: device.zh, state, options};
|
|
}
|
|
|
|
// biome-ignore lint/suspicious/useAwait: API
|
|
override async start(): Promise<void> {
|
|
for (const device of this.zigbee.devicesIterator(utils.deviceNotCoordinator)) {
|
|
// don't await, in case of repeated failures this would hold startup
|
|
this.callOnEvent(device, {type: "start", data: this.#getOnEventBaseData(device)}).catch(utils.noop);
|
|
}
|
|
|
|
this.eventBus.onDeviceJoined(this, async (data) => {
|
|
await this.callOnEvent(data.device, {type: "deviceJoined", data: this.#getOnEventBaseData(data.device)});
|
|
});
|
|
this.eventBus.onDeviceLeave(this, async (data) => {
|
|
if (data.device) {
|
|
await this.callOnEvent(data.device, {type: "stop", data: {ieeeAddr: data.device.ieeeAddr}});
|
|
}
|
|
});
|
|
this.eventBus.onEntityRemoved(this, async (data) => {
|
|
if (data.entity.isDevice()) {
|
|
await this.callOnEvent(data.entity, {type: "stop", data: {ieeeAddr: data.entity.ieeeAddr}});
|
|
}
|
|
});
|
|
this.eventBus.onDeviceInterview(this, async (data) => {
|
|
// TODO: this is triggering for any `data.status`, any use outside `successful`?
|
|
// ZHC definition would skip from `device.definition?` but OnEvent from ZHC index wouldn't => triple triggering?
|
|
await this.callOnEvent(data.device, {type: "deviceInterview", data: {...this.#getOnEventBaseData(data.device), status: data.status}});
|
|
});
|
|
this.eventBus.onDeviceAnnounce(this, async (data) => {
|
|
await this.callOnEvent(data.device, {type: "deviceAnnounce", data: this.#getOnEventBaseData(data.device)});
|
|
});
|
|
this.eventBus.onDeviceNetworkAddressChanged(this, async (data) => {
|
|
await this.callOnEvent(data.device, {type: "deviceNetworkAddressChanged", data: this.#getOnEventBaseData(data.device)});
|
|
});
|
|
this.eventBus.onEntityOptionsChanged(this, async (data) => {
|
|
if (data.entity.isDevice()) {
|
|
await this.callOnEvent(data.entity, {
|
|
type: "deviceOptionsChanged",
|
|
data: {...this.#getOnEventBaseData(data.entity), from: data.from, to: data.to},
|
|
});
|
|
this.eventBus.emitDevicesChanged();
|
|
}
|
|
});
|
|
}
|
|
|
|
override async stop(): Promise<void> {
|
|
await super.stop();
|
|
|
|
// ensure properly started, else this throws undesired errors (e.g. SIGINT during startup)
|
|
if (this.zigbee.zhController !== undefined) {
|
|
for (const device of this.zigbee.devicesIterator(utils.deviceNotCoordinator)) {
|
|
await this.callOnEvent(device, {type: "stop", data: {ieeeAddr: device.ieeeAddr}});
|
|
}
|
|
}
|
|
}
|
|
|
|
private async callOnEvent(device: Device, event: ZhcOnEvent.Event): Promise<void> {
|
|
if (device.options.disabled) {
|
|
return;
|
|
}
|
|
|
|
if (event.type === "start") {
|
|
this.#startCalled.add(device.ieeeAddr);
|
|
} else if (event.type !== "stop" && !this.#startCalled.has(device.ieeeAddr) && device.definition?.onEvent) {
|
|
this.#startCalled.add(device.ieeeAddr);
|
|
await device.definition.onEvent({type: "start", data: this.#getOnEventBaseData(device)});
|
|
}
|
|
|
|
await onEvent(event);
|
|
await device.definition?.onEvent?.(event);
|
|
|
|
if (event.type === "stop") {
|
|
this.#startCalled.delete(device.ieeeAddr);
|
|
}
|
|
}
|
|
}
|