zigbee-clusters 2.8.1 → 2.9.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 +730 -150
- package/index.js +5 -0
- package/lib/constants.js +97 -0
- package/package.json +1 -1
- package/scripts/generate-types.js +120 -19
package/index.js
CHANGED
|
@@ -44,6 +44,8 @@ const {
|
|
|
44
44
|
ZCLStruct,
|
|
45
45
|
} = zclTypes;
|
|
46
46
|
|
|
47
|
+
const { ZIGBEE_PROFILE_ID, ZIGBEE_DEVICE_ID, IAS_ZONE_TYPE } = require('./lib/constants');
|
|
48
|
+
|
|
47
49
|
module.exports = {
|
|
48
50
|
Cluster,
|
|
49
51
|
BoundCluster,
|
|
@@ -55,4 +57,7 @@ module.exports = {
|
|
|
55
57
|
ZCLStruct,
|
|
56
58
|
...Clusters,
|
|
57
59
|
debug,
|
|
60
|
+
ZIGBEE_PROFILE_ID,
|
|
61
|
+
ZIGBEE_DEVICE_ID,
|
|
62
|
+
IAS_ZONE_TYPE,
|
|
58
63
|
};
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zigbee Profile IDs from the ZCL specification.
|
|
5
|
+
*/
|
|
6
|
+
const ZIGBEE_PROFILE_ID = {
|
|
7
|
+
INDUSTRIAL_PLANT_MONITORING: 0x0101,
|
|
8
|
+
HOME_AUTOMATION: 0x0104,
|
|
9
|
+
COMMERCIAL_BUILDING_AUTOMATION: 0x0105,
|
|
10
|
+
TELECOM_APPLICATIONS: 0x0107,
|
|
11
|
+
PERSONAL_HOME_AND_HOSPITAL_CARE: 0x0108,
|
|
12
|
+
ADVANCED_METERING_INITIATIVE: 0x0109,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Zigbee Device IDs from the ZCL specification.
|
|
17
|
+
*/
|
|
18
|
+
const ZIGBEE_DEVICE_ID = {
|
|
19
|
+
GENERIC: {
|
|
20
|
+
ON_OFF_SWITCH: 0x0000,
|
|
21
|
+
LEVEL_CONTROL_SWITCH: 0x0001,
|
|
22
|
+
ON_OFF_OUTPUT: 0x0002,
|
|
23
|
+
LEVEL_CONTROLLABLE_OUTPUT: 0x0003,
|
|
24
|
+
SCENE_SELECTOR: 0x0004,
|
|
25
|
+
CONFIGURATION_TOOL: 0x0005,
|
|
26
|
+
REMOTE_CONTROL: 0x0006,
|
|
27
|
+
COMBINED_INTERFACE: 0x0007,
|
|
28
|
+
RANGE_EXTENDER: 0x0008,
|
|
29
|
+
MAINS_POWER_OUTLET: 0x0009,
|
|
30
|
+
DOOR_LOCK: 0x000a,
|
|
31
|
+
DOOR_LOCK_CONTROLLER: 0x000b,
|
|
32
|
+
SIMPLE_SENSOR: 0x000c,
|
|
33
|
+
CONSUMPTION_AWARENESS_DEVICE: 0x000d,
|
|
34
|
+
HOME_GATEWAY: 0x0050,
|
|
35
|
+
SMART_PLUG: 0x0051,
|
|
36
|
+
WHITE_GOODS: 0x0052,
|
|
37
|
+
METER_INTERFACE: 0x0053,
|
|
38
|
+
},
|
|
39
|
+
LIGHTING: {
|
|
40
|
+
ON_OFF_LIGHT: 0x0100,
|
|
41
|
+
DIMMABLE_LIGHT: 0x0101,
|
|
42
|
+
COLOR_DIMMABLE_LIGHT: 0x0102,
|
|
43
|
+
ON_OFF_LIGHT_SWITCH: 0x0103,
|
|
44
|
+
DIMMER_SWITCH: 0x0104,
|
|
45
|
+
COLOR_DIMMER_SWITCH: 0x0105,
|
|
46
|
+
LIGHT_SENSOR: 0x0106,
|
|
47
|
+
OCCUPANCY_SENSOR: 0x0107,
|
|
48
|
+
},
|
|
49
|
+
CLOSURES: {
|
|
50
|
+
SHADE: 0x0200,
|
|
51
|
+
SHADE_CONTROLLER: 0x0201,
|
|
52
|
+
WINDOW_COVERING_DEVICE: 0x0202,
|
|
53
|
+
WINDOW_COVERING_CONTROLLER: 0x0203,
|
|
54
|
+
},
|
|
55
|
+
HVAC: {
|
|
56
|
+
HEATING_COOLING_UNIT: 0x0300,
|
|
57
|
+
THERMOSTAT: 0x0301,
|
|
58
|
+
TEMPERATURE_SENSOR: 0x0302,
|
|
59
|
+
PUMP: 0x0303,
|
|
60
|
+
PUMP_CONTROLLER: 0x0304,
|
|
61
|
+
PRESSURE_SENSOR: 0x0305,
|
|
62
|
+
FLOW_SENSOR: 0x0306,
|
|
63
|
+
},
|
|
64
|
+
INTRUDER_ALARM_SYSTEMS: {
|
|
65
|
+
IAS_CONTROL_INDICATING_EQUIPMENT: 0x0400,
|
|
66
|
+
IAS_ANCILLARY_CONTROL_EQUIPMENT: 0x0401,
|
|
67
|
+
IAS_ZONE: 0x0402,
|
|
68
|
+
IAS_WARNING_DEVICE: 0x0403,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* IAS Zone Type values from the ZCL specification (IAS Zone cluster, zoneType attribute).
|
|
74
|
+
*/
|
|
75
|
+
const IAS_ZONE_TYPE = {
|
|
76
|
+
STANDARD_CIE: 0x0000,
|
|
77
|
+
MOTION_SENSOR: 0x000d,
|
|
78
|
+
CONTACT_SWITCH: 0x0015,
|
|
79
|
+
FIRE_SENSOR: 0x0028,
|
|
80
|
+
WATER_SENSOR: 0x002a,
|
|
81
|
+
CARBON_MONOXIDE_SENSOR: 0x002b,
|
|
82
|
+
PERSONAL_EMERGENCY_DEVICE: 0x002c,
|
|
83
|
+
VIBRATION_MOVEMENT_SENSOR: 0x002d,
|
|
84
|
+
REMOTE_CONTROL: 0x010f,
|
|
85
|
+
KEY_FOB: 0x0115,
|
|
86
|
+
KEYPAD: 0x021d,
|
|
87
|
+
STANDARD_WARNING_DEVICE: 0x0225,
|
|
88
|
+
GLASS_BREAK_SENSOR: 0x0226,
|
|
89
|
+
SECURITY_REPEATER: 0x0229,
|
|
90
|
+
INVALID_ZONE_TYPE: 0xffff,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
module.exports = {
|
|
94
|
+
ZIGBEE_PROFILE_ID,
|
|
95
|
+
ZIGBEE_DEVICE_ID,
|
|
96
|
+
IAS_ZONE_TYPE,
|
|
97
|
+
};
|
package/package.json
CHANGED
|
@@ -179,6 +179,8 @@ function generateClusterInterface(cluster) {
|
|
|
179
179
|
lines.push(` readAttributes<K extends ${attrNames}>(attributeNames: K[], opts?: { timeout?: number }): Promise<Pick<${interfaceName}Attributes, K>>;`);
|
|
180
180
|
lines.push(` readAttributes(attributeNames: Array<keyof ${interfaceName}Attributes | number>, opts?: { timeout?: number }): Promise<Partial<${interfaceName}Attributes> & Record<number, unknown>>;`);
|
|
181
181
|
lines.push(` writeAttributes(attributes: Partial<${interfaceName}Attributes>, opts?: { timeout?: number }): Promise<unknown>;`);
|
|
182
|
+
lines.push(` on<K extends keyof ${interfaceName}Attributes & string>(eventName: \`attr.\${K}\`, listener: (value: ${interfaceName}Attributes[K]) => void): this;`);
|
|
183
|
+
lines.push(` once<K extends keyof ${interfaceName}Attributes & string>(eventName: \`attr.\${K}\`, listener: (value: ${interfaceName}Attributes[K]) => void): this;`);
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
// Add command methods
|
|
@@ -208,9 +210,29 @@ function generateClusterInterface(cluster) {
|
|
|
208
210
|
/**
|
|
209
211
|
* Generate the full index.d.ts file
|
|
210
212
|
* @param {object[]} clusters - Array of parsed cluster definitions
|
|
213
|
+
* @param {Array<{
|
|
214
|
+
* constantName: string;
|
|
215
|
+
* clusterId: number;
|
|
216
|
+
* clusterName: string;
|
|
217
|
+
* }>} clusterDefinitions - Array of CLUSTER definitions used to generate typed CLUSTER exports
|
|
211
218
|
* @returns {string} Complete TypeScript definitions file
|
|
212
219
|
*/
|
|
213
|
-
function
|
|
220
|
+
function generateConstantObject(obj, indent = 2) {
|
|
221
|
+
const lines = [];
|
|
222
|
+
const pad = ' '.repeat(indent);
|
|
223
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
224
|
+
if (typeof value === 'object' && value !== null) {
|
|
225
|
+
lines.push(`${pad}${key}: {`);
|
|
226
|
+
lines.push(generateConstantObject(value, indent + 2));
|
|
227
|
+
lines.push(`${pad}};`);
|
|
228
|
+
} else {
|
|
229
|
+
lines.push(`${pad}${key}: ${typeof value === 'number' ? value : JSON.stringify(value)};`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return lines.join('\n');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function generateTypesFile(clusters, clusterDefinitions, constants) {
|
|
214
236
|
const lines = [];
|
|
215
237
|
|
|
216
238
|
// Header
|
|
@@ -309,6 +331,42 @@ type ZCLNodeConstructorInput = {
|
|
|
309
331
|
lines.push('}');
|
|
310
332
|
lines.push('');
|
|
311
333
|
|
|
334
|
+
// Generate cluster type lookup maps for inference helpers
|
|
335
|
+
lines.push('/** Cluster type lookup by cluster NAME */');
|
|
336
|
+
lines.push('export interface ClusterTypeByName {');
|
|
337
|
+
for (const cluster of clusters) {
|
|
338
|
+
const interfaceName = toInterfaceName(cluster);
|
|
339
|
+
lines.push(` ${cluster.clusterName}: ${interfaceName};`);
|
|
340
|
+
}
|
|
341
|
+
lines.push('}');
|
|
342
|
+
lines.push('');
|
|
343
|
+
|
|
344
|
+
// Generate cluster attribute lookup maps for inference helpers
|
|
345
|
+
lines.push('/** Cluster attributes lookup by cluster NAME */');
|
|
346
|
+
lines.push('export interface ClusterAttributesByName {');
|
|
347
|
+
for (const cluster of clusters) {
|
|
348
|
+
const interfaceName = toInterfaceName(cluster);
|
|
349
|
+
const attributesInterfaceName = `${interfaceName}Attributes`;
|
|
350
|
+
const attributesType = cluster.attributes.length > 0 ? attributesInterfaceName : 'Record<string, unknown>';
|
|
351
|
+
lines.push(` ${cluster.clusterName}: ${attributesType};`);
|
|
352
|
+
}
|
|
353
|
+
lines.push('}');
|
|
354
|
+
lines.push('');
|
|
355
|
+
|
|
356
|
+
lines.push('/** Infer a typed cluster interface from a CLUSTER definition object. */');
|
|
357
|
+
lines.push('export type ClusterTypeFromDefinition<TDef extends { NAME: string; ID: number }> =');
|
|
358
|
+
lines.push(" TDef['NAME'] extends keyof ClusterTypeByName");
|
|
359
|
+
lines.push(" ? ClusterTypeByName[TDef['NAME']]");
|
|
360
|
+
lines.push(' : ZCLNodeCluster;');
|
|
361
|
+
lines.push('');
|
|
362
|
+
|
|
363
|
+
lines.push('/** Infer typed cluster attribute map from a CLUSTER definition object. */');
|
|
364
|
+
lines.push('export type ClusterAttributesFromDefinition<TDef extends { NAME: string; ID: number }> =');
|
|
365
|
+
lines.push(" TDef['NAME'] extends keyof ClusterAttributesByName");
|
|
366
|
+
lines.push(" ? ClusterAttributesByName[TDef['NAME']]");
|
|
367
|
+
lines.push(' : Record<string, unknown>;');
|
|
368
|
+
lines.push('');
|
|
369
|
+
|
|
312
370
|
// Generate endpoint type
|
|
313
371
|
lines.push(`export type ZCLNodeEndpoint = {
|
|
314
372
|
clusters: ClusterRegistry & {
|
|
@@ -327,30 +385,61 @@ export interface ZCLNode {
|
|
|
327
385
|
}
|
|
328
386
|
`);
|
|
329
387
|
|
|
330
|
-
//
|
|
331
|
-
lines.push(`
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
};
|
|
335
|
-
export const CLUSTER: {
|
|
336
|
-
[key: string]: { ID: number; NAME: string; ATTRIBUTES: unknown; COMMANDS: unknown };
|
|
337
|
-
};
|
|
338
|
-
export { ZCLNodeCluster };`);
|
|
388
|
+
// Runtime value exports
|
|
389
|
+
lines.push(`export const ZCLNode: {
|
|
390
|
+
new (node: ZCLNodeConstructorInput): ZCLNode;
|
|
391
|
+
};
|
|
339
392
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
lines.push(` export const ${exportName}: {`);
|
|
345
|
-
lines.push(` new (...args: any[]): ${interfaceName};`);
|
|
393
|
+
export const CLUSTER: {
|
|
394
|
+
`);
|
|
395
|
+
for (const def of clusterDefinitions) {
|
|
396
|
+
lines.push(` ${def.constantName}: {`);
|
|
346
397
|
lines.push(' ID: number;');
|
|
347
|
-
lines.push(
|
|
398
|
+
lines.push(` NAME: '${def.clusterName}';`);
|
|
348
399
|
lines.push(' ATTRIBUTES: unknown;');
|
|
349
400
|
lines.push(' COMMANDS: unknown;');
|
|
350
401
|
lines.push(' };');
|
|
351
402
|
}
|
|
403
|
+
lines.push('};');
|
|
352
404
|
|
|
353
|
-
|
|
405
|
+
// Export all cluster classes
|
|
406
|
+
for (const cluster of clusters) {
|
|
407
|
+
const interfaceName = toInterfaceName(cluster);
|
|
408
|
+
const exportName = cluster.exportName || interfaceName;
|
|
409
|
+
lines.push(`export const ${exportName}: {`);
|
|
410
|
+
lines.push(` new (...args: any[]): ${interfaceName};`);
|
|
411
|
+
lines.push(` ID: ${cluster.clusterId};`);
|
|
412
|
+
lines.push(` NAME: '${cluster.clusterName}';`);
|
|
413
|
+
lines.push(' ATTRIBUTES: unknown;');
|
|
414
|
+
lines.push(' COMMANDS: unknown;');
|
|
415
|
+
lines.push('};');
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Export constants
|
|
419
|
+
if (constants) {
|
|
420
|
+
for (const [name, value] of Object.entries(constants)) {
|
|
421
|
+
lines.push('');
|
|
422
|
+
lines.push(`export const ${name}: {`);
|
|
423
|
+
lines.push(generateConstantObject(value));
|
|
424
|
+
lines.push('};');
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
lines.push('');
|
|
429
|
+
lines.push('declare const _default: {');
|
|
430
|
+
lines.push(' ZCLNode: typeof ZCLNode;');
|
|
431
|
+
lines.push(' CLUSTER: typeof CLUSTER;');
|
|
432
|
+
for (const cluster of clusters) {
|
|
433
|
+
const exportName = cluster.exportName || toInterfaceName(cluster);
|
|
434
|
+
lines.push(` ${exportName}: typeof ${exportName};`);
|
|
435
|
+
}
|
|
436
|
+
if (constants) {
|
|
437
|
+
for (const name of Object.keys(constants)) {
|
|
438
|
+
lines.push(` ${name}: typeof ${name};`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
lines.push('};');
|
|
442
|
+
lines.push('export default _default;');
|
|
354
443
|
|
|
355
444
|
return lines.join('\n');
|
|
356
445
|
}
|
|
@@ -381,8 +470,20 @@ function main() {
|
|
|
381
470
|
// Sort clusters alphabetically
|
|
382
471
|
clusters.sort((a, b) => a.clusterName.localeCompare(b.clusterName));
|
|
383
472
|
|
|
473
|
+
const clusterDefinitions = Object.entries(clustersModule.CLUSTER)
|
|
474
|
+
.map(([constantName, value]) => ({
|
|
475
|
+
constantName,
|
|
476
|
+
clusterId: value.ID,
|
|
477
|
+
clusterName: value.NAME,
|
|
478
|
+
}))
|
|
479
|
+
.sort((a, b) => a.constantName.localeCompare(b.constantName));
|
|
480
|
+
|
|
481
|
+
// Load constants
|
|
482
|
+
const { ZIGBEE_PROFILE_ID, ZIGBEE_DEVICE_ID, IAS_ZONE_TYPE } = require('../lib/constants');
|
|
483
|
+
const constants = { ZIGBEE_PROFILE_ID, ZIGBEE_DEVICE_ID, IAS_ZONE_TYPE };
|
|
484
|
+
|
|
384
485
|
console.log(`\nGenerating ${OUTPUT_FILE}...`);
|
|
385
|
-
const output = generateTypesFile(clusters);
|
|
486
|
+
const output = generateTypesFile(clusters, clusterDefinitions, constants);
|
|
386
487
|
fs.writeFileSync(OUTPUT_FILE, output);
|
|
387
488
|
|
|
388
489
|
console.log(`Done! Generated types for ${clusters.length} clusters.`);
|