zigbee-clusters 2.4.1 → 2.5.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/index.d.ts +8 -0
- package/lib/Endpoint.js +69 -48
- package/package.json +3 -1
package/index.d.ts
CHANGED
|
@@ -173,6 +173,12 @@ interface ZCLNodeCluster extends EventEmitter {
|
|
|
173
173
|
discoverAttributesExtended(): Promise<any[]>;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
interface BasicCluster extends ZCLNodeCluster {
|
|
177
|
+
factoryReset(): Promise<void>;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
interface PowerConfigurationCluster extends ZCLNodeCluster {}
|
|
181
|
+
|
|
176
182
|
interface OnOffCluster extends ZCLNodeCluster {
|
|
177
183
|
setOn(): Promise<void>;
|
|
178
184
|
setOff(): Promise<void>;
|
|
@@ -309,7 +315,9 @@ declare module "zigbee-clusters" {
|
|
|
309
315
|
[key: string]: { ID: number; NAME: string; ATTRIBUTES: any; COMMANDS: any };
|
|
310
316
|
};
|
|
311
317
|
export var ZCLNodeCluster;
|
|
318
|
+
export var BasicCluster;
|
|
312
319
|
export var OnOffCluster;
|
|
313
320
|
export var LevelControlCluster;
|
|
314
321
|
export var ColorControlCluster;
|
|
322
|
+
export var PowerConfigurationCluster;
|
|
315
323
|
}
|
package/lib/Endpoint.js
CHANGED
|
@@ -104,43 +104,51 @@ class Endpoint extends EventEmitter {
|
|
|
104
104
|
*/
|
|
105
105
|
async handleFrame(clusterId, frame, meta) {
|
|
106
106
|
const rawFrame = frame;
|
|
107
|
+
frame = Endpoint.parseFrame(frame);
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
} else frame = ZCLStandardHeader.fromBuffer(rawFrame);
|
|
111
|
-
|
|
112
|
-
// NOTE: we do not respond with a default response if:
|
|
113
|
-
// 1. The frame we received is a default response (frame.cmdId = 11)
|
|
114
|
-
// 2. Another command is sent in response to the received frame
|
|
115
|
-
// 3. The frame has the disableDefaultResponse flag set
|
|
116
|
-
// See ZCL specification 2.5.12.2.
|
|
117
|
-
const response = (
|
|
118
|
-
frame.frameControl.disableDefaultResponse
|
|
119
|
-
|| (meta && meta.groupId)
|
|
120
|
-
|| frame.cmdId === 11
|
|
121
|
-
) ? null : this._makeErrorResponse(frame);
|
|
122
|
-
|
|
109
|
+
let clusterSpecificResponse = null;
|
|
110
|
+
let clusterSpecificError = null;
|
|
123
111
|
try {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
response.data = data.toBuffer();
|
|
129
|
-
response.cmdId = cmdId;
|
|
130
|
-
} else {
|
|
131
|
-
// Set status to success
|
|
132
|
-
response.data[1] = 0;
|
|
133
|
-
}
|
|
134
|
-
} catch (e) {
|
|
135
|
-
debug(`${this.getLogId(clusterId)}, error while handling frame`, e.message, { meta, frame });
|
|
112
|
+
clusterSpecificResponse = await this.handleZCLFrame(clusterId, frame, meta, rawFrame);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
clusterSpecificError = err;
|
|
115
|
+
debug(`${this.getLogId(clusterId)}, error while handling frame`, err.message, { meta, frame });
|
|
136
116
|
}
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
117
|
+
|
|
118
|
+
// Don't respond to this frame if it is a default response or a group cast (ZCL spec 2.5.12.2)
|
|
119
|
+
if (frame.cmdId === 11 || (meta && typeof meta.groupId === 'number')) return;
|
|
120
|
+
|
|
121
|
+
// If cluster specific error, respond with a default response error frame
|
|
122
|
+
if (clusterSpecificError) {
|
|
123
|
+
const defaultResponseErrorFrame = this.makeDefaultResponseFrame(frame, false);
|
|
124
|
+
this.sendFrame(clusterId, defaultResponseErrorFrame.toBuffer()).catch(err => {
|
|
125
|
+
debug(`${this.getLogId(clusterId)}, error while sending default error response`, err, { response: defaultResponseErrorFrame });
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// No further handling for this frame
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Create response frame and set status to success
|
|
133
|
+
const responseFrame = this.makeDefaultResponseFrame(frame, true);
|
|
134
|
+
|
|
135
|
+
// If a cluster specific response was generated, set the response data
|
|
136
|
+
// and cmdId in the response frame.
|
|
137
|
+
if (clusterSpecificResponse) {
|
|
138
|
+
const [cmdId, data] = clusterSpecificResponse;
|
|
139
|
+
responseFrame.data = data.toBuffer();
|
|
140
|
+
responseFrame.cmdId = cmdId;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// If there was no cluster specific response and the default response is disabled, don't
|
|
144
|
+
// send a response.
|
|
145
|
+
if (!clusterSpecificResponse && frame.frameControl.disableDefaultResponse) return;
|
|
146
|
+
|
|
147
|
+
// Send either cluster specific, or default response frame
|
|
148
|
+
try {
|
|
149
|
+
await this.sendFrame(clusterId, responseFrame.toBuffer());
|
|
150
|
+
} catch (err) {
|
|
151
|
+
debug(`${this.getLogId(clusterId)}, error while sending cluster specific or default success response`, err, { response: responseFrame });
|
|
144
152
|
}
|
|
145
153
|
}
|
|
146
154
|
|
|
@@ -173,25 +181,38 @@ class Endpoint extends EventEmitter {
|
|
|
173
181
|
return response;
|
|
174
182
|
}
|
|
175
183
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Returns a default response frame with an error status code.
|
|
186
|
+
* @param {*} receivedFrame
|
|
187
|
+
* @param {boolean} success
|
|
188
|
+
* @returns {ZCLStandardHeader|ZCLMfgSpecificHeader}
|
|
189
|
+
*/
|
|
190
|
+
makeDefaultResponseFrame(receivedFrame, success) {
|
|
191
|
+
let responseFrame;
|
|
192
|
+
if (receivedFrame instanceof ZCLStandardHeader) {
|
|
193
|
+
responseFrame = new ZCLStandardHeader();
|
|
180
194
|
} else {
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
responseFrame = new ZCLMfgSpecificHeader();
|
|
196
|
+
responseFrame.manufacturerId = receivedFrame.manufacturerId;
|
|
183
197
|
}
|
|
184
198
|
// TODO: flip proper bits
|
|
185
|
-
|
|
199
|
+
responseFrame.frameControl = receivedFrame.frameControl.copy();
|
|
200
|
+
|
|
201
|
+
responseFrame.frameControl.disableDefaultResponse = true;
|
|
202
|
+
responseFrame.frameControl.clusterSpecific = false;
|
|
203
|
+
responseFrame.frameControl.directionToClient = !receivedFrame.frameControl.directionToClient;
|
|
186
204
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
205
|
+
responseFrame.trxSequenceNumber = receivedFrame.trxSequenceNumber;
|
|
206
|
+
responseFrame.cmdId = 0x0B;
|
|
207
|
+
responseFrame.data = Buffer.from([receivedFrame.cmdId, success ? 0 : 1]);
|
|
208
|
+
return responseFrame;
|
|
209
|
+
}
|
|
190
210
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
211
|
+
static parseFrame(frame) {
|
|
212
|
+
if (frame[0] & 0x4) {
|
|
213
|
+
return ZCLMfgSpecificHeader.fromBuffer(frame);
|
|
214
|
+
}
|
|
215
|
+
return ZCLStandardHeader.fromBuffer(frame);
|
|
195
216
|
}
|
|
196
217
|
|
|
197
218
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zigbee-clusters",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "Zigbee Cluster Library for Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"homepage": "https://github.com/athombv/node-zigbee-clusters#readme",
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@athombv/jsdoc-template": "^1.6.1",
|
|
35
|
+
"@types/sinon": "^17.0.3",
|
|
35
36
|
"concurrently": "^5.2.0",
|
|
36
37
|
"eslint": "^6.8.0",
|
|
37
38
|
"eslint-config-athom": "^2.1.0",
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
"jsdoc-ts-utils": "^2.0.0",
|
|
40
41
|
"mocha": "^10.1.0",
|
|
41
42
|
"serve": "^14.0.1",
|
|
43
|
+
"sinon": "^19.0.2",
|
|
42
44
|
"watch": "^1.0.2"
|
|
43
45
|
},
|
|
44
46
|
"dependencies": {
|