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