@willieee802/zigbee-herdsman 0.49.3 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +0 -3
- package/.github/workflows/ci.yml +1 -2
- package/.github/workflows/release-please.yml +1 -1
- package/.github/workflows/typedoc.yaml +3 -3
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +143 -0
- package/biome.json +1 -1
- package/dist/adapter/adapter.d.ts +14 -1
- package/dist/adapter/adapter.d.ts.map +1 -1
- package/dist/adapter/adapter.js +17 -0
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/adapterDiscovery.d.ts.map +1 -1
- package/dist/adapter/adapterDiscovery.js.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +1 -3
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.js +14 -29
- package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.d.ts +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.js +19 -10
- package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.d.ts +2 -0
- package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.js +13 -5
- package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +1 -3
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.js +17 -30
- package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
- package/dist/adapter/ezsp/driver/index.d.ts +1 -1
- package/dist/adapter/ezsp/driver/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/index.js +1 -1
- package/dist/adapter/ezsp/driver/index.js.map +1 -1
- package/dist/adapter/ezsp/driver/types/index.d.ts +1 -1
- package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/types/index.js +3 -3
- package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
- package/dist/adapter/serialPort.d.ts.map +1 -1
- package/dist/adapter/serialPort.js +7 -0
- package/dist/adapter/serialPort.js.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-backup.js +1 -1
- package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +1 -1
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.js +12 -2
- package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
- package/dist/adapter/z-stack/adapter/tstype.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +1 -3
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.js +20 -34
- package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
- package/dist/adapter/z-stack/constants/index.d.ts +1 -1
- package/dist/adapter/z-stack/constants/index.d.ts.map +1 -1
- package/dist/adapter/z-stack/constants/index.js +1 -1
- package/dist/adapter/z-stack/constants/index.js.map +1 -1
- package/dist/adapter/z-stack/unpi/constants.d.ts +1 -1
- package/dist/adapter/z-stack/unpi/constants.d.ts.map +1 -1
- package/dist/adapter/z-stack/unpi/constants.js +1 -1
- package/dist/adapter/z-stack/unpi/constants.js.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +7 -8
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.js +12 -30
- package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
- package/dist/adapter/zboss/driver.d.ts.map +1 -1
- package/dist/adapter/zboss/driver.js +8 -1
- package/dist/adapter/zboss/driver.js.map +1 -1
- package/dist/adapter/zboss/uart.d.ts.map +1 -1
- package/dist/adapter/zboss/uart.js +14 -2
- package/dist/adapter/zboss/uart.js.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +1 -3
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.js +8 -29
- package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
- package/dist/adapter/zoh/adapter/zohAdapter.d.ts +1 -3
- package/dist/adapter/zoh/adapter/zohAdapter.d.ts.map +1 -1
- package/dist/adapter/zoh/adapter/zohAdapter.js +18 -33
- package/dist/adapter/zoh/adapter/zohAdapter.js.map +1 -1
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +10 -2
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/greenPower.d.ts.map +1 -1
- package/dist/controller/greenPower.js +15 -9
- package/dist/controller/greenPower.js.map +1 -1
- package/dist/controller/helpers/ota.d.ts +4 -4
- package/dist/controller/helpers/ota.d.ts.map +1 -1
- package/dist/controller/helpers/ota.js +28 -9
- package/dist/controller/helpers/ota.js.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.js +17 -16
- package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
- package/dist/controller/model/device.d.ts +14 -4
- package/dist/controller/model/device.d.ts.map +1 -1
- package/dist/controller/model/device.js +167 -85
- package/dist/controller/model/device.js.map +1 -1
- package/dist/controller/model/endpoint.d.ts +7 -3
- package/dist/controller/model/endpoint.d.ts.map +1 -1
- package/dist/controller/model/endpoint.js +34 -21
- package/dist/controller/model/endpoint.js.map +1 -1
- package/dist/controller/model/group.d.ts +0 -1
- package/dist/controller/model/group.d.ts.map +1 -1
- package/dist/controller/model/group.js +14 -19
- package/dist/controller/model/group.js.map +1 -1
- package/dist/controller/touchlink.js +3 -3
- package/dist/controller/touchlink.js.map +1 -1
- package/dist/utils/timeService.js +2 -2
- package/dist/utils/timeService.js.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.d.ts +3 -3
- package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.js +198 -96
- package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
- package/dist/zspec/zcl/definition/cluster.d.ts +2 -2
- package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/cluster.js +2699 -2808
- package/dist/zspec/zcl/definition/cluster.js.map +1 -1
- package/dist/zspec/zcl/definition/clusters-types.d.ts +63 -1109
- package/dist/zspec/zcl/definition/clusters-types.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.d.ts +0 -1
- package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.js +0 -1
- package/dist/zspec/zcl/definition/enums.js.map +1 -1
- package/dist/zspec/zcl/definition/foundation.d.ts +306 -7
- package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/foundation.js +552 -207
- package/dist/zspec/zcl/definition/foundation.js.map +1 -1
- package/dist/zspec/zcl/definition/status.d.ts +21 -10
- package/dist/zspec/zcl/definition/status.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/status.js +11 -0
- package/dist/zspec/zcl/definition/status.js.map +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts +57 -48
- package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.d.ts +7 -4
- package/dist/zspec/zcl/utils.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.js +133 -240
- package/dist/zspec/zcl/utils.js.map +1 -1
- package/dist/zspec/zcl/zclFrame.d.ts +4 -4
- package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
- package/dist/zspec/zcl/zclFrame.js +19 -103
- package/dist/zspec/zcl/zclFrame.js.map +1 -1
- package/dist/zspec/zcl/zclStatusError.d.ts +1 -1
- package/dist/zspec/zcl/zclStatusError.d.ts.map +1 -1
- package/dist/zspec/zcl/zclStatusError.js +2 -2
- package/dist/zspec/zcl/zclStatusError.js.map +1 -1
- package/package.json +1 -1
- package/scripts/clusters-typegen.ts +44 -139
- package/src/adapter/adapter.ts +38 -3
- package/src/adapter/adapterDiscovery.ts +2 -1
- package/src/adapter/deconz/adapter/deconzAdapter.ts +24 -51
- package/src/adapter/deconz/driver/constants.ts +1 -1
- package/src/adapter/ember/adapter/emberAdapter.ts +23 -10
- package/src/adapter/ember/adapter/oneWaitress.ts +16 -6
- package/src/adapter/ezsp/adapter/ezspAdapter.ts +27 -48
- package/src/adapter/ezsp/driver/index.ts +1 -1
- package/src/adapter/ezsp/driver/types/index.ts +99 -99
- package/src/adapter/serialPort.ts +9 -0
- package/src/adapter/z-stack/adapter/adapter-backup.ts +1 -1
- package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +1 -1
- package/src/adapter/z-stack/adapter/manager.ts +16 -2
- package/src/adapter/z-stack/adapter/tstype.ts +1 -0
- package/src/adapter/z-stack/adapter/zStackAdapter.ts +34 -81
- package/src/adapter/z-stack/constants/index.ts +1 -1
- package/src/adapter/z-stack/unpi/constants.ts +1 -1
- package/src/adapter/zboss/adapter/zbossAdapter.ts +23 -54
- package/src/adapter/zboss/driver.ts +8 -1
- package/src/adapter/zboss/uart.ts +14 -1
- package/src/adapter/zigate/adapter/zigateAdapter.ts +17 -48
- package/src/adapter/zoh/adapter/zohAdapter.ts +27 -50
- package/src/controller/controller.ts +12 -2
- package/src/controller/greenPower.ts +16 -9
- package/src/controller/helpers/ota.ts +37 -11
- package/src/controller/helpers/zclFrameConverter.ts +20 -17
- package/src/controller/model/device.ts +204 -97
- package/src/controller/model/endpoint.ts +36 -24
- package/src/controller/model/group.ts +14 -20
- package/src/controller/touchlink.ts +3 -3
- package/src/utils/timeService.ts +2 -2
- package/src/zspec/zcl/buffaloZcl.ts +226 -100
- package/src/zspec/zcl/definition/cluster.ts +2713 -2822
- package/src/zspec/zcl/definition/clusters-types.ts +80 -1135
- package/src/zspec/zcl/definition/enums.ts +0 -1
- package/src/zspec/zcl/definition/foundation.ts +703 -216
- package/src/zspec/zcl/definition/status.ts +22 -11
- package/src/zspec/zcl/definition/tstype.ts +59 -58
- package/src/zspec/zcl/utils.ts +137 -264
- package/src/zspec/zcl/zclFrame.ts +25 -130
- package/src/zspec/zcl/zclStatusError.ts +2 -2
- package/test/adapter/ember/emberAdapter.test.ts +191 -4
- package/test/adapter/ezsp/uart.test.ts +10 -10
- package/test/adapter/z-stack/adapter.test.ts +88 -32
- package/test/adapter/zoh/zohAdapter.test.ts +4 -4
- package/test/controller.test.ts +822 -248
- package/test/device-ota.test.ts +141 -16
- package/test/device.test.ts +731 -0
- package/test/requests.bench.ts +2 -0
- package/test/zcl.test.ts +70 -95
- package/test/zspec/zcl/buffalo.test.ts +251 -11
- package/test/zspec/zcl/foundation.test.ts +990 -0
- package/test/zspec/zcl/frame.test.ts +84 -69
- package/test/zspec/zcl/utils.test.ts +105 -81
- package/tsconfig.json +0 -1
- package/scripts/check-clusters-changes.ts +0 -328
- package/scripts/clusters-changes.log +0 -584
- package/scripts/utils.ts +0 -88
- package/scripts/zap-update-clusters-report.json +0 -303
- package/scripts/zap-update-clusters.ts +0 -1520
- package/scripts/zap-update-types.ts +0 -707
- package/scripts/zap-xml-clusters-overrides-data.ts +0 -52
- package/scripts/zap-xml-clusters-overrides.ts +0 -400
- package/scripts/zap-xml-types.ts +0 -146
|
@@ -2,7 +2,7 @@ import { Events as AdapterEvents } from '../../adapter';
|
|
|
2
2
|
import type { Eui64 } from "../../zspec/tstypes";
|
|
3
3
|
import * as Zcl from "../../zspec/zcl";
|
|
4
4
|
import type { TClusterCommandPayload, TPartialClusterAttributes } from "../../zspec/zcl/definition/clusters-types";
|
|
5
|
-
import type {
|
|
5
|
+
import type { Cluster, CustomClusters } from "../../zspec/zcl/definition/tstype";
|
|
6
6
|
import type { BindingTableEntry, LQITableEntry, RoutingTableEntry } from "../../zspec/zdo/definition/tstypes";
|
|
7
7
|
import type { ControllerEventMap } from "../controller";
|
|
8
8
|
import type { DeviceType, KeyValue, OtaDataSettings, OtaExtraMetas, OtaSource, OtaUpdateAvailableResult, ZigbeeOtaImageMeta } from "../tstype";
|
|
@@ -68,6 +68,7 @@ export declare class Device extends Entity<ControllerEventMap> {
|
|
|
68
68
|
get skipDefaultResponse(): boolean;
|
|
69
69
|
set skipDefaultResponse(skipDefaultResponse: boolean);
|
|
70
70
|
get customReadResponse(): CustomReadResponse | undefined;
|
|
71
|
+
/** If the set function returns true, the default read response behavior is skipped */
|
|
71
72
|
set customReadResponse(customReadResponse: CustomReadResponse | undefined);
|
|
72
73
|
get checkinInterval(): number | undefined;
|
|
73
74
|
set checkinInterval(checkinInterval: number | undefined);
|
|
@@ -80,10 +81,15 @@ export declare class Device extends Entity<ControllerEventMap> {
|
|
|
80
81
|
get otaInProgress(): boolean;
|
|
81
82
|
meta: KeyValue;
|
|
82
83
|
private static readonly devices;
|
|
83
|
-
private static loadedFromDatabase;
|
|
84
84
|
private static readonly deletedDevices;
|
|
85
85
|
private static readonly nwkToIeeeCache;
|
|
86
86
|
private constructor();
|
|
87
|
+
/**
|
|
88
|
+
* Reset transient data about the device.
|
|
89
|
+
* @param cache If true, reset some previously cached data.
|
|
90
|
+
* Should be set to true when device potentially changed its internal data to prevent mismatching state/config.
|
|
91
|
+
*/
|
|
92
|
+
resetTransient(cache: boolean): void;
|
|
87
93
|
createEndpoint(id: number): Endpoint;
|
|
88
94
|
changeIeeeAddress(ieeeAddr: string): void;
|
|
89
95
|
getEndpoint(id: number): Endpoint | undefined;
|
|
@@ -93,7 +99,7 @@ export declare class Device extends Entity<ControllerEventMap> {
|
|
|
93
99
|
updateLastSeen(): void;
|
|
94
100
|
private resetPendingRequestTimeout;
|
|
95
101
|
private hasPendingRequests;
|
|
96
|
-
onZclData(dataPayload: AdapterEvents.ZclPayload, frame: Zcl.Frame, endpoint: Endpoint): Promise<void>;
|
|
102
|
+
onZclData(dataPayload: AdapterEvents.ZclPayload, frame: Zcl.Frame, endpoint: Endpoint, defaultResponse: Zcl.Status | undefined): Promise<void>;
|
|
97
103
|
/**
|
|
98
104
|
* Reset runtime lookups.
|
|
99
105
|
*/
|
|
@@ -136,13 +142,17 @@ export declare class Device extends Entity<ControllerEventMap> {
|
|
|
136
142
|
*/
|
|
137
143
|
clearAllBindings(eui64List: Eui64[]): Promise<void>;
|
|
138
144
|
ping(disableRecovery?: boolean): Promise<void>;
|
|
139
|
-
addCustomCluster(name: string, cluster:
|
|
145
|
+
addCustomCluster(name: string, cluster: Cluster): void;
|
|
140
146
|
findMatchingOtaImage(source: OtaSource, current: TClusterCommandPayload<"genOta", "queryNextImageRequest">, extraMetas: OtaExtraMetas): Promise<ZigbeeOtaImageMeta | undefined>;
|
|
141
147
|
/**
|
|
142
148
|
* If `current` is undefined, will automatically notify and reply to query with `NO_IMAGE_AVAILABLE` (stops device from doing further requests).
|
|
143
149
|
*/
|
|
144
150
|
checkOta(source: OtaSource, current: TClusterCommandPayload<"genOta", "queryNextImageRequest"> | undefined, extraMetas: OtaExtraMetas, endpoint?: Endpoint | undefined): Promise<OtaUpdateAvailableResult>;
|
|
145
151
|
updateOta(source: Readonly<OtaSource> | undefined, requestPayload: TClusterCommandPayload<"genOta", "queryNextImageRequest"> | undefined, requestTsn: number | undefined, extraMetas: Readonly<OtaExtraMetas>, onProgress: (progress: number, remaining: number) => void, dataSettings: OtaDataSettings, endpoint?: Endpoint | undefined): Promise<[from: OtaUpdateAvailableResult["current"], to: OtaUpdateAvailableResult["current"] | undefined]>;
|
|
152
|
+
/**
|
|
153
|
+
* Abort running OTA if any. Send `ABORT` with next block response to device.
|
|
154
|
+
*/
|
|
155
|
+
abortOta(): void;
|
|
146
156
|
scheduleOta(source: OtaSource): void;
|
|
147
157
|
unscheduleOta(): void;
|
|
148
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../../src/controller/model/device.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,IAAI,aAAa,EAAC,MAAM,eAAe,CAAC;AAMtD,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAC;AACvC,OAAO,KAAK,EAAC,sBAAsB,
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../../src/controller/model/device.ts"],"names":[],"mappings":"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"}
|
|
@@ -61,6 +61,10 @@ const INTERVIEW_GENBASIC_ATTRIBUTES = [
|
|
|
61
61
|
"dateCode",
|
|
62
62
|
"swBuildId",
|
|
63
63
|
];
|
|
64
|
+
const GEN_BASIC_CLUSTER_ID = Zcl.Clusters.genBasic.ID;
|
|
65
|
+
const GEN_TIME_CLUSTER_ID = Zcl.Clusters.genTime.ID;
|
|
66
|
+
const GEN_POLL_CTRL_CLUSTER_ID = Zcl.Clusters.genPollCtrl.ID;
|
|
67
|
+
const GEN_OTA_CLUSTER_ID = Zcl.Clusters.genOta.ID;
|
|
64
68
|
var InterviewState;
|
|
65
69
|
(function (InterviewState) {
|
|
66
70
|
InterviewState["Pending"] = "PENDING";
|
|
@@ -90,6 +94,7 @@ class Device extends entity_1.default {
|
|
|
90
94
|
_gpSecurityKey;
|
|
91
95
|
#scheduledOta;
|
|
92
96
|
#otaInProgress = false;
|
|
97
|
+
#otaAbortController;
|
|
93
98
|
// Getters/setters
|
|
94
99
|
get ieeeAddr() {
|
|
95
100
|
return this._ieeeAddr;
|
|
@@ -209,6 +214,7 @@ class Device extends entity_1.default {
|
|
|
209
214
|
get customReadResponse() {
|
|
210
215
|
return this._customReadResponse;
|
|
211
216
|
}
|
|
217
|
+
/** If the set function returns true, the default read response behavior is skipped */
|
|
212
218
|
set customReadResponse(customReadResponse) {
|
|
213
219
|
this._customReadResponse = customReadResponse;
|
|
214
220
|
}
|
|
@@ -244,7 +250,6 @@ class Device extends entity_1.default {
|
|
|
244
250
|
// This lookup contains all devices that are queried from the database, this is to ensure that always
|
|
245
251
|
// the same instance is returned.
|
|
246
252
|
static devices = new Map();
|
|
247
|
-
static loadedFromDatabase = false;
|
|
248
253
|
static deletedDevices = new Map();
|
|
249
254
|
static nwkToIeeeCache = new Map();
|
|
250
255
|
constructor(databaseID, id, type, ieeeAddr, networkAddress, manufacturerID, endpoints, manufacturerName, powerSource, modelID, applicationVersion, stackVersion, zclVersion, hardwareVersion, dateCode, softwareBuildID, interviewState, meta, lastSeen, checkinInterval, pendingRequestTimeout, gpSecurityKey, scheduledOta) {
|
|
@@ -274,6 +279,19 @@ class Device extends entity_1.default {
|
|
|
274
279
|
this._gpSecurityKey = gpSecurityKey;
|
|
275
280
|
this.#scheduledOta = scheduledOta;
|
|
276
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Reset transient data about the device.
|
|
284
|
+
* @param cache If true, reset some previously cached data.
|
|
285
|
+
* Should be set to true when device potentially changed its internal data to prevent mismatching state/config.
|
|
286
|
+
*/
|
|
287
|
+
resetTransient(cache) {
|
|
288
|
+
this._lastDefaultResponseSequenceNumber = undefined;
|
|
289
|
+
if (cache) {
|
|
290
|
+
// force retrieving this data again
|
|
291
|
+
this._checkinInterval = undefined;
|
|
292
|
+
this._pendingRequestTimeout = 0;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
277
295
|
createEndpoint(id) {
|
|
278
296
|
if (this.getEndpoint(id)) {
|
|
279
297
|
throw new Error(`Device '${this.ieeeAddr}' already has an endpoint '${id}'`);
|
|
@@ -319,62 +337,115 @@ class Device extends entity_1.default {
|
|
|
319
337
|
hasPendingRequests() {
|
|
320
338
|
return this.endpoints.find((e) => e.hasPendingRequests()) !== undefined;
|
|
321
339
|
}
|
|
322
|
-
async onZclData(dataPayload, frame, endpoint) {
|
|
340
|
+
async onZclData(dataPayload, frame, endpoint, defaultResponse) {
|
|
323
341
|
if (!Device.devices.get(this.databaseID)?.has(this.ieeeAddr)) {
|
|
324
342
|
// prevent race conditions where device gets deleted during processing
|
|
325
343
|
return;
|
|
326
344
|
}
|
|
327
|
-
if (
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
345
|
+
if (this.type === "GreenPower") {
|
|
346
|
+
// nothing below applies
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const { header, command, cluster } = frame;
|
|
350
|
+
let sendDefaultResponse = !dataPayload.wasBroadcast && command.response === undefined;
|
|
351
|
+
let defaultResponseStatus = defaultResponse ?? Zcl.Status.SUCCESS;
|
|
352
|
+
if (header.isGlobal) {
|
|
353
|
+
// Response to read requests from device to coordinator
|
|
354
|
+
switch (command.name) {
|
|
355
|
+
case "read": {
|
|
356
|
+
// NOTE: `sendDefaultResponse` always false from `command.response === 0x01`
|
|
357
|
+
if (this._customReadResponse?.(frame, endpoint)) {
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
340
360
|
const response = {};
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
361
|
+
switch (dataPayload.clusterID) {
|
|
362
|
+
case GEN_TIME_CLUSTER_ID: {
|
|
363
|
+
// relax type to index by attr name, undefined results in non-success attr record
|
|
364
|
+
const timeAttrs = timeService.getTimeClusterAttributes();
|
|
365
|
+
for (const entry of frame.payload) {
|
|
366
|
+
// TODO: this.manufacturerID or frame.header.manufacturerCode
|
|
367
|
+
const name = Zcl.Utils.getClusterAttribute(cluster, entry.attrId, this.manufacturerID)?.name;
|
|
368
|
+
if (name === undefined) {
|
|
369
|
+
// UNSUPPORTED_ATTRIBUTE
|
|
370
|
+
response[entry.attrId] = { value: undefined, type: Zcl.DataType.NO_DATA };
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
response[name] = timeAttrs[name];
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
// NOTE: can add more clusters here to use defaults from spec as needed
|
|
379
|
+
case GEN_BASIC_CLUSTER_ID: {
|
|
380
|
+
for (const entry of frame.payload) {
|
|
381
|
+
// TODO: this.manufacturerID or frame.header.manufacturerCode
|
|
382
|
+
const attr = Zcl.Utils.getClusterAttribute(cluster, entry.attrId, this.manufacturerID);
|
|
383
|
+
if (attr?.default === undefined) {
|
|
384
|
+
// UNSUPPORTED_ATTRIBUTE
|
|
385
|
+
response[entry.attrId] = { value: undefined, type: Zcl.DataType.NO_DATA };
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
response[attr.name] = attr.default;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
default: {
|
|
394
|
+
for (const entry of frame.payload) {
|
|
395
|
+
// UNSUPPORTED_ATTRIBUTE
|
|
396
|
+
response[entry.attrId] = { value: undefined, type: Zcl.DataType.NO_DATA };
|
|
397
|
+
}
|
|
398
|
+
break;
|
|
345
399
|
}
|
|
346
400
|
}
|
|
347
401
|
try {
|
|
348
|
-
await endpoint.readResponse(
|
|
402
|
+
await endpoint.readResponse(cluster.ID, header.transactionSequenceNumber, response, {
|
|
349
403
|
srcEndpoint: dataPayload.destinationEndpoint,
|
|
350
404
|
});
|
|
351
405
|
}
|
|
352
406
|
catch (error) {
|
|
353
407
|
logger_1.logger.error(`Read response to ${this.ieeeAddr} failed (${error.message})`, NS);
|
|
408
|
+
// XXX: technically, if `readResponse` fails before reaching the network (internal to ZH), we should send a default response
|
|
409
|
+
// currently not possible due to implementation (no distinction as to "where" it failed)
|
|
354
410
|
}
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
case "defaultRsp": {
|
|
414
|
+
sendDefaultResponse = false; // per spec
|
|
415
|
+
break;
|
|
355
416
|
}
|
|
356
417
|
}
|
|
357
418
|
}
|
|
358
|
-
else if (
|
|
359
|
-
switch (
|
|
419
|
+
else if (header.isSpecific) {
|
|
420
|
+
switch (cluster.name) {
|
|
360
421
|
case "ssIasZone": {
|
|
361
|
-
if (
|
|
422
|
+
if (command.name === "enrollReq") {
|
|
362
423
|
// Respond to enroll requests
|
|
363
424
|
logger_1.logger.debug(`IAS - '${this.ieeeAddr}' responding to enroll response`, NS);
|
|
364
|
-
|
|
425
|
+
try {
|
|
426
|
+
await endpoint.command("ssIasZone", "enrollRsp", { enrollrspcode: 0, zoneid: 23 }, { transactionSequenceNumber: header.transactionSequenceNumber, disableDefaultResponse: true });
|
|
427
|
+
sendDefaultResponse = false; // per spec, sending a specific response TODO: no "Effect on receipt" in spec, is this correct?
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
logger_1.logger.error(`Handling of IAS zone enroll for ${this.ieeeAddr} failed (${error.message})`, NS);
|
|
431
|
+
defaultResponseStatus = Zcl.Status.FAILURE;
|
|
432
|
+
}
|
|
365
433
|
}
|
|
366
434
|
break;
|
|
367
435
|
}
|
|
368
436
|
case "genPollCtrl": {
|
|
369
|
-
if (
|
|
437
|
+
if (command.name === "checkin") {
|
|
438
|
+
let startedFastPolling = false;
|
|
370
439
|
// Handle check-in from sleeping end devices
|
|
371
440
|
try {
|
|
372
441
|
if (this.hasPendingRequests() || this._checkinInterval === undefined) {
|
|
373
442
|
logger_1.logger.debug(`check-in from ${this.ieeeAddr}: accepting fast-poll`, NS);
|
|
374
|
-
await endpoint.command(
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
443
|
+
await endpoint.command(cluster.name, "checkinRsp", { startFastPolling: 1, fastPollTimeout: 0 }, {
|
|
444
|
+
transactionSequenceNumber: header.transactionSequenceNumber,
|
|
445
|
+
disableDefaultResponse: true,
|
|
446
|
+
sendPolicy: "immediate",
|
|
447
|
+
});
|
|
448
|
+
startedFastPolling = true;
|
|
378
449
|
// This is a good time to read the checkin interval if we haven't stored it previously
|
|
379
450
|
if (this._checkinInterval === undefined) {
|
|
380
451
|
const pollPeriod = await endpoint.read("genPollCtrl", ["checkinInterval"], { sendPolicy: "immediate" });
|
|
@@ -383,21 +454,32 @@ class Device extends entity_1.default {
|
|
|
383
454
|
logger_1.logger.debug(`Request Queue (${this.ieeeAddr}): default expiration timeout set to ${this.pendingRequestTimeout}`, NS);
|
|
384
455
|
}
|
|
385
456
|
await Promise.all(this.endpoints.map(async (e) => await e.sendPendingRequests(true)));
|
|
386
|
-
// We *must* end fast-poll when we're done sending things. Otherwise
|
|
387
|
-
// we cause undue power-drain.
|
|
388
|
-
logger_1.logger.debug(`check-in from ${this.ieeeAddr}: stopping fast-poll`, NS);
|
|
389
|
-
await endpoint.command(frame.cluster.name, "fastPollStop", {}, { sendPolicy: "immediate" });
|
|
390
457
|
}
|
|
391
458
|
else {
|
|
392
459
|
logger_1.logger.debug(`check-in from ${this.ieeeAddr}: declining fast-poll`, NS);
|
|
393
|
-
await endpoint.command(
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
460
|
+
await endpoint.command(cluster.name, "checkinRsp", { startFastPolling: 0, fastPollTimeout: 0 }, {
|
|
461
|
+
transactionSequenceNumber: header.transactionSequenceNumber,
|
|
462
|
+
disableDefaultResponse: true,
|
|
463
|
+
sendPolicy: "immediate",
|
|
464
|
+
});
|
|
397
465
|
}
|
|
466
|
+
sendDefaultResponse = false; // per spec, sending a specific response
|
|
398
467
|
}
|
|
399
468
|
catch (error) {
|
|
400
469
|
logger_1.logger.error(`Handling of poll check-in from ${this.ieeeAddr} failed (${error.message})`, NS);
|
|
470
|
+
defaultResponseStatus = Zcl.Status.FAILURE;
|
|
471
|
+
}
|
|
472
|
+
finally {
|
|
473
|
+
if (startedFastPolling) {
|
|
474
|
+
// We *must* end fast-poll when we're done sending things. Otherwise we cause undue power-drain.
|
|
475
|
+
logger_1.logger.debug(`check-in from ${this.ieeeAddr}: stopping fast-poll`, NS);
|
|
476
|
+
try {
|
|
477
|
+
await endpoint.command(cluster.name, "fastPollStop", {}, { sendPolicy: "immediate" });
|
|
478
|
+
}
|
|
479
|
+
catch (error) {
|
|
480
|
+
logger_1.logger.error(`Failed to stop fast poll for ${this.ieeeAddr} (${error.message})`, NS);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
401
483
|
}
|
|
402
484
|
}
|
|
403
485
|
break;
|
|
@@ -405,34 +487,23 @@ class Device extends entity_1.default {
|
|
|
405
487
|
}
|
|
406
488
|
}
|
|
407
489
|
// Send a default response if necessary.
|
|
408
|
-
const isDefaultResponse = frame.header.isGlobal && frame.command.name === "defaultRsp";
|
|
409
|
-
const commandHasResponse = frame.command.response !== undefined;
|
|
410
|
-
const disableDefaultResponse = frame.header.frameControl.disableDefaultResponse;
|
|
411
490
|
/* v8 ignore next */
|
|
412
491
|
const disableTuyaDefaultResponse = this.manufacturerName?.startsWith("_TZ") && process.env.DISABLE_TUYA_DEFAULT_RESPONSE;
|
|
413
492
|
// Sometimes messages are received twice, prevent responding twice
|
|
414
|
-
const alreadyResponded = this._lastDefaultResponseSequenceNumber ===
|
|
415
|
-
if (this.
|
|
416
|
-
|
|
417
|
-
!disableDefaultResponse &&
|
|
418
|
-
!isDefaultResponse &&
|
|
419
|
-
!commandHasResponse &&
|
|
420
|
-
!this._skipDefaultResponse &&
|
|
493
|
+
const alreadyResponded = this._lastDefaultResponseSequenceNumber === header.transactionSequenceNumber;
|
|
494
|
+
if (!this._skipDefaultResponse &&
|
|
495
|
+
sendDefaultResponse &&
|
|
496
|
+
(!header.frameControl.disableDefaultResponse || defaultResponseStatus !== Zcl.Status.SUCCESS) &&
|
|
421
497
|
!alreadyResponded &&
|
|
422
498
|
!disableTuyaDefaultResponse) {
|
|
423
499
|
try {
|
|
424
|
-
this._lastDefaultResponseSequenceNumber =
|
|
425
|
-
|
|
426
|
-
// In https://github.com/Koenkk/zigbee2mqtt/issues/18096 a commandResponse (SERVER_TO_CLIENT)
|
|
427
|
-
// is send and the device expects a CLIENT_TO_SERVER back.
|
|
428
|
-
// Previously SERVER_TO_CLIENT was always used.
|
|
429
|
-
// Therefore for non-global commands we inverse the direction.
|
|
430
|
-
const direction = frame.header.isGlobal
|
|
500
|
+
this._lastDefaultResponseSequenceNumber = header.transactionSequenceNumber;
|
|
501
|
+
const direction = header.frameControl.direction === Zcl.Direction.CLIENT_TO_SERVER
|
|
431
502
|
? Zcl.Direction.SERVER_TO_CLIENT
|
|
432
|
-
:
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
503
|
+
: Zcl.Direction.CLIENT_TO_SERVER;
|
|
504
|
+
await endpoint.defaultResponse(command.ID, defaultResponseStatus, cluster.ID, header.transactionSequenceNumber, {
|
|
505
|
+
direction,
|
|
506
|
+
});
|
|
436
507
|
}
|
|
437
508
|
catch (error) {
|
|
438
509
|
logger_1.logger.debug(`Default response to ${this.ieeeAddr} failed (${error})`, NS);
|
|
@@ -447,7 +518,6 @@ class Device extends entity_1.default {
|
|
|
447
518
|
*/
|
|
448
519
|
static resetCache() {
|
|
449
520
|
Device.devices.clear();
|
|
450
|
-
Device.loadedFromDatabase = false;
|
|
451
521
|
Device.deletedDevices.clear();
|
|
452
522
|
Device.nwkToIeeeCache.clear();
|
|
453
523
|
}
|
|
@@ -464,7 +534,7 @@ class Device extends entity_1.default {
|
|
|
464
534
|
}
|
|
465
535
|
// default: no timeout (messages expire immediately after first send attempt)
|
|
466
536
|
let pendingRequestTimeout = 0;
|
|
467
|
-
if (endpoints.filter((e) => e.inputClusters.includes(
|
|
537
|
+
if (endpoints.filter((e) => e.inputClusters.includes(GEN_POLL_CTRL_CLUSTER_ID)).length > 0) {
|
|
468
538
|
// default for devices that support genPollCtrl cluster (RX off when idle): 1 day
|
|
469
539
|
pendingRequestTimeout = 86400000;
|
|
470
540
|
}
|
|
@@ -518,22 +588,19 @@ class Device extends entity_1.default {
|
|
|
518
588
|
entity_1.default.getDatabaseByID(this.databaseID)?.update(this.toDatabaseEntry(), writeDatabase);
|
|
519
589
|
}
|
|
520
590
|
static loadFromDatabaseIfNecessary() {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
Device.nwkToIeeeCache.get(database.id).set(device.networkAddress, device.ieeeAddr);
|
|
532
|
-
}
|
|
591
|
+
entity_1.default.databases.forEach(database => {
|
|
592
|
+
if (!Device.devices.has(database.id)) {
|
|
593
|
+
Device.devices.set(database.id, new Map());
|
|
594
|
+
Device.deletedDevices.set(database.id, new Map());
|
|
595
|
+
Device.nwkToIeeeCache.set(database.id, new Map());
|
|
596
|
+
const entries = database.getEntriesIterator(['Coordinator', 'EndDevice', 'Router', 'GreenPower', 'Unknown']);
|
|
597
|
+
for (const entry of entries) {
|
|
598
|
+
const device = Device.fromDatabaseEntry(entry, database.id);
|
|
599
|
+
Device.devices.get(database.id).set(device.ieeeAddr, device);
|
|
600
|
+
Device.nwkToIeeeCache.get(database.id).set(device.networkAddress, device.ieeeAddr);
|
|
533
601
|
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
}
|
|
602
|
+
}
|
|
603
|
+
});
|
|
537
604
|
}
|
|
538
605
|
static find(databaseID, ieeeOrNwkAddress, includeDeleted = false) {
|
|
539
606
|
return typeof ieeeOrNwkAddress === "string"
|
|
@@ -1102,31 +1169,35 @@ class Device extends entity_1.default {
|
|
|
1102
1169
|
// Zigbee does not have an official pinging mechanism. Use a read request
|
|
1103
1170
|
// of a mandatory basic cluster attribute to keep it as lightweight as
|
|
1104
1171
|
// possible.
|
|
1105
|
-
const endpoint = this.endpoints.find((ep) => ep.inputClusters.includes(
|
|
1172
|
+
const endpoint = this.endpoints.find((ep) => ep.inputClusters.includes(GEN_BASIC_CLUSTER_ID)) ?? this.endpoints[0];
|
|
1106
1173
|
await endpoint.read("genBasic", ["zclVersion"], { disableRecovery, sendPolicy: "immediate" });
|
|
1107
1174
|
}
|
|
1108
1175
|
addCustomCluster(name, cluster) {
|
|
1109
|
-
(0, node_assert_1.default)(
|
|
1176
|
+
(0, node_assert_1.default)(cluster.ID !== Zcl.Clusters.touchlink.ID && cluster.ID !== Zcl.Clusters.greenPower.ID, "Overriding of greenPower or touchlink cluster is not supported");
|
|
1110
1177
|
if (Zcl.Utils.isClusterName(name)) {
|
|
1111
|
-
const existingCluster = this._customClusters[name] ?? Zcl.Clusters[name];
|
|
1112
1178
|
// Extend existing cluster
|
|
1179
|
+
const existingCluster = this._customClusters[name] ?? Zcl.Clusters[name];
|
|
1113
1180
|
(0, node_assert_1.default)(existingCluster.ID === cluster.ID, `Custom cluster ID (${cluster.ID}) should match existing cluster ID (${existingCluster.ID})`);
|
|
1114
|
-
|
|
1181
|
+
const extendedCluster = {
|
|
1182
|
+
name: cluster.name,
|
|
1115
1183
|
ID: cluster.ID,
|
|
1116
1184
|
manufacturerCode: cluster.manufacturerCode,
|
|
1117
1185
|
attributes: { ...existingCluster.attributes, ...cluster.attributes },
|
|
1118
1186
|
commands: { ...existingCluster.commands, ...cluster.commands },
|
|
1119
1187
|
commandsResponse: { ...existingCluster.commandsResponse, ...cluster.commandsResponse },
|
|
1120
1188
|
};
|
|
1189
|
+
this._customClusters[name] = extendedCluster;
|
|
1190
|
+
}
|
|
1191
|
+
else {
|
|
1192
|
+
this._customClusters[name] = cluster;
|
|
1121
1193
|
}
|
|
1122
|
-
this._customClusters[name] = cluster;
|
|
1123
1194
|
}
|
|
1124
|
-
#waitForOtaCommand(endpointId, commandId,
|
|
1195
|
+
#waitForOtaCommand(endpointId, commandId, defaultRspCommandId, timeout) {
|
|
1125
1196
|
const adapter = entity_1.default.getAdapterByID(this.databaseID);
|
|
1126
1197
|
if (!adapter) {
|
|
1127
1198
|
throw new Error(`No adapter found for database ID ${this.databaseID}`);
|
|
1128
1199
|
}
|
|
1129
|
-
const waiter = adapter.waitFor(this.networkAddress, endpointId, Zcl.FrameType.SPECIFIC, Zcl.Direction.CLIENT_TO_SERVER,
|
|
1200
|
+
const waiter = adapter.waitFor(this.networkAddress, endpointId, Zcl.FrameType.SPECIFIC, Zcl.Direction.CLIENT_TO_SERVER, undefined, GEN_OTA_CLUSTER_ID, commandId, defaultRspCommandId, timeout);
|
|
1130
1201
|
const promise = new Promise((resolve, reject) => {
|
|
1131
1202
|
waiter.promise.then((payload) => {
|
|
1132
1203
|
try {
|
|
@@ -1168,10 +1239,11 @@ class Device extends entity_1.default {
|
|
|
1168
1239
|
}
|
|
1169
1240
|
async #notifyOta(endpoint) {
|
|
1170
1241
|
// Some devices (e.g. Insta) take a very long trying to discover the correct coordinator EP for OTA
|
|
1171
|
-
const queryNextImageRequest = this.#waitForOtaCommand(endpoint.ID, Zcl.Clusters.genOta.commands.queryNextImageRequest.ID,
|
|
1242
|
+
const queryNextImageRequest = this.#waitForOtaCommand(endpoint.ID, Zcl.Clusters.genOta.commands.queryNextImageRequest.ID, Zcl.Clusters.genOta.commandsResponse.imageNotify.ID, 60000);
|
|
1172
1243
|
try {
|
|
1173
1244
|
await endpoint.commandResponse("genOta", "imageNotify", { payloadType: 0, queryJitter: 100 }, { sendPolicy: "immediate" });
|
|
1174
1245
|
const response = await queryNextImageRequest.promise;
|
|
1246
|
+
(0, node_assert_1.default)(response.header.isSpecific);
|
|
1175
1247
|
return [response.payload, response.header.transactionSequenceNumber];
|
|
1176
1248
|
}
|
|
1177
1249
|
catch {
|
|
@@ -1309,10 +1381,14 @@ class Device extends entity_1.default {
|
|
|
1309
1381
|
const session = new ota_1.OtaSession(this.ieeeAddr, endpoint, image, onProgress, dataSettings, this.#waitForOtaCommand.bind(this));
|
|
1310
1382
|
let endResult;
|
|
1311
1383
|
try {
|
|
1312
|
-
|
|
1384
|
+
this.#otaAbortController = new AbortController();
|
|
1385
|
+
const runEnd = await session.run(this.#otaAbortController.signal);
|
|
1386
|
+
(0, node_assert_1.default)(runEnd.header.isSpecific);
|
|
1387
|
+
endResult = runEnd;
|
|
1313
1388
|
}
|
|
1314
1389
|
finally {
|
|
1315
1390
|
this.#otaInProgress = false;
|
|
1391
|
+
this.#otaAbortController = undefined;
|
|
1316
1392
|
}
|
|
1317
1393
|
logger_1.logger.debug(() => `Received upgrade end request for ${this.ieeeAddr}: ${JSON.stringify(endResult.payload)}`, NS);
|
|
1318
1394
|
if (endResult.payload.status === Zcl.Status.SUCCESS) {
|
|
@@ -1367,7 +1443,7 @@ class Device extends entity_1.default {
|
|
|
1367
1443
|
* response command with status of success and it SHALL wait for the client to reinitiate the upgrade process.
|
|
1368
1444
|
*/
|
|
1369
1445
|
try {
|
|
1370
|
-
await endpoint.defaultResponse(Zcl.Clusters.genOta.commands.upgradeEndRequest.ID, Zcl.Status.SUCCESS,
|
|
1446
|
+
await endpoint.defaultResponse(Zcl.Clusters.genOta.commands.upgradeEndRequest.ID, Zcl.Status.SUCCESS, GEN_OTA_CLUSTER_ID, endResult.header.transactionSequenceNumber);
|
|
1371
1447
|
}
|
|
1372
1448
|
catch (error) {
|
|
1373
1449
|
logger_1.logger.debug(() => `OTA upgrade end request default response for ${this.ieeeAddr} failed: ${error.message}`, NS);
|
|
@@ -1376,6 +1452,12 @@ class Device extends entity_1.default {
|
|
|
1376
1452
|
throw new Error(`OTA update of ${this.ieeeAddr} failed with reason: ${Zcl.Status[endResult.payload.status]}`);
|
|
1377
1453
|
}
|
|
1378
1454
|
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Abort running OTA if any. Send `ABORT` with next block response to device.
|
|
1457
|
+
*/
|
|
1458
|
+
abortOta() {
|
|
1459
|
+
this.#otaAbortController?.abort();
|
|
1460
|
+
}
|
|
1379
1461
|
scheduleOta(source) {
|
|
1380
1462
|
(0, node_assert_1.default)(this.endpoints.some((e) => e.supportsOutputCluster("genOta")), `No endpoint found with OTA cluster support for ${this.ieeeAddr}`);
|
|
1381
1463
|
if (this.#scheduledOta) {
|