@deconz-community/ddf-validator 2.11.0 → 2.12.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/dist/ddf-schema.json +1 -1
- package/dist/ddf-validator.cjs +1 -1
- package/dist/ddf-validator.d.ts +1 -0
- package/dist/ddf-validator.mjs +222 -197
- package/package.json +11 -11
package/dist/ddf-validator.mjs
CHANGED
|
@@ -1,61 +1,62 @@
|
|
|
1
1
|
import { z as e } from "zod";
|
|
2
|
-
const
|
|
2
|
+
const O = "2.12.0", y = {
|
|
3
3
|
"devcap1.schema.json": [
|
|
4
|
-
O,
|
|
5
|
-
D,
|
|
6
4
|
E,
|
|
7
|
-
|
|
5
|
+
T,
|
|
6
|
+
w,
|
|
7
|
+
$,
|
|
8
|
+
C
|
|
8
9
|
],
|
|
9
10
|
"constants2.schema.json": [
|
|
10
|
-
|
|
11
|
+
_
|
|
11
12
|
]
|
|
12
13
|
};
|
|
13
|
-
function
|
|
14
|
-
const o = typeof
|
|
14
|
+
function E(t, r, f) {
|
|
15
|
+
const o = typeof t.manufacturername == "string" && typeof t.modelid == "string";
|
|
15
16
|
if (o)
|
|
16
17
|
return;
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
|
|
18
|
+
const c = Array.isArray(t.manufacturername) && Array.isArray(t.modelid);
|
|
19
|
+
if (c && t.manufacturername.length !== t.modelid.length) {
|
|
20
|
+
r.addIssue({
|
|
20
21
|
code: e.ZodIssueCode.invalid_intersection_types,
|
|
21
22
|
message: "When 'manufacturername' and 'modelid' are both arrays they should be the same length",
|
|
22
23
|
path: ["manufacturername", "modelid"]
|
|
23
24
|
});
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
26
|
-
(o ||
|
|
27
|
+
(o || c) === !1 && r.addIssue({
|
|
27
28
|
code: e.ZodIssueCode.invalid_intersection_types,
|
|
28
29
|
message: "Invalid properties 'manufacturername' and 'modelid' should have the same type",
|
|
29
30
|
path: ["manufacturername", "modelid"]
|
|
30
31
|
});
|
|
31
32
|
}
|
|
32
|
-
function
|
|
33
|
-
if (!
|
|
33
|
+
function T(t, r, f) {
|
|
34
|
+
if (!t.bindings)
|
|
34
35
|
return;
|
|
35
|
-
const o = (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const o = (n) => `0x${(typeof n == "number" ? n : Number.parseInt(n, 16)).toString(16)}`, c = {};
|
|
37
|
+
t.bindings.forEach((n) => {
|
|
38
|
+
n.bind === "unicast" && n.report && n.report.forEach((s) => {
|
|
39
|
+
s.max !== 65535 && (c[`${o(n["src.ep"])}.${o(n.cl)}.${o(s.at)}`] = s.max);
|
|
39
40
|
});
|
|
40
|
-
}),
|
|
41
|
-
|
|
42
|
-
var
|
|
43
|
-
if (
|
|
44
|
-
const
|
|
45
|
-
for (let
|
|
46
|
-
const
|
|
47
|
-
|
|
41
|
+
}), t.subdevices.forEach((n, s) => {
|
|
42
|
+
n.items.forEach((i, d) => {
|
|
43
|
+
var m;
|
|
44
|
+
if (i["refresh.interval"] && i.read && i.read.fn === "zcl") {
|
|
45
|
+
const h = o(i.read.ep ?? ((m = n.fingerprint) == null ? void 0 : m.endpoint) ?? n.uuid[1]), b = Array.isArray(i.read.at) ? i.read.at : [i.read.at];
|
|
46
|
+
for (let v = 0; v < b.length; v++) {
|
|
47
|
+
const g = `${h}.${o(i.read.cl)}.${o(b[v])}`;
|
|
48
|
+
c[g] !== void 0 && i["refresh.interval"] - 60 < c[g] && r.addIssue({
|
|
48
49
|
code: e.ZodIssueCode.custom,
|
|
49
|
-
message: `The refresh interval (${
|
|
50
|
-
path: ["subdevices",
|
|
50
|
+
message: `The refresh interval (${i["refresh.interval"]} - 60 = ${i["refresh.interval"] - 60}) should be greater than the binding max refresh value (${c[g]}) with a margin of 60 seconds`,
|
|
51
|
+
path: ["subdevices", s, "items", d, "refresh.interval"]
|
|
51
52
|
});
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
});
|
|
55
56
|
});
|
|
56
57
|
}
|
|
57
|
-
function
|
|
58
|
-
if (!
|
|
58
|
+
function w(t, r, f) {
|
|
59
|
+
if (!t.bindings)
|
|
59
60
|
return;
|
|
60
61
|
const o = [
|
|
61
62
|
/*
|
|
@@ -138,72 +139,93 @@ function E(a, i) {
|
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
];
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
o.forEach((
|
|
144
|
-
(Object.keys(
|
|
145
|
-
var
|
|
146
|
-
switch (
|
|
142
|
+
t.subdevices.forEach((c, n) => {
|
|
143
|
+
const s = c.items.map((i) => i.name);
|
|
144
|
+
o.forEach((i) => {
|
|
145
|
+
(Object.keys(i.if).length === 0 || Object.keys(i.if).some((d) => {
|
|
146
|
+
var m;
|
|
147
|
+
switch (d) {
|
|
147
148
|
case "type":
|
|
148
|
-
return (
|
|
149
|
+
return (m = i.if[d]) == null ? void 0 : m.includes(c.type);
|
|
149
150
|
case "item":
|
|
150
|
-
return
|
|
151
|
-
var
|
|
152
|
-
return (
|
|
151
|
+
return s.some((h) => {
|
|
152
|
+
var b;
|
|
153
|
+
return (b = i.if[d]) == null ? void 0 : b.includes(h);
|
|
153
154
|
});
|
|
154
155
|
default:
|
|
155
156
|
return !1;
|
|
156
157
|
}
|
|
157
|
-
})) &&
|
|
158
|
-
|
|
158
|
+
})) && i.need.item.forEach((d) => {
|
|
159
|
+
s.includes(d) || r.addIssue({
|
|
159
160
|
code: e.ZodIssueCode.custom,
|
|
160
|
-
message: `The device should have the item "${
|
|
161
|
-
path: ["subdevices",
|
|
161
|
+
message: `The device should have the item "${d}" because ${i.description}`,
|
|
162
|
+
path: ["subdevices", n, "items"]
|
|
162
163
|
});
|
|
163
164
|
});
|
|
164
165
|
});
|
|
165
166
|
});
|
|
166
167
|
}
|
|
167
|
-
function
|
|
168
|
+
function $(t, r, f) {
|
|
168
169
|
const o = ["parse", "write"];
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
o.forEach((
|
|
172
|
-
const
|
|
173
|
-
|
|
170
|
+
t.subdevices.forEach((c, n) => {
|
|
171
|
+
c.items.forEach((s, i) => {
|
|
172
|
+
o.forEach((d) => {
|
|
173
|
+
const m = s[d];
|
|
174
|
+
m !== void 0 && (m.fn === void 0 || m.fn === "zcl" || m.fn === "zcl:attr" || m.fn === "zcl:cmd") && (m.eval === void 0 && m.script === void 0 && r.addIssue({
|
|
174
175
|
code: e.ZodIssueCode.custom,
|
|
175
|
-
message: `The '${
|
|
176
|
-
path: ["subdevices",
|
|
177
|
-
}),
|
|
176
|
+
message: `The '${d}' function is missing 'eval' or 'script' option.`,
|
|
177
|
+
path: ["subdevices", n, "items", i, d]
|
|
178
|
+
}), m.eval !== void 0 && m.script !== void 0 && r.addIssue({
|
|
178
179
|
code: e.ZodIssueCode.custom,
|
|
179
|
-
message: `The '${
|
|
180
|
-
path: ["subdevices",
|
|
180
|
+
message: `The '${d}' function is having both 'eval' and 'script' option.`,
|
|
181
|
+
path: ["subdevices", n, "items", i, d]
|
|
181
182
|
}));
|
|
182
183
|
});
|
|
183
184
|
});
|
|
184
185
|
});
|
|
185
186
|
}
|
|
186
|
-
function
|
|
187
|
-
const o =
|
|
188
|
-
Object.keys(
|
|
189
|
-
if (!Object.keys(o.shape).includes(
|
|
190
|
-
if (!["$MF_", "$TYPE_"].some((
|
|
191
|
-
|
|
187
|
+
function _(t, r, f) {
|
|
188
|
+
const o = I();
|
|
189
|
+
Object.keys(t).forEach((c) => {
|
|
190
|
+
if (!Object.keys(o.shape).includes(c)) {
|
|
191
|
+
if (!["$MF_", "$TYPE_"].some((n) => c.startsWith(n))) {
|
|
192
|
+
r.addIssue({
|
|
192
193
|
code: e.ZodIssueCode.custom,
|
|
193
194
|
message: "The constant key should start with '$MF_' or '$TYPE_'",
|
|
194
|
-
path: [
|
|
195
|
+
path: [c]
|
|
195
196
|
});
|
|
196
197
|
return;
|
|
197
198
|
}
|
|
198
|
-
typeof
|
|
199
|
+
typeof t[c] != "string" && r.addIssue({
|
|
199
200
|
code: e.ZodIssueCode.custom,
|
|
200
201
|
message: "The constant value should be a string",
|
|
201
|
-
path: [
|
|
202
|
+
path: [c]
|
|
202
203
|
});
|
|
203
204
|
}
|
|
204
205
|
});
|
|
205
206
|
}
|
|
206
|
-
function
|
|
207
|
+
function C(t, r, f) {
|
|
208
|
+
t.bindings && t.subdevices.forEach((o, c) => {
|
|
209
|
+
const n = f.subDevices[o.type];
|
|
210
|
+
if (!n) {
|
|
211
|
+
r.addIssue({
|
|
212
|
+
code: e.ZodIssueCode.custom,
|
|
213
|
+
message: `The device is missing the device definition for the type "${o.type}"`,
|
|
214
|
+
path: ["subdevices", c, "items"]
|
|
215
|
+
});
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
let s = n.items;
|
|
219
|
+
n.items_optional && (s = s.filter((i) => !n.items_optional.includes(i))), s.forEach((i) => {
|
|
220
|
+
o.items.find((d) => d.name === i) || r.addIssue({
|
|
221
|
+
code: e.ZodIssueCode.custom,
|
|
222
|
+
message: `The device should have the item "${i}" because it is mandatory for devices of type "${o.type}"`,
|
|
223
|
+
path: ["subdevices", c, "items"]
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
function A(t) {
|
|
207
229
|
return e.strictObject({
|
|
208
230
|
$schema: e.optional(e.string()),
|
|
209
231
|
schema: e.literal("constants1.schema.json"),
|
|
@@ -211,36 +233,36 @@ function $(a) {
|
|
|
211
233
|
"device-types": e.record(e.string().startsWith("$TYPE_"), e.string())
|
|
212
234
|
});
|
|
213
235
|
}
|
|
214
|
-
function
|
|
236
|
+
function I(t) {
|
|
215
237
|
return e.object({
|
|
216
238
|
$schema: e.optional(e.string()),
|
|
217
239
|
schema: e.literal("constants2.schema.json")
|
|
218
240
|
}).passthrough();
|
|
219
241
|
}
|
|
220
|
-
function
|
|
242
|
+
function S() {
|
|
221
243
|
return e.string().regex(
|
|
222
244
|
// Regex for AAAA-MM-JJ
|
|
223
245
|
/^(\d{4})-(?:(?:0[1-9])|(?:1[0-2]))-(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01]))$/,
|
|
224
246
|
"Invalid date value"
|
|
225
247
|
);
|
|
226
248
|
}
|
|
227
|
-
function t
|
|
228
|
-
const
|
|
229
|
-
return
|
|
249
|
+
function a(t = void 0) {
|
|
250
|
+
const r = "Invalid hexadecimal value";
|
|
251
|
+
return t === void 0 ? e.string().regex(/^0x[0-9a-fA-F]+$/, r) : e.string().regex(new RegExp(`^0x[0-9a-fA-F]{${t}}$`), r);
|
|
230
252
|
}
|
|
231
253
|
function u() {
|
|
232
254
|
return e.union([
|
|
233
|
-
|
|
255
|
+
a(2),
|
|
234
256
|
e.number().min(0).max(255)
|
|
235
257
|
]);
|
|
236
258
|
}
|
|
237
|
-
function
|
|
238
|
-
return e.custom((
|
|
239
|
-
if (!Array.isArray(
|
|
259
|
+
function J() {
|
|
260
|
+
return e.custom((t) => {
|
|
261
|
+
if (!Array.isArray(t) || t.length % 2 !== 0)
|
|
240
262
|
return !1;
|
|
241
|
-
for (let
|
|
242
|
-
const
|
|
243
|
-
if (typeof
|
|
263
|
+
for (let r = 0; r < t.length; r += 2) {
|
|
264
|
+
const f = t[r], o = t[r + 1];
|
|
265
|
+
if (typeof f != "number" || typeof o != "string")
|
|
244
266
|
return !1;
|
|
245
267
|
}
|
|
246
268
|
return !0;
|
|
@@ -250,12 +272,12 @@ function j() {
|
|
|
250
272
|
return e.union([
|
|
251
273
|
e.tuple([
|
|
252
274
|
e.literal("$address.ext"),
|
|
253
|
-
|
|
275
|
+
a(2)
|
|
254
276
|
]),
|
|
255
277
|
e.tuple([
|
|
256
278
|
e.literal("$address.ext"),
|
|
257
|
-
|
|
258
|
-
|
|
279
|
+
a(2),
|
|
280
|
+
a(4)
|
|
259
281
|
])
|
|
260
282
|
]);
|
|
261
283
|
}
|
|
@@ -265,92 +287,92 @@ function p() {
|
|
|
265
287
|
function l() {
|
|
266
288
|
return e.string();
|
|
267
289
|
}
|
|
268
|
-
function
|
|
290
|
+
function M() {
|
|
269
291
|
return e.discriminatedUnion("fn", [
|
|
270
292
|
e.strictObject({
|
|
271
293
|
fn: e.literal("none")
|
|
272
294
|
}),
|
|
273
295
|
e.strictObject({
|
|
274
296
|
fn: e.undefined().describe("Generic function to read ZCL attributes."),
|
|
275
|
-
at:
|
|
276
|
-
cl:
|
|
297
|
+
at: a(4).or(e.array(a(4))).describe("Attribute ID."),
|
|
298
|
+
cl: a(4).describe("Cluster ID."),
|
|
277
299
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
278
|
-
mf: e.optional(
|
|
300
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
279
301
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value.")
|
|
280
302
|
}),
|
|
281
303
|
e.strictObject({
|
|
282
304
|
fn: e.literal("zcl").describe("Generic function to read ZCL attributes."),
|
|
283
|
-
at:
|
|
284
|
-
cl:
|
|
305
|
+
at: a(4).or(e.array(a(4))).describe("Attribute ID."),
|
|
306
|
+
cl: a(4).describe("Cluster ID."),
|
|
285
307
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
286
|
-
mf: e.optional(
|
|
308
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
287
309
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value."),
|
|
288
310
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
289
311
|
}).describe("Deprecated"),
|
|
290
312
|
e.strictObject({
|
|
291
313
|
fn: e.literal("zcl:attr").describe("Generic function to parse ZCL values from read/report commands."),
|
|
292
|
-
at:
|
|
293
|
-
cl:
|
|
314
|
+
at: a(4).or(e.array(a(4))).describe("String hex value or array of string hex values."),
|
|
315
|
+
cl: a(4).describe("Cluster ID."),
|
|
294
316
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
295
|
-
mf: e.optional(
|
|
317
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
296
318
|
eval: e.optional(l()).describe("Javascript expression to transform the attribute value to the Item value."),
|
|
297
319
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
298
320
|
}),
|
|
299
321
|
e.strictObject({
|
|
300
322
|
fn: e.literal("zcl:cmd").describe("Generic function to parse ZCL values from read/report commands."),
|
|
301
|
-
cl:
|
|
323
|
+
cl: a(4).describe("Cluster ID."),
|
|
302
324
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
303
|
-
mf: e.optional(
|
|
304
|
-
cmd: e.optional(
|
|
325
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
326
|
+
cmd: e.optional(a(2)).describe("Zigbee command."),
|
|
305
327
|
eval: e.optional(l()).describe("Javascript expression to transform the attribute value to the Item value."),
|
|
306
328
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
307
329
|
}),
|
|
308
330
|
e.strictObject({
|
|
309
331
|
fn: e.literal("tuya").describe("Generic function to read all Tuya datapoints. It has no parameters.")
|
|
310
332
|
})
|
|
311
|
-
]).refine((
|
|
333
|
+
]).refine((t) => !("eval" in t && "script" in t), {
|
|
312
334
|
message: "eval and script should not both be present"
|
|
313
335
|
});
|
|
314
336
|
}
|
|
315
|
-
function
|
|
337
|
+
function Z() {
|
|
316
338
|
return e.discriminatedUnion("fn", [
|
|
317
339
|
e.strictObject({
|
|
318
340
|
fn: e.undefined().describe("Generic function to parse ZCL attributes and commands."),
|
|
319
|
-
at: e.optional(
|
|
320
|
-
cl:
|
|
341
|
+
at: e.optional(a(4).or(e.array(a(4)))).describe("Attribute ID."),
|
|
342
|
+
cl: a(4).describe("Cluster ID."),
|
|
321
343
|
cppsrc: e.optional(e.string()),
|
|
322
344
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
323
|
-
cmd: e.optional(
|
|
324
|
-
mf: e.optional(
|
|
345
|
+
cmd: e.optional(a(2)).describe("Zigbee command."),
|
|
346
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
325
347
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value."),
|
|
326
348
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
327
349
|
}),
|
|
328
350
|
e.strictObject({
|
|
329
351
|
fn: e.literal("zcl").describe("Generic function to parse ZCL attributes and commands."),
|
|
330
|
-
at: e.optional(
|
|
331
|
-
cl:
|
|
352
|
+
at: e.optional(a(4).or(e.array(a(4)))).describe("Attribute ID."),
|
|
353
|
+
cl: a(4).describe("Cluster ID."),
|
|
332
354
|
cppsrc: e.optional(e.string()),
|
|
333
355
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
334
|
-
cmd: e.optional(
|
|
335
|
-
mf: e.optional(
|
|
356
|
+
cmd: e.optional(a(2)).describe("Zigbee command."),
|
|
357
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
336
358
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value."),
|
|
337
359
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
338
360
|
}).describe("Deprecated"),
|
|
339
361
|
e.strictObject({
|
|
340
362
|
fn: e.literal("zcl:attr").describe("Generic function to parse ZCL values from read/report commands."),
|
|
341
|
-
at:
|
|
342
|
-
cl:
|
|
363
|
+
at: a(4).or(e.array(a(4))).describe("String hex value or array of string hex values."),
|
|
364
|
+
cl: a(4).describe("Cluster ID."),
|
|
343
365
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
344
|
-
mf: e.optional(
|
|
366
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
345
367
|
eval: e.optional(l()).describe("Javascript expression to transform the attribute value to the Item value."),
|
|
346
368
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
347
369
|
}),
|
|
348
370
|
e.strictObject({
|
|
349
371
|
fn: e.literal("zcl:cmd").describe("Generic function to parse ZCL values from read/report commands."),
|
|
350
|
-
cl:
|
|
372
|
+
cl: a(4).describe("Cluster ID."),
|
|
351
373
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
352
|
-
mf: e.optional(
|
|
353
|
-
cmd: e.optional(
|
|
374
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
375
|
+
cmd: e.optional(a(2)).describe("Zigbee command."),
|
|
354
376
|
eval: e.optional(l()).describe("Javascript expression to transform the attribute value to the Item value."),
|
|
355
377
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
356
378
|
}),
|
|
@@ -363,7 +385,7 @@ function S() {
|
|
|
363
385
|
// TODO use generic
|
|
364
386
|
srcitem: e.enum(["state/airqualityppb", "state/pm2_5"]).describe("The source item holding the number."),
|
|
365
387
|
op: e.enum(["lt", "le", "eq", "gt", "ge"]).describe("Comparison operator (lt | le | eq | gt | ge)"),
|
|
366
|
-
to:
|
|
388
|
+
to: J().describe("Array of (num, string) mappings")
|
|
367
389
|
}),
|
|
368
390
|
e.strictObject({
|
|
369
391
|
fn: e.literal("time").describe("Specialized function to parse time, local and last set time from read/report commands of the time cluster and auto-sync time if needed.")
|
|
@@ -371,9 +393,9 @@ function S() {
|
|
|
371
393
|
e.strictObject({
|
|
372
394
|
fn: e.literal("xiaomi:special").describe("Generic function to parse custom Xiaomi attributes and commands."),
|
|
373
395
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
374
|
-
mf: e.optional(
|
|
375
|
-
at: e.optional(
|
|
376
|
-
idx:
|
|
396
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
397
|
+
at: e.optional(a(4)).describe("Attribute ID. The attribute to parse, shall be 0xff01, 0xff02 or 0x00f7"),
|
|
398
|
+
idx: a(2).describe("A 8-bit string hex value."),
|
|
377
399
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value."),
|
|
378
400
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
379
401
|
}),
|
|
@@ -383,80 +405,80 @@ function S() {
|
|
|
383
405
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value."),
|
|
384
406
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
385
407
|
})
|
|
386
|
-
]).refine((
|
|
408
|
+
]).refine((t) => !("eval" in t && "script" in t), {
|
|
387
409
|
message: "eval and script should not both be present"
|
|
388
410
|
});
|
|
389
411
|
}
|
|
390
|
-
function
|
|
412
|
+
function R() {
|
|
391
413
|
return e.discriminatedUnion("fn", [
|
|
392
414
|
e.strictObject({
|
|
393
415
|
fn: e.literal("none")
|
|
394
416
|
}),
|
|
395
417
|
e.strictObject({
|
|
396
418
|
fn: e.undefined(),
|
|
397
|
-
at: e.optional(
|
|
419
|
+
at: e.optional(a(4).or(e.array(a(4)))).describe("Attribute ID."),
|
|
398
420
|
"state.timeout": e.optional(e.number()),
|
|
399
421
|
"change.timeout": e.optional(e.number()),
|
|
400
|
-
cl:
|
|
401
|
-
dt:
|
|
422
|
+
cl: a(4).describe("Cluster ID."),
|
|
423
|
+
dt: a(2).describe("Data type."),
|
|
402
424
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
403
|
-
mf: e.optional(
|
|
425
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
404
426
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value."),
|
|
405
427
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
406
428
|
}),
|
|
407
429
|
e.strictObject({
|
|
408
430
|
fn: e.literal("zcl"),
|
|
409
|
-
at: e.optional(
|
|
431
|
+
at: e.optional(a(4).or(e.array(a(4)))).describe("Attribute ID."),
|
|
410
432
|
"state.timeout": e.optional(e.number()),
|
|
411
433
|
"change.timeout": e.optional(e.number()),
|
|
412
|
-
cl:
|
|
413
|
-
dt:
|
|
434
|
+
cl: a(4).describe("Cluster ID."),
|
|
435
|
+
dt: a(2).describe("Data type."),
|
|
414
436
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
415
|
-
mf: e.optional(
|
|
437
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
416
438
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value."),
|
|
417
439
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
418
440
|
}).describe("Deprecated"),
|
|
419
441
|
e.strictObject({
|
|
420
442
|
fn: e.literal("zcl:attr").describe("Generic function to parse ZCL values from read/report commands."),
|
|
421
|
-
at:
|
|
443
|
+
at: a(4).or(e.array(a(4))).describe("String hex value or array of string hex values."),
|
|
422
444
|
"state.timeout": e.optional(e.number()),
|
|
423
445
|
"change.timeout": e.optional(e.number()),
|
|
424
|
-
cl:
|
|
425
|
-
dt:
|
|
446
|
+
cl: a(4).describe("Cluster ID."),
|
|
447
|
+
dt: a(2).describe("Data type."),
|
|
426
448
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
427
|
-
mf: e.optional(
|
|
449
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
428
450
|
eval: e.optional(l()).describe("Javascript expression to transform the attribute value to the Item value."),
|
|
429
451
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
430
452
|
}),
|
|
431
453
|
e.strictObject({
|
|
432
454
|
fn: e.literal("zcl:cmd").describe("Generic function to parse ZCL values from read/report commands."),
|
|
433
|
-
cl:
|
|
434
|
-
dt:
|
|
455
|
+
cl: a(4).describe("Cluster ID."),
|
|
456
|
+
dt: a(2).describe("Data type."),
|
|
435
457
|
ep: e.optional(u()).describe("Endpoint, 255 means any endpoint, 0 means auto selected from subdevice."),
|
|
436
|
-
mf: e.optional(
|
|
437
|
-
cmd: e.optional(
|
|
458
|
+
mf: e.optional(a(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
|
|
459
|
+
cmd: e.optional(a(2)).describe("Zigbee command."),
|
|
438
460
|
eval: e.optional(l()).describe("Javascript expression to transform the attribute value to the Item value."),
|
|
439
461
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
440
462
|
}),
|
|
441
463
|
e.strictObject({
|
|
442
464
|
fn: e.literal("tuya").describe("Generic function to write Tuya data."),
|
|
443
465
|
dpid: e.number().describe("Data point ID. 1-255 the datapoint ID."),
|
|
444
|
-
dt:
|
|
466
|
+
dt: a(2).describe("Data type."),
|
|
445
467
|
eval: e.optional(l()).describe("Javascript expression to transform the raw value."),
|
|
446
468
|
script: e.optional(p()).describe("Relative path of a Javascript .js file.")
|
|
447
469
|
})
|
|
448
|
-
]).refine((
|
|
470
|
+
]).refine((t) => !("eval" in t && "script" in t), {
|
|
449
471
|
message: "eval and script should not both be present"
|
|
450
472
|
});
|
|
451
473
|
}
|
|
452
|
-
function
|
|
474
|
+
function D(t) {
|
|
453
475
|
return e.strictObject({
|
|
454
476
|
$schema: e.optional(e.string()),
|
|
455
477
|
schema: e.literal("resourceitem1.schema.json"),
|
|
456
478
|
id: e.string(),
|
|
457
479
|
description: e.optional(e.string()).describe("Item description, better to do not use it."),
|
|
458
480
|
comment: e.optional(e.string()).describe("TODO: What is this ? What the difference with description ?"),
|
|
459
|
-
deprecated: e.optional(
|
|
481
|
+
deprecated: e.optional(S()).describe("Date of deprecation, if the item is deprecated, it's better to use the new one."),
|
|
460
482
|
datatype: e.optional(e.enum(["String", "Bool", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Double", "Array", "Array[3]", "ISO 8601 timestamp"])).describe("Data type of the item."),
|
|
461
483
|
access: e.optional(e.enum(["R", "W", "RW"])).describe("Access mode for this item, some of them are not editable."),
|
|
462
484
|
public: e.optional(e.boolean()).describe("Item visible on the API."),
|
|
@@ -466,9 +488,9 @@ function I(a) {
|
|
|
466
488
|
static: e.optional(e.union([e.string(), e.number(), e.boolean()])).describe("A static default value is fixed and can be not changed."),
|
|
467
489
|
range: e.optional(e.tuple([e.number(), e.number()])).describe("Values range limit."),
|
|
468
490
|
virtual: e.optional(e.boolean()).describe("TODO: What is this ?"),
|
|
469
|
-
read: e.optional(
|
|
470
|
-
parse: e.optional(
|
|
471
|
-
write: e.optional(
|
|
491
|
+
read: e.optional(M()).describe("Fonction used to read value."),
|
|
492
|
+
parse: e.optional(Z()).describe("Fonction used to parse incoming values."),
|
|
493
|
+
write: e.optional(R()).describe("Fonction used to write value."),
|
|
472
494
|
"refresh.interval": e.optional(e.number()).describe("Refresh interval used for read fonction, NEED to be superior at value used in binding part."),
|
|
473
495
|
// TODO Validate this
|
|
474
496
|
values: e.optional(e.unknown()).describe("TODO: What is this ?"),
|
|
@@ -476,7 +498,7 @@ function I(a) {
|
|
|
476
498
|
default: e.optional(e.unknown()).describe("Defaut value.")
|
|
477
499
|
});
|
|
478
500
|
}
|
|
479
|
-
function
|
|
501
|
+
function G(t) {
|
|
480
502
|
return e.strictObject({
|
|
481
503
|
$schema: e.optional(e.string()),
|
|
482
504
|
schema: e.literal("devcap1.schema.json"),
|
|
@@ -487,11 +509,11 @@ function M(a) {
|
|
|
487
509
|
"doc:hdr": e.optional(e.string()),
|
|
488
510
|
"md:known_issues": e.optional(e.array(e.string())).describe("Know issues for this device, markdown file."),
|
|
489
511
|
manufacturername: e.union([
|
|
490
|
-
e.enum(Object.keys(
|
|
512
|
+
e.enum(Object.keys(t.manufacturers)),
|
|
491
513
|
e.string().regex(/^(?!\$MF_).*/g, "The manufacturer name start with $MF_ but is not present in constants.json"),
|
|
492
514
|
e.array(
|
|
493
515
|
e.union([
|
|
494
|
-
e.enum(Object.keys(
|
|
516
|
+
e.enum(Object.keys(t.manufacturers)),
|
|
495
517
|
e.string().regex(/^(?!\$MF_).*/g, "The manufacturer name start with $MF_ but is not present in constants.json")
|
|
496
518
|
])
|
|
497
519
|
)
|
|
@@ -505,24 +527,24 @@ function M(a) {
|
|
|
505
527
|
sleeper: e.optional(e.boolean()).describe("Sleeping devices can only receive when awake."),
|
|
506
528
|
supportsMgmtBind: e.optional(e.boolean()),
|
|
507
529
|
status: e.enum(["Draft", "Bronze", "Silver", "Gold"]).describe("The code quality of the DDF file."),
|
|
508
|
-
subdevices: e.array(
|
|
509
|
-
bindings: e.optional(e.array(
|
|
530
|
+
subdevices: e.array(F(t)).describe("Devices section."),
|
|
531
|
+
bindings: e.optional(e.array(z())).describe("Bindings section.")
|
|
510
532
|
});
|
|
511
533
|
}
|
|
512
|
-
function
|
|
534
|
+
function F(t) {
|
|
513
535
|
return e.strictObject({
|
|
514
536
|
type: e.union([
|
|
515
|
-
e.enum(Object.keys(
|
|
537
|
+
e.enum(Object.keys(t.deviceTypes)),
|
|
516
538
|
e.string().regex(/^(?!\$TYPE_).*/g, "The type start with $TYPE_ but is not present in constants.json")
|
|
517
539
|
]),
|
|
518
540
|
restapi: e.enum(["/lights", "/sensors"]),
|
|
519
541
|
uuid: j(),
|
|
520
542
|
fingerprint: e.optional(e.strictObject({
|
|
521
|
-
profile:
|
|
522
|
-
device:
|
|
543
|
+
profile: a(4),
|
|
544
|
+
device: a(4),
|
|
523
545
|
endpoint: u(),
|
|
524
|
-
in: e.optional(e.array(
|
|
525
|
-
out: e.optional(e.array(
|
|
546
|
+
in: e.optional(e.array(a(4))),
|
|
547
|
+
out: e.optional(e.array(a(4)))
|
|
526
548
|
})),
|
|
527
549
|
meta: e.optional(e.strictObject({
|
|
528
550
|
// TODO validate this
|
|
@@ -533,123 +555,126 @@ function R(a) {
|
|
|
533
555
|
buttons: e.optional(e.any()),
|
|
534
556
|
// TODO validate this
|
|
535
557
|
buttonevents: e.optional(e.any()),
|
|
536
|
-
items: e.array(
|
|
558
|
+
items: e.array(k(t)),
|
|
537
559
|
example: e.optional(e.unknown())
|
|
538
560
|
});
|
|
539
561
|
}
|
|
540
|
-
function
|
|
541
|
-
return
|
|
562
|
+
function k(t) {
|
|
563
|
+
return D().omit({
|
|
542
564
|
$schema: !0,
|
|
543
565
|
schema: !0,
|
|
544
566
|
id: !0
|
|
545
567
|
}).extend({
|
|
546
|
-
name: e.enum(
|
|
568
|
+
name: e.enum(t.attributes).describe("Item name.")
|
|
547
569
|
});
|
|
548
570
|
}
|
|
549
|
-
function
|
|
571
|
+
function z(t) {
|
|
550
572
|
return e.discriminatedUnion("bind", [
|
|
551
573
|
e.strictObject({
|
|
552
574
|
bind: e.literal("unicast"),
|
|
553
575
|
"src.ep": u().describe("Source endpoint."),
|
|
554
576
|
"dst.ep": e.optional(u()).describe("Destination endpoint, generaly 0x01."),
|
|
555
|
-
cl:
|
|
577
|
+
cl: a(4).describe("Cluster."),
|
|
556
578
|
report: e.optional(e.array(
|
|
557
579
|
e.strictObject({
|
|
558
|
-
at:
|
|
559
|
-
dt:
|
|
560
|
-
mf: e.optional(
|
|
580
|
+
at: a(4),
|
|
581
|
+
dt: a(2),
|
|
582
|
+
mf: e.optional(a(4)),
|
|
561
583
|
min: e.number(),
|
|
562
584
|
max: e.number(),
|
|
563
|
-
change: e.optional(
|
|
564
|
-
}).refine((
|
|
585
|
+
change: e.optional(a().or(e.number()))
|
|
586
|
+
}).refine((r) => r.min <= r.max, { message: "invalid report time, min should be smaller than max" })
|
|
565
587
|
))
|
|
566
588
|
}),
|
|
567
589
|
e.strictObject({
|
|
568
590
|
bind: e.literal("groupcast"),
|
|
569
591
|
"src.ep": u().describe("Source endpoint."),
|
|
570
|
-
cl:
|
|
592
|
+
cl: a(4).describe("Cluster."),
|
|
571
593
|
"config.group": e.number().min(0).max(255)
|
|
572
594
|
})
|
|
573
595
|
]);
|
|
574
596
|
}
|
|
575
|
-
function
|
|
597
|
+
function L(t) {
|
|
576
598
|
return e.strictObject({
|
|
577
599
|
$schema: e.optional(e.string()),
|
|
578
600
|
schema: e.literal("subdevice1.schema.json"),
|
|
579
601
|
type: e.union([
|
|
580
|
-
e.enum(Object.keys(
|
|
602
|
+
e.enum(Object.keys(t.deviceTypes)),
|
|
581
603
|
e.string().regex(/^(?!\$TYPE_).*/g, "The type start with $TYPE_ but is not present in constants.json")
|
|
582
604
|
]),
|
|
583
605
|
name: e.string(),
|
|
584
606
|
restapi: e.enum(["/lights", "/sensors"]),
|
|
585
607
|
order: e.number(),
|
|
586
608
|
uuid: j(),
|
|
587
|
-
items: e.array(e.enum(
|
|
609
|
+
items: e.array(e.enum(t.attributes)),
|
|
610
|
+
items_optional: e.optional(e.array(e.enum(t.attributes)))
|
|
588
611
|
});
|
|
589
612
|
}
|
|
590
|
-
function
|
|
613
|
+
function x(t) {
|
|
591
614
|
return e.discriminatedUnion("schema", [
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
x(),
|
|
615
|
+
G(t),
|
|
616
|
+
A(),
|
|
595
617
|
I(),
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
618
|
+
D(),
|
|
619
|
+
L(t)
|
|
620
|
+
]).superRefine((r, f) => {
|
|
621
|
+
switch (r.schema) {
|
|
599
622
|
case "devcap1.schema.json":
|
|
600
|
-
|
|
623
|
+
y[r.schema].map((o) => o(r, f, t));
|
|
601
624
|
break;
|
|
602
625
|
case "constants2.schema.json":
|
|
603
|
-
|
|
626
|
+
y[r.schema].map((o) => o(r, f, t));
|
|
604
627
|
break;
|
|
605
628
|
}
|
|
606
629
|
});
|
|
607
630
|
}
|
|
608
|
-
function
|
|
631
|
+
function W(t = {
|
|
609
632
|
attributes: [],
|
|
610
633
|
manufacturers: {},
|
|
611
634
|
deviceTypes: {},
|
|
612
|
-
resources: {}
|
|
635
|
+
resources: {},
|
|
636
|
+
subDevices: {}
|
|
613
637
|
}) {
|
|
614
|
-
let
|
|
615
|
-
const
|
|
616
|
-
|
|
638
|
+
let r = x(t);
|
|
639
|
+
const f = () => {
|
|
640
|
+
r = x(t);
|
|
617
641
|
};
|
|
618
|
-
return { generics:
|
|
619
|
-
const
|
|
620
|
-
switch (
|
|
642
|
+
return { generics: t, loadGeneric: (n) => {
|
|
643
|
+
const s = r.parse(n);
|
|
644
|
+
switch (s.schema) {
|
|
621
645
|
case "constants1.schema.json":
|
|
622
|
-
|
|
623
|
-
...
|
|
624
|
-
...
|
|
625
|
-
},
|
|
626
|
-
...
|
|
627
|
-
...
|
|
646
|
+
t.manufacturers = {
|
|
647
|
+
...t.manufacturers,
|
|
648
|
+
...s.manufacturers
|
|
649
|
+
}, t.deviceTypes = {
|
|
650
|
+
...t.deviceTypes,
|
|
651
|
+
...s["device-types"]
|
|
628
652
|
};
|
|
629
653
|
break;
|
|
630
654
|
case "constants2.schema.json": {
|
|
631
|
-
Object.keys(
|
|
632
|
-
|
|
633
|
-
}), Object.keys(
|
|
634
|
-
|
|
655
|
+
Object.keys(s).filter((i) => i.startsWith("$MF_")).forEach((i) => {
|
|
656
|
+
t.manufacturers[i] = s[i];
|
|
657
|
+
}), Object.keys(s).filter((i) => i.startsWith("$TYPE_")).forEach((i) => {
|
|
658
|
+
t.deviceTypes[i] = s[i];
|
|
635
659
|
});
|
|
636
660
|
break;
|
|
637
661
|
}
|
|
638
662
|
case "resourceitem1.schema.json": {
|
|
639
|
-
if (
|
|
640
|
-
throw new Error(`Got duplicate resource item with attribute id '${
|
|
641
|
-
const
|
|
642
|
-
delete
|
|
663
|
+
if (t.attributes.includes(s.id))
|
|
664
|
+
throw new Error(`Got duplicate resource item with attribute id '${s.id}'.`);
|
|
665
|
+
const i = s, d = s.id;
|
|
666
|
+
delete i.$schema, delete i.schema, delete i.id, t.resources[d] = i, t.attributes.push(d);
|
|
643
667
|
break;
|
|
644
668
|
}
|
|
645
669
|
case "subdevice1.schema.json":
|
|
670
|
+
t.subDevices[s.type] = s, t.subDevices[s.name] = s;
|
|
646
671
|
break;
|
|
647
672
|
case "devcap1.schema.json":
|
|
648
673
|
throw new Error("Got invalid generic file, got data with schema 'devcap1.schema.json'.");
|
|
649
674
|
}
|
|
650
|
-
return
|
|
651
|
-
}, validate: (
|
|
675
|
+
return f(), !0;
|
|
676
|
+
}, validate: (n) => r.parse(n), getSchema: () => r, version: O };
|
|
652
677
|
}
|
|
653
678
|
export {
|
|
654
|
-
|
|
679
|
+
W as createValidator
|
|
655
680
|
};
|