zigbee-herdsman 5.0.4 → 6.0.1
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 +3 -0
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/typedoc.yaml +1 -1
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +29 -0
- package/biome.json +1 -1
- package/dist/adapter/ember/ezsp/buffalo.d.ts +0 -2
- package/dist/adapter/ember/ezsp/buffalo.d.ts.map +1 -1
- package/dist/adapter/ember/ezsp/buffalo.js +0 -4
- package/dist/adapter/ember/ezsp/buffalo.js.map +1 -1
- package/dist/adapter/ember/uart/ash.d.ts.map +1 -1
- package/dist/adapter/ember/uart/ash.js +0 -2
- package/dist/adapter/ember/uart/ash.js.map +1 -1
- package/dist/buffalo/buffalo.d.ts +5 -0
- package/dist/buffalo/buffalo.d.ts.map +1 -1
- package/dist/buffalo/buffalo.js +7 -0
- package/dist/buffalo/buffalo.js.map +1 -1
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +8 -11
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/events.d.ts +2 -1
- package/dist/controller/events.d.ts.map +1 -1
- package/dist/controller/helpers/request.d.ts.map +1 -1
- package/dist/controller/helpers/request.js +2 -1
- package/dist/controller/helpers/request.js.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.d.ts +2 -4
- package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.js +2 -0
- package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
- package/dist/controller/model/device.d.ts +13 -24
- package/dist/controller/model/device.d.ts.map +1 -1
- package/dist/controller/model/device.js +88 -129
- package/dist/controller/model/device.js.map +1 -1
- package/dist/controller/model/endpoint.d.ts +17 -16
- package/dist/controller/model/endpoint.d.ts.map +1 -1
- package/dist/controller/model/endpoint.js +31 -16
- package/dist/controller/model/endpoint.js.map +1 -1
- package/dist/controller/model/group.d.ts +6 -6
- package/dist/controller/model/group.d.ts.map +1 -1
- package/dist/controller/model/group.js +5 -3
- package/dist/controller/model/group.js.map +1 -1
- package/dist/controller/model/index.d.ts +1 -0
- package/dist/controller/model/index.d.ts.map +1 -1
- package/dist/controller/model/index.js +3 -1
- package/dist/controller/model/index.js.map +1 -1
- package/dist/controller/model/zigbeeEntity.d.ts +8 -0
- package/dist/controller/model/zigbeeEntity.d.ts.map +1 -0
- package/dist/controller/model/zigbeeEntity.js +11 -0
- package/dist/controller/model/zigbeeEntity.js.map +1 -0
- package/dist/controller/tstype.d.ts +39 -0
- package/dist/controller/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.d.ts +32 -17
- package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.js +257 -121
- package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
- package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/cluster.js +156 -33
- package/dist/zspec/zcl/definition/cluster.js.map +1 -1
- package/dist/zspec/zcl/definition/clusters-typegen.d.ts +2 -0
- package/dist/zspec/zcl/definition/clusters-typegen.d.ts.map +1 -0
- package/dist/zspec/zcl/definition/clusters-typegen.js +348 -0
- package/dist/zspec/zcl/definition/clusters-typegen.js.map +1 -0
- package/dist/zspec/zcl/definition/clusters-types.d.ts +7238 -0
- package/dist/zspec/zcl/definition/clusters-types.d.ts.map +1 -0
- package/dist/zspec/zcl/definition/clusters-types.js +3 -0
- package/dist/zspec/zcl/definition/clusters-types.js.map +1 -0
- package/dist/zspec/zcl/definition/enums.d.ts +14 -6
- package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.js +15 -6
- package/dist/zspec/zcl/definition/enums.js.map +1 -1
- package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/foundation.js +43 -15
- package/dist/zspec/zcl/definition/foundation.js.map +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts +105 -11
- package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/index.d.ts +1 -0
- package/dist/zspec/zcl/index.d.ts.map +1 -1
- package/dist/zspec/zcl/index.js.map +1 -1
- package/dist/zspec/zcl/utils.d.ts +1 -1
- package/dist/zspec/zcl/utils.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.js +1 -1
- package/dist/zspec/zcl/utils.js.map +1 -1
- package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
- package/dist/zspec/zcl/zclFrame.js +32 -20
- package/dist/zspec/zcl/zclFrame.js.map +1 -1
- package/dist/zspec/zdo/buffaloZdo.d.ts +0 -6
- package/dist/zspec/zdo/buffaloZdo.d.ts.map +1 -1
- package/dist/zspec/zdo/buffaloZdo.js +0 -8
- package/dist/zspec/zdo/buffaloZdo.js.map +1 -1
- package/package.json +3 -3
- package/src/adapter/ember/ezsp/buffalo.ts +0 -5
- package/src/adapter/ember/uart/ash.ts +0 -2
- package/src/adapter/ezsp/driver/driver.ts +1 -1
- package/src/buffalo/buffalo.ts +8 -0
- package/src/controller/controller.ts +13 -16
- package/src/controller/events.ts +2 -1
- package/src/controller/greenPower.ts +4 -4
- package/src/controller/helpers/request.ts +3 -1
- package/src/controller/helpers/zclFrameConverter.ts +13 -17
- package/src/controller/model/device.ts +103 -148
- package/src/controller/model/endpoint.ts +112 -64
- package/src/controller/model/group.ts +33 -9
- package/src/controller/model/index.ts +1 -0
- package/src/controller/model/zigbeeEntity.ts +30 -0
- package/src/controller/tstype.ts +251 -16
- package/src/zspec/zcl/buffaloZcl.ts +323 -238
- package/src/zspec/zcl/definition/cluster.ts +156 -33
- package/src/zspec/zcl/definition/clusters-typegen.ts +588 -0
- package/src/zspec/zcl/definition/clusters-types.ts +7331 -0
- package/src/zspec/zcl/definition/enums.ts +14 -5
- package/src/zspec/zcl/definition/foundation.ts +43 -15
- package/src/zspec/zcl/definition/tstype.ts +118 -8
- package/src/zspec/zcl/index.ts +1 -0
- package/src/zspec/zcl/utils.ts +1 -1
- package/src/zspec/zcl/zclFrame.ts +37 -19
- package/src/zspec/zdo/buffaloZdo.ts +0 -9
- package/test/controller.test.ts +356 -896
- package/test/greenpower.test.ts +0 -12
- package/test/zcl.test.ts +13 -11
- package/test/zspec/zcl/buffalo.test.ts +216 -74
- package/test/zspec/zcl/frame.test.ts +62 -28
- package/test/zspec/zcl/utils.test.ts +4 -4
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
/* v8 ignore start */
|
|
2
|
+
/**
|
|
3
|
+
* How to run:
|
|
4
|
+
* ```bash
|
|
5
|
+
* npm i -g ts-node
|
|
6
|
+
* ts-node ./src/zspec/zcl/definition/clusters-typegen.ts && pnpm run check:w
|
|
7
|
+
* ```
|
|
8
|
+
* or with compiled:
|
|
9
|
+
* ```bash
|
|
10
|
+
* pnpm run prepack
|
|
11
|
+
* node ./dist/zspec/zcl/definition/clusters-typegen.js && pnpm run check:w
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
import {writeFileSync} from "node:fs";
|
|
15
|
+
import ts from "typescript";
|
|
16
|
+
import {isFoundationDiscoverRsp} from "../utils";
|
|
17
|
+
import {Clusters} from "./cluster";
|
|
18
|
+
import {BuffaloZclDataType, DataType} from "./enums";
|
|
19
|
+
import {Foundation, type FoundationCommandName, type FoundationDefinition} from "./foundation";
|
|
20
|
+
import {ManufacturerCode} from "./manufacturerCode";
|
|
21
|
+
import type {AttributeDefinition, ClusterName, CommandDefinition, ParameterDefinition} from "./tstype";
|
|
22
|
+
|
|
23
|
+
const FILENAME = "clusters-types.ts";
|
|
24
|
+
|
|
25
|
+
const file = ts.createSourceFile(FILENAME, "", ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS);
|
|
26
|
+
const printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed});
|
|
27
|
+
|
|
28
|
+
const emptyObject = ts.factory.createTypeReferenceNode("Record", [
|
|
29
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
30
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword),
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
const namedImports = ts.factory.createImportDeclaration(
|
|
34
|
+
undefined,
|
|
35
|
+
ts.factory.createImportClause(
|
|
36
|
+
true,
|
|
37
|
+
undefined,
|
|
38
|
+
ts.factory.createNamedImports([
|
|
39
|
+
// sorted by name
|
|
40
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("ExtensionFieldSet")),
|
|
41
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("Gpd")),
|
|
42
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("GpdAttributeReport")),
|
|
43
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("GpdChannelConfiguration")),
|
|
44
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("GpdChannelRequest")),
|
|
45
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("GpdCommissioningReply")),
|
|
46
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("GpdCustomReply")),
|
|
47
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("MiboxerZone")),
|
|
48
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("Struct")),
|
|
49
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("StructuredSelector")),
|
|
50
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("ThermoTransition")),
|
|
51
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("TuyaDataPointValue")),
|
|
52
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("ZclArray")),
|
|
53
|
+
// ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("ZclDate")), // XXX: currently unused
|
|
54
|
+
// ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("ZclTimeOfDay")), // XXX: currently unused
|
|
55
|
+
ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("ZoneInfo")),
|
|
56
|
+
]),
|
|
57
|
+
),
|
|
58
|
+
ts.factory.createStringLiteral("./tstype"),
|
|
59
|
+
undefined,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const getTypeFromDataType = (dataType: DataType | BuffaloZclDataType): ts.TypeNode => {
|
|
63
|
+
switch (dataType) {
|
|
64
|
+
case DataType.NO_DATA:
|
|
65
|
+
case DataType.UNKNOWN: {
|
|
66
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword);
|
|
67
|
+
}
|
|
68
|
+
case DataType.DATA56:
|
|
69
|
+
case DataType.BITMAP56:
|
|
70
|
+
case DataType.UINT56:
|
|
71
|
+
case DataType.DATA64:
|
|
72
|
+
case DataType.BITMAP64:
|
|
73
|
+
case DataType.UINT64:
|
|
74
|
+
case DataType.INT56:
|
|
75
|
+
case DataType.INT64: {
|
|
76
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword);
|
|
77
|
+
}
|
|
78
|
+
case DataType.OCTET_STR:
|
|
79
|
+
case DataType.LONG_OCTET_STR:
|
|
80
|
+
case DataType.SEC_KEY: {
|
|
81
|
+
return ts.factory.createTypeReferenceNode("Buffer");
|
|
82
|
+
}
|
|
83
|
+
case DataType.CHAR_STR:
|
|
84
|
+
case DataType.LONG_CHAR_STR:
|
|
85
|
+
case DataType.IEEE_ADDR: {
|
|
86
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
87
|
+
}
|
|
88
|
+
case DataType.ARRAY:
|
|
89
|
+
case DataType.SET:
|
|
90
|
+
case DataType.BAG: {
|
|
91
|
+
// mismatch on read vs write, have to union
|
|
92
|
+
return ts.factory.createUnionTypeNode([
|
|
93
|
+
ts.factory.createTypeReferenceNode("ZclArray"),
|
|
94
|
+
ts.factory.createArrayTypeNode(ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)),
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
case DataType.STRUCT: {
|
|
98
|
+
return ts.factory.createTypeReferenceNode("Struct");
|
|
99
|
+
}
|
|
100
|
+
case DataType.TOD: {
|
|
101
|
+
return ts.factory.createTypeReferenceNode("ZclTimeOfDay");
|
|
102
|
+
}
|
|
103
|
+
case DataType.DATE: {
|
|
104
|
+
return ts.factory.createTypeReferenceNode("ZclDate");
|
|
105
|
+
}
|
|
106
|
+
case BuffaloZclDataType.USE_DATA_TYPE: {
|
|
107
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
|
108
|
+
}
|
|
109
|
+
case BuffaloZclDataType.LIST_UINT8:
|
|
110
|
+
case BuffaloZclDataType.LIST_UINT16:
|
|
111
|
+
case BuffaloZclDataType.LIST_UINT24:
|
|
112
|
+
case BuffaloZclDataType.LIST_UINT32: {
|
|
113
|
+
return ts.factory.createArrayTypeNode(ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
|
|
114
|
+
}
|
|
115
|
+
case BuffaloZclDataType.LIST_ZONEINFO: {
|
|
116
|
+
return ts.factory.createArrayTypeNode(ts.factory.createTypeReferenceNode("ZoneInfo"));
|
|
117
|
+
}
|
|
118
|
+
case BuffaloZclDataType.EXTENSION_FIELD_SETS: {
|
|
119
|
+
return ts.factory.createArrayTypeNode(ts.factory.createTypeReferenceNode("ExtensionFieldSet"));
|
|
120
|
+
}
|
|
121
|
+
case BuffaloZclDataType.LIST_THERMO_TRANSITIONS: {
|
|
122
|
+
return ts.factory.createArrayTypeNode(ts.factory.createTypeReferenceNode("ThermoTransition"));
|
|
123
|
+
}
|
|
124
|
+
case BuffaloZclDataType.BUFFER: {
|
|
125
|
+
return ts.factory.createTypeReferenceNode("Buffer");
|
|
126
|
+
}
|
|
127
|
+
case BuffaloZclDataType.GPD_FRAME: {
|
|
128
|
+
return ts.factory.createUnionTypeNode([
|
|
129
|
+
ts.factory.createTypeReferenceNode("Gpd"),
|
|
130
|
+
ts.factory.createTypeReferenceNode("GpdChannelRequest"),
|
|
131
|
+
ts.factory.createTypeReferenceNode("GpdAttributeReport"),
|
|
132
|
+
ts.factory.createTypeLiteralNode([
|
|
133
|
+
ts.factory.createPropertySignature(undefined, "raw", undefined, ts.factory.createTypeReferenceNode("Buffer")),
|
|
134
|
+
]),
|
|
135
|
+
ts.factory.createTypeReferenceNode("Record<string, never>"),
|
|
136
|
+
ts.factory.createTypeReferenceNode("GpdCommissioningReply"),
|
|
137
|
+
ts.factory.createTypeReferenceNode("GpdChannelConfiguration"),
|
|
138
|
+
ts.factory.createTypeReferenceNode("GpdCustomReply"),
|
|
139
|
+
]);
|
|
140
|
+
}
|
|
141
|
+
case BuffaloZclDataType.STRUCTURED_SELECTOR: {
|
|
142
|
+
return ts.factory.createTypeReferenceNode("StructuredSelector");
|
|
143
|
+
}
|
|
144
|
+
case BuffaloZclDataType.LIST_TUYA_DATAPOINT_VALUES: {
|
|
145
|
+
return ts.factory.createArrayTypeNode(ts.factory.createTypeReferenceNode("TuyaDataPointValue"));
|
|
146
|
+
}
|
|
147
|
+
case BuffaloZclDataType.LIST_MIBOXER_ZONES: {
|
|
148
|
+
return ts.factory.createArrayTypeNode(ts.factory.createTypeReferenceNode("MiboxerZone"));
|
|
149
|
+
}
|
|
150
|
+
default: {
|
|
151
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const getConditionStr = (conditions: ParameterDefinition["conditions"]): string | undefined => {
|
|
157
|
+
if (conditions) {
|
|
158
|
+
let str = ", Conditions: [";
|
|
159
|
+
|
|
160
|
+
for (const condition of conditions) {
|
|
161
|
+
str += `{${condition.type}`;
|
|
162
|
+
|
|
163
|
+
for (const key in condition) {
|
|
164
|
+
if (key === "type") {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
str += ` ${key}=${condition[key as keyof typeof condition]}`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
str += "}";
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return `${str}]`;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const addAttributes = (attributes: Readonly<Record<string, Readonly<AttributeDefinition>>>): ts.TypeNode => {
|
|
179
|
+
const elements: ts.PropertySignature[] = [];
|
|
180
|
+
|
|
181
|
+
for (const attributeName in attributes) {
|
|
182
|
+
const attribute = attributes[attributeName];
|
|
183
|
+
|
|
184
|
+
const element = ts.factory.createPropertySignature(
|
|
185
|
+
undefined,
|
|
186
|
+
attributeName,
|
|
187
|
+
// always optional if manuf-specific
|
|
188
|
+
attribute.manufacturerCode ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined,
|
|
189
|
+
getTypeFromDataType(attribute.type),
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
elements.push(element);
|
|
193
|
+
|
|
194
|
+
let comment = `* ID: ${attribute.ID} | Type: ${DataType[attribute.type] ?? BuffaloZclDataType[attribute.type]} `;
|
|
195
|
+
|
|
196
|
+
if (attribute.manufacturerCode !== undefined) {
|
|
197
|
+
comment += `| Specific to manufacturer: ${ManufacturerCode[attribute.manufacturerCode]} (${attribute.manufacturerCode}) `;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
ts.addSyntheticLeadingComment(element, ts.SyntaxKind.MultiLineCommentTrivia, comment, true);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return elements.length > 0 ? ts.factory.createTypeLiteralNode(elements) : ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const addCommands = (commands: Readonly<Record<string, Readonly<CommandDefinition>>>): ts.TypeNode => {
|
|
207
|
+
const elements: ts.PropertySignature[] = [];
|
|
208
|
+
|
|
209
|
+
for (const commandName in commands) {
|
|
210
|
+
const command = commands[commandName];
|
|
211
|
+
const cmdElements: ts.PropertySignature[] = [];
|
|
212
|
+
|
|
213
|
+
for (const parameter of command.parameters) {
|
|
214
|
+
// @ts-expect-error bad typing?
|
|
215
|
+
const existing = cmdElements.find((element) => element.name.escapedText === parameter.name);
|
|
216
|
+
const paramType = getTypeFromDataType(parameter.type);
|
|
217
|
+
|
|
218
|
+
if (!existing) {
|
|
219
|
+
const cmdElement = ts.factory.createPropertySignature(
|
|
220
|
+
undefined,
|
|
221
|
+
parameter.name,
|
|
222
|
+
parameter.conditions ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined,
|
|
223
|
+
paramType,
|
|
224
|
+
);
|
|
225
|
+
const conditionComment = getConditionStr(parameter.conditions);
|
|
226
|
+
|
|
227
|
+
cmdElements.push(cmdElement);
|
|
228
|
+
ts.addSyntheticLeadingComment(
|
|
229
|
+
cmdElement,
|
|
230
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
231
|
+
`* Type: ${DataType[parameter.type] ?? BuffaloZclDataType[parameter.type]}${conditionComment ?? ""} `,
|
|
232
|
+
true,
|
|
233
|
+
);
|
|
234
|
+
} else if (
|
|
235
|
+
// @ts-expect-error bad typing?
|
|
236
|
+
existing.type?.typeName?.escapedText &&
|
|
237
|
+
// @ts-expect-error bad typing?
|
|
238
|
+
paramType.typeName?.escapedText &&
|
|
239
|
+
// @ts-expect-error bad typing?
|
|
240
|
+
existing.type.typeName.escapedText !== paramType.typeName.escapedText
|
|
241
|
+
) {
|
|
242
|
+
// XXX: not currently used, untested
|
|
243
|
+
ts.factory.updatePropertySignature(
|
|
244
|
+
existing,
|
|
245
|
+
existing.modifiers,
|
|
246
|
+
existing.name,
|
|
247
|
+
existing.questionToken,
|
|
248
|
+
ts.factory.createUnionTypeNode([existing.type, paramType]),
|
|
249
|
+
);
|
|
250
|
+
} else if (!parameter.conditions) {
|
|
251
|
+
throw new Error(`Two or more cluster command parameters have identical name without conditions. ${JSON.stringify(parameter)}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const element = ts.factory.createPropertySignature(
|
|
256
|
+
undefined,
|
|
257
|
+
commandName,
|
|
258
|
+
undefined,
|
|
259
|
+
cmdElements.length > 0 ? ts.factory.createTypeLiteralNode(cmdElements) : emptyObject,
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
elements.push(element);
|
|
263
|
+
|
|
264
|
+
let comment = `* ID: ${command.ID} `;
|
|
265
|
+
|
|
266
|
+
if (command.response !== undefined) {
|
|
267
|
+
comment += `| Response ID: ${command.response} `;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
ts.addSyntheticLeadingComment(element, ts.SyntaxKind.MultiLineCommentTrivia, comment, true);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return elements.length > 0 ? ts.factory.createTypeLiteralNode(elements) : ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword);
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const clusterElements: ts.TypeElement[] = [];
|
|
277
|
+
|
|
278
|
+
for (const clusterName in Clusters) {
|
|
279
|
+
const cluster = Clusters[clusterName as ClusterName];
|
|
280
|
+
|
|
281
|
+
const attributesProp = ts.factory.createPropertySignature(undefined, "attributes", undefined, addAttributes(cluster.attributes));
|
|
282
|
+
const commandsProp = ts.factory.createPropertySignature(undefined, "commands", undefined, addCommands(cluster.commands));
|
|
283
|
+
const commandResponsesProp = ts.factory.createPropertySignature(undefined, "commandResponses", undefined, addCommands(cluster.commandsResponse));
|
|
284
|
+
|
|
285
|
+
clusterElements.push(
|
|
286
|
+
ts.factory.createPropertySignature(
|
|
287
|
+
undefined,
|
|
288
|
+
clusterName,
|
|
289
|
+
undefined,
|
|
290
|
+
ts.factory.createTypeLiteralNode([attributesProp, commandsProp, commandResponsesProp]),
|
|
291
|
+
),
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const clustersDecl = ts.factory.createInterfaceDeclaration(
|
|
296
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
297
|
+
"TClusters",
|
|
298
|
+
undefined,
|
|
299
|
+
undefined,
|
|
300
|
+
clusterElements,
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
const addParameters = (foundation: Readonly<FoundationDefinition>): ts.TypeNode => {
|
|
304
|
+
const elements: ts.PropertySignature[] = [];
|
|
305
|
+
|
|
306
|
+
for (const parameter of foundation.parameters) {
|
|
307
|
+
const element = ts.factory.createPropertySignature(
|
|
308
|
+
undefined,
|
|
309
|
+
parameter.name,
|
|
310
|
+
parameter.conditions ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined,
|
|
311
|
+
getTypeFromDataType(parameter.type),
|
|
312
|
+
);
|
|
313
|
+
const conditionComment = getConditionStr(parameter.conditions);
|
|
314
|
+
|
|
315
|
+
elements.push(element);
|
|
316
|
+
|
|
317
|
+
ts.addSyntheticLeadingComment(
|
|
318
|
+
element,
|
|
319
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
320
|
+
`* Type: ${DataType[parameter.type] ?? BuffaloZclDataType[parameter.type]}${conditionComment ?? ""} `,
|
|
321
|
+
true,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (elements.length === 0) {
|
|
326
|
+
return emptyObject;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
switch (foundation.parseStrategy) {
|
|
330
|
+
case "repetitive": {
|
|
331
|
+
return ts.factory.createArrayTypeNode(ts.factory.createTypeLiteralNode(elements));
|
|
332
|
+
}
|
|
333
|
+
case "flat": {
|
|
334
|
+
return ts.factory.createTypeLiteralNode(elements);
|
|
335
|
+
}
|
|
336
|
+
case "oneof": {
|
|
337
|
+
if (isFoundationDiscoverRsp(foundation.ID)) {
|
|
338
|
+
const discComplete = ts.factory.createPropertySignature(
|
|
339
|
+
undefined,
|
|
340
|
+
"discComplete",
|
|
341
|
+
undefined,
|
|
342
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
ts.addSyntheticLeadingComment(discComplete, ts.SyntaxKind.MultiLineCommentTrivia, `* Type: ${DataType[DataType.UINT8]} `, true);
|
|
346
|
+
|
|
347
|
+
return ts.factory.createTypeLiteralNode([
|
|
348
|
+
discComplete,
|
|
349
|
+
ts.factory.createPropertySignature(
|
|
350
|
+
undefined,
|
|
351
|
+
"attrInfos",
|
|
352
|
+
undefined,
|
|
353
|
+
ts.factory.createArrayTypeNode(ts.factory.createTypeLiteralNode(elements)),
|
|
354
|
+
),
|
|
355
|
+
]);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
throw new Error(`Unknown command strategy for ${JSON.stringify(foundation)}`);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const foundationElements: ts.TypeElement[] = [];
|
|
364
|
+
const foundationRepetitiveElements: ts.TypeNode[] = [];
|
|
365
|
+
const foundationFlatElements: ts.TypeNode[] = [];
|
|
366
|
+
const foundationOneOfElements: ts.TypeNode[] = [];
|
|
367
|
+
|
|
368
|
+
for (const foundationName in Foundation) {
|
|
369
|
+
const foundation = Foundation[foundationName as FoundationCommandName];
|
|
370
|
+
const element = ts.factory.createPropertySignature(undefined, foundationName, undefined, addParameters(foundation));
|
|
371
|
+
|
|
372
|
+
foundationElements.push(element);
|
|
373
|
+
ts.addSyntheticLeadingComment(element, ts.SyntaxKind.MultiLineCommentTrivia, `* ID: ${foundation.ID} `, true);
|
|
374
|
+
|
|
375
|
+
const stratNode = ts.factory.createTypeReferenceNode(`"${foundationName}"`);
|
|
376
|
+
|
|
377
|
+
switch (foundation.parseStrategy) {
|
|
378
|
+
case "repetitive": {
|
|
379
|
+
foundationRepetitiveElements.push(stratNode);
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
case "flat": {
|
|
383
|
+
foundationFlatElements.push(stratNode);
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
case "oneof": {
|
|
387
|
+
foundationOneOfElements.push(stratNode);
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const foundationDecl = ts.factory.createInterfaceDeclaration(
|
|
394
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
395
|
+
"TFoundation",
|
|
396
|
+
undefined,
|
|
397
|
+
undefined,
|
|
398
|
+
foundationElements,
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
const foundationRepetitiveDecl = ts.factory.createTypeAliasDeclaration(
|
|
402
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
403
|
+
"TFoundationRepetitive",
|
|
404
|
+
undefined,
|
|
405
|
+
ts.factory.createUnionTypeNode(foundationRepetitiveElements),
|
|
406
|
+
);
|
|
407
|
+
const foundationFlatDecl = ts.factory.createTypeAliasDeclaration(
|
|
408
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
409
|
+
"TFoundationFlat",
|
|
410
|
+
undefined,
|
|
411
|
+
ts.factory.createUnionTypeNode(foundationFlatElements),
|
|
412
|
+
);
|
|
413
|
+
const foundationOneOfDecl = ts.factory.createTypeAliasDeclaration(
|
|
414
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
415
|
+
"TFoundationOneOf",
|
|
416
|
+
undefined,
|
|
417
|
+
ts.factory.createUnionTypeNode(foundationOneOfElements),
|
|
418
|
+
);
|
|
419
|
+
const clDecl = ts.factory.createTypeParameterDeclaration(
|
|
420
|
+
undefined,
|
|
421
|
+
"Cl",
|
|
422
|
+
ts.factory.createUnionTypeNode([
|
|
423
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
|
|
424
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
425
|
+
]),
|
|
426
|
+
);
|
|
427
|
+
const coDecl = ts.factory.createTypeParameterDeclaration(
|
|
428
|
+
undefined,
|
|
429
|
+
"Co",
|
|
430
|
+
ts.factory.createUnionTypeNode([
|
|
431
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
|
|
432
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
433
|
+
]),
|
|
434
|
+
);
|
|
435
|
+
const clusterAttributeKeysDecl = ts.factory.createTypeAliasDeclaration(
|
|
436
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
437
|
+
"TClusterAttributeKeys",
|
|
438
|
+
[clDecl],
|
|
439
|
+
ts.factory.createTypeReferenceNode(
|
|
440
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? (keyof ${clustersDecl.name.escapedText}[Cl]["attributes"])[] : (string | number)[];`,
|
|
441
|
+
),
|
|
442
|
+
);
|
|
443
|
+
const clusterAttributesDecl = ts.factory.createTypeAliasDeclaration(
|
|
444
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
445
|
+
"TClusterAttributes",
|
|
446
|
+
[clDecl],
|
|
447
|
+
ts.factory.createTypeReferenceNode(
|
|
448
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? ${clustersDecl.name.escapedText}[Cl]["attributes"] : never`,
|
|
449
|
+
),
|
|
450
|
+
);
|
|
451
|
+
const partialClusterAttributesDecl = ts.factory.createTypeAliasDeclaration(
|
|
452
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
453
|
+
"TPartialClusterAttributes",
|
|
454
|
+
[clDecl],
|
|
455
|
+
ts.factory.createTypeReferenceNode(
|
|
456
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? Partial<${clustersDecl.name.escapedText}[Cl]["attributes"]> : never`,
|
|
457
|
+
),
|
|
458
|
+
);
|
|
459
|
+
const clusterCommandKeysDecl = ts.factory.createTypeAliasDeclaration(
|
|
460
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
461
|
+
"TClusterCommandKeys",
|
|
462
|
+
[clDecl],
|
|
463
|
+
ts.factory.createTypeReferenceNode(
|
|
464
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? (keyof ${clustersDecl.name.escapedText}[Cl]["commands"])[] : (string | number)[];`,
|
|
465
|
+
),
|
|
466
|
+
);
|
|
467
|
+
const clusterCommandResponseKeysDecl = ts.factory.createTypeAliasDeclaration(
|
|
468
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
469
|
+
"TClusterCommandResponseKeys",
|
|
470
|
+
[clDecl],
|
|
471
|
+
ts.factory.createTypeReferenceNode(
|
|
472
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? (keyof ${clustersDecl.name.escapedText}[Cl]["commandResponses"])[] : (string | number)[];`,
|
|
473
|
+
),
|
|
474
|
+
);
|
|
475
|
+
const clusterCommandsDecl = ts.factory.createTypeAliasDeclaration(
|
|
476
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
477
|
+
"TClusterCommands",
|
|
478
|
+
[clDecl],
|
|
479
|
+
ts.factory.createTypeReferenceNode(
|
|
480
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? ${clustersDecl.name.escapedText}[Cl]["commands"] : never`,
|
|
481
|
+
),
|
|
482
|
+
);
|
|
483
|
+
const clusterCommandResponsesDecl = ts.factory.createTypeAliasDeclaration(
|
|
484
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
485
|
+
"TClusterCommandResponses",
|
|
486
|
+
[clDecl],
|
|
487
|
+
ts.factory.createTypeReferenceNode(
|
|
488
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? ${clustersDecl.name.escapedText}[Cl]["commandResponses"] : never`,
|
|
489
|
+
),
|
|
490
|
+
);
|
|
491
|
+
const clusterCommandPayloadDecl = ts.factory.createTypeAliasDeclaration(
|
|
492
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
493
|
+
"TClusterCommandPayload",
|
|
494
|
+
[clDecl, coDecl],
|
|
495
|
+
ts.factory.createTypeReferenceNode(
|
|
496
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? Co extends keyof ${clustersDecl.name.escapedText}[Cl]["commands"] ? ${clustersDecl.name.escapedText}[Cl]["commands"][Co] : never : never;`,
|
|
497
|
+
),
|
|
498
|
+
);
|
|
499
|
+
const clusterCommandResponsePayloadDecl = ts.factory.createTypeAliasDeclaration(
|
|
500
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
501
|
+
"TClusterCommandResponsePayload",
|
|
502
|
+
[clDecl, coDecl],
|
|
503
|
+
ts.factory.createTypeReferenceNode(
|
|
504
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? Co extends keyof ${clustersDecl.name.escapedText}[Cl]["commandResponses"] ? ${clustersDecl.name.escapedText}[Cl]["commandResponses"][Co] : never : never;`,
|
|
505
|
+
),
|
|
506
|
+
);
|
|
507
|
+
const clusterPayloadDecl = ts.factory.createTypeAliasDeclaration(
|
|
508
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
509
|
+
"TClusterPayload",
|
|
510
|
+
[clDecl, coDecl],
|
|
511
|
+
ts.factory.createTypeReferenceNode(
|
|
512
|
+
`Cl extends keyof ${clustersDecl.name.escapedText} ? ${clustersDecl.name.escapedText}[Cl]["commands"] extends never ? ${clustersDecl.name.escapedText}[Cl]["commandResponses"] extends never ? never : Co extends keyof ${clustersDecl.name.escapedText}[Cl]["commandResponses"] ? ${clustersDecl.name.escapedText}[Cl]["commandResponses"][Co] : never : Co extends keyof ${clustersDecl.name.escapedText}[Cl]["commands"] ? ${clustersDecl.name.escapedText}[Cl]["commands"][Co] : Co extends keyof ${clustersDecl.name.escapedText}[Cl]["commandResponses"] ? ${clustersDecl.name.escapedText}[Cl]["commandResponses"][Co] : never : never;`,
|
|
513
|
+
),
|
|
514
|
+
);
|
|
515
|
+
const foundationGenericPayloadDecl = ts.factory.createTypeAliasDeclaration(
|
|
516
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
517
|
+
"TFoundationGenericPayload",
|
|
518
|
+
undefined,
|
|
519
|
+
ts.factory.createTypeReferenceNode(`${foundationDecl.name.escapedText}[keyof ${foundationDecl.name.escapedText}]`),
|
|
520
|
+
);
|
|
521
|
+
const foundationRepetitivePayloadDecl = ts.factory.createTypeAliasDeclaration(
|
|
522
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
523
|
+
"TFoundationRepetitivePayload",
|
|
524
|
+
undefined,
|
|
525
|
+
ts.factory.createTypeReferenceNode(`${foundationDecl.name.escapedText}[${foundationRepetitiveDecl.name.escapedText}]`),
|
|
526
|
+
);
|
|
527
|
+
const foundationFlatPayloadDecl = ts.factory.createTypeAliasDeclaration(
|
|
528
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
529
|
+
"TFoundationFlatPayload",
|
|
530
|
+
undefined,
|
|
531
|
+
ts.factory.createTypeReferenceNode(`${foundationDecl.name.escapedText}[${foundationFlatDecl.name.escapedText}]`),
|
|
532
|
+
);
|
|
533
|
+
const foundationOneOfPayloadDecl = ts.factory.createTypeAliasDeclaration(
|
|
534
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
535
|
+
"TFoundationOneOfPayload",
|
|
536
|
+
undefined,
|
|
537
|
+
ts.factory.createTypeReferenceNode(`${foundationDecl.name.escapedText}[${foundationOneOfDecl.name.escapedText}]`),
|
|
538
|
+
);
|
|
539
|
+
const foundationPayloadDecl = ts.factory.createTypeAliasDeclaration(
|
|
540
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
541
|
+
"TFoundationPayload",
|
|
542
|
+
[coDecl],
|
|
543
|
+
ts.factory.createTypeReferenceNode(
|
|
544
|
+
`Co extends keyof ${foundationDecl.name.escapedText} ? ${foundationDecl.name.escapedText}[Co] : ${foundationGenericPayloadDecl.name.escapedText}`,
|
|
545
|
+
),
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
const result = `${printer.printNode(ts.EmitHint.Unspecified, namedImports, file)}
|
|
549
|
+
|
|
550
|
+
${printer.printNode(ts.EmitHint.Unspecified, clustersDecl, file)}
|
|
551
|
+
|
|
552
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationDecl, file)}
|
|
553
|
+
|
|
554
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationRepetitiveDecl, file)}
|
|
555
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationFlatDecl, file)}
|
|
556
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationOneOfDecl, file)}
|
|
557
|
+
|
|
558
|
+
// Clusters
|
|
559
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterAttributeKeysDecl, file)}
|
|
560
|
+
|
|
561
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterAttributesDecl, file)}
|
|
562
|
+
|
|
563
|
+
${printer.printNode(ts.EmitHint.Unspecified, partialClusterAttributesDecl, file)}
|
|
564
|
+
|
|
565
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterCommandKeysDecl, file)}
|
|
566
|
+
|
|
567
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterCommandResponseKeysDecl, file)}
|
|
568
|
+
|
|
569
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterCommandsDecl, file)}
|
|
570
|
+
|
|
571
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterCommandResponsesDecl, file)}
|
|
572
|
+
|
|
573
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterCommandPayloadDecl, file)}
|
|
574
|
+
|
|
575
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterCommandResponsePayloadDecl, file)}
|
|
576
|
+
|
|
577
|
+
${printer.printNode(ts.EmitHint.Unspecified, clusterPayloadDecl, file)}
|
|
578
|
+
|
|
579
|
+
// Foundation
|
|
580
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationGenericPayloadDecl, file)}
|
|
581
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationRepetitivePayloadDecl, file)}
|
|
582
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationFlatPayloadDecl, file)}
|
|
583
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationOneOfPayloadDecl, file)}
|
|
584
|
+
|
|
585
|
+
${printer.printNode(ts.EmitHint.Unspecified, foundationPayloadDecl, file)}
|
|
586
|
+
`;
|
|
587
|
+
|
|
588
|
+
writeFileSync(`./src/zspec/zcl/definition/${FILENAME}`, result, {encoding: "utf8"});
|