@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.
@@ -1,61 +1,62 @@
1
1
  import { z as e } from "zod";
2
- const g = {
2
+ const O = "2.12.0", y = {
3
3
  "devcap1.schema.json": [
4
- D,
5
- O,
6
4
  E,
7
- w
5
+ T,
6
+ w,
7
+ $,
8
+ C
8
9
  ],
9
10
  "constants2.schema.json": [
10
- T
11
+ _
11
12
  ]
12
13
  };
13
- function D(a, i) {
14
- const o = typeof a.manufacturername == "string" && typeof a.modelid == "string";
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 s = Array.isArray(a.manufacturername) && Array.isArray(a.modelid);
18
- if (s && a.manufacturername.length !== a.modelid.length) {
19
- i.addIssue({
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 || s) === !1 && i.addIssue({
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 O(a, i) {
33
- if (!a.bindings)
33
+ function T(t, r, f) {
34
+ if (!t.bindings)
34
35
  return;
35
- const o = (c) => `0x${(typeof c == "number" ? c : Number.parseInt(c, 16)).toString(16)}`, s = {};
36
- a.bindings.forEach((c) => {
37
- c.bind === "unicast" && c.report && c.report.forEach((p) => {
38
- p.max !== 65535 && (s[`${o(c["src.ep"])}.${o(c.cl)}.${o(p.at)}`] = p.max);
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
- }), a.subdevices.forEach((c, p) => {
41
- c.items.forEach((r, n) => {
42
- var d;
43
- if (r["refresh.interval"] && r.read && r.read.fn === "zcl") {
44
- const b = o(r.read.ep ?? ((d = c.fingerprint) == null ? void 0 : d.endpoint) ?? c.uuid[1]), f = Array.isArray(r.read.at) ? r.read.at : [r.read.at];
45
- for (let h = 0; h < f.length; h++) {
46
- const v = `${b}.${o(r.read.cl)}.${o(f[h])}`;
47
- s[v] !== void 0 && r["refresh.interval"] - 60 < s[v] && i.addIssue({
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 (${r["refresh.interval"]} - 60 = ${r["refresh.interval"] - 60}) should be greater than the binding max refresh value (${s[v]}) with a margin of 60 seconds`,
50
- path: ["subdevices", p, "items", n, "refresh.interval"]
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 E(a, i) {
58
- if (!a.bindings)
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
- a.subdevices.forEach((s, c) => {
127
- const p = s.items.map((r) => r.name);
128
- o.forEach((r) => {
129
- (Object.keys(r.if).length === 0 || Object.keys(r.if).some((n) => {
130
- var d;
131
- switch (n) {
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 (d = r.if[n]) == null ? void 0 : d.includes(s.type);
149
+ return (m = i.if[d]) == null ? void 0 : m.includes(c.type);
134
150
  case "item":
135
- return p.some((b) => {
136
- var f;
137
- return (f = r.if[n]) == null ? void 0 : f.includes(b);
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
- })) && r.need.item.forEach((n) => {
143
- p.includes(n) || i.addIssue({
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 "${n}" because ${r.description}`,
146
- path: ["subdevices", c, "items"]
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 w(a, i) {
168
+ function $(t, r, f) {
153
169
  const o = ["parse", "write"];
154
- a.subdevices.forEach((s, c) => {
155
- s.items.forEach((p, r) => {
156
- o.forEach((n) => {
157
- const d = p[n];
158
- d !== void 0 && (d.fn === void 0 || d.fn === "zcl" || d.fn === "zcl:attr" || d.fn === "zcl:cmd") && (d.eval === void 0 && d.script === void 0 && i.addIssue({
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 '${n}' function is missing 'eval' or 'script' option.`,
161
- path: ["subdevices", c, "items", r, n]
162
- }), d.eval !== void 0 && d.script !== void 0 && i.addIssue({
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 '${n}' function is having both 'eval' and 'script' option.`,
165
- path: ["subdevices", c, "items", r, n]
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 T(a, i) {
172
- const o = x();
173
- Object.keys(a).forEach((s) => {
174
- if (!Object.keys(o.shape).includes(s)) {
175
- if (!["$MF_", "$TYPE_"].some((c) => s.startsWith(c))) {
176
- i.addIssue({
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: [s]
195
+ path: [c]
180
196
  });
181
197
  return;
182
198
  }
183
- typeof a[s] != "string" && i.addIssue({
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: [s]
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 $(a) {
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 x(a) {
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 C() {
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(a = void 0) {
213
- const i = "Invalid hexadecimal value";
214
- return a === void 0 ? e.string().regex(/^0x[0-9a-fA-F]+$/, i) : e.string().regex(new RegExp(`^0x[0-9a-fA-F]{${a}}$`), i);
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
- t(2),
255
+ a(2),
219
256
  e.number().min(0).max(255)
220
257
  ]);
221
258
  }
222
- function _() {
223
- return e.custom((a) => {
224
- if (!Array.isArray(a) || a.length % 2 !== 0)
259
+ function J() {
260
+ return e.custom((t) => {
261
+ if (!Array.isArray(t) || t.length % 2 !== 0)
225
262
  return !1;
226
- for (let i = 0; i < a.length; i += 2) {
227
- const o = a[i], s = a[i + 1];
228
- if (typeof o != "number" || typeof s != "string")
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
- t(2)
275
+ a(2)
239
276
  ]),
240
277
  e.tuple([
241
278
  e.literal("$address.ext"),
242
- t(2),
243
- t(4)
279
+ a(2),
280
+ a(4)
244
281
  ])
245
282
  ]);
246
283
  }
247
- function m() {
284
+ function p() {
248
285
  return e.string();
249
286
  }
250
287
  function l() {
251
288
  return e.string();
252
289
  }
253
- function A() {
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: t(4).or(e.array(t(4))).describe("Attribute ID."),
261
- cl: t(4).describe("Cluster ID."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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: t(4).or(e.array(t(4))).describe("Attribute ID."),
269
- cl: t(4).describe("Cluster ID."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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(m()).describe("Relative path of a Javascript .js file.")
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: t(4).or(e.array(t(4))).describe("String hex value or array of string hex values."),
278
- cl: t(4).describe("Cluster ID."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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(m()).describe("Relative path of a Javascript .js file.")
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: t(4).describe("Cluster ID."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
289
- cmd: e.optional(t(2)).describe("Zigbee command."),
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(m()).describe("Relative path of a Javascript .js file.")
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((a) => !("eval" in a && "script" in a), {
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 S() {
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(t(4).or(e.array(t(4)))).describe("Attribute ID."),
305
- cl: t(4).describe("Cluster ID."),
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(t(2)).describe("Zigbee command."),
309
- mf: e.optional(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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(m()).describe("Relative path of a Javascript .js file.")
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(t(4).or(e.array(t(4)))).describe("Attribute ID."),
316
- cl: t(4).describe("Cluster ID."),
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(t(2)).describe("Zigbee command."),
320
- mf: e.optional(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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(m()).describe("Relative path of a Javascript .js file.")
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: t(4).or(e.array(t(4))).describe("String hex value or array of string hex values."),
327
- cl: t(4).describe("Cluster ID."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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(m()).describe("Relative path of a Javascript .js file.")
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: t(4).describe("Cluster ID."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
338
- cmd: e.optional(t(2)).describe("Zigbee command."),
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(m()).describe("Relative path of a Javascript .js file.")
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: _().describe("Array of (num, string) mappings")
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
360
- at: e.optional(t(4)).describe("Attribute ID. The attribute to parse, shall be 0xff01, 0xff02 or 0x00f7"),
361
- idx: t(2).describe("A 8-bit string hex value."),
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(m()).describe("Relative path of a Javascript .js file.")
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(m()).describe("Relative path of a Javascript .js file.")
406
+ script: e.optional(p()).describe("Relative path of a Javascript .js file.")
370
407
  })
371
- ]).refine((a) => !("eval" in a && "script" in a), {
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 J() {
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(t(4).or(e.array(t(4)))).describe("Attribute ID."),
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: t(4).describe("Cluster ID."),
386
- dt: t(2).describe("Data type."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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(m()).describe("Relative path of a Javascript .js file.")
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(t(4).or(e.array(t(4)))).describe("Attribute ID."),
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: t(4).describe("Cluster ID."),
398
- dt: t(2).describe("Data type."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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(m()).describe("Relative path of a Javascript .js file.")
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: t(4).or(e.array(t(4))).describe("String hex value or array of string hex values."),
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: t(4).describe("Cluster ID."),
410
- dt: t(2).describe("Data type."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
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(m()).describe("Relative path of a Javascript .js file.")
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: t(4).describe("Cluster ID."),
419
- dt: t(2).describe("Data type."),
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(t(4)).describe("Manufacturer code, must be set to 0x0000 for non manufacturer specific commands."),
422
- cmd: e.optional(t(2)).describe("Zigbee command."),
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(m()).describe("Relative path of a Javascript .js file.")
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: t(2).describe("Data type."),
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(m()).describe("Relative path of a Javascript .js file.")
468
+ script: e.optional(p()).describe("Relative path of a Javascript .js file.")
432
469
  })
433
- ]).refine((a) => !("eval" in a && "script" in a), {
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 I(a) {
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(C()).describe("Date of deprecation, if the item is deprecated, it's better to use the new one."),
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(A()).describe("Fonction used to read value."),
455
- parse: e.optional(S()).describe("Fonction used to parse incoming values."),
456
- write: e.optional(J()).describe("Fonction used to write value."),
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 M(a) {
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(a.manufacturers)),
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(a.manufacturers)),
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(m()).describe("DDF path, useless, can be removed."),
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(R(a)).describe("Devices section."),
494
- bindings: e.optional(e.array(G())).describe("Bindings section.")
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 R(a) {
534
+ function F(t) {
498
535
  return e.strictObject({
499
536
  type: e.union([
500
- e.enum(Object.keys(a.deviceTypes)),
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: t(4),
507
- device: t(4),
543
+ profile: a(4),
544
+ device: a(4),
508
545
  endpoint: u(),
509
- in: e.optional(e.array(t(4))),
510
- out: e.optional(e.array(t(4)))
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(Z(a)),
558
+ items: e.array(k(t)),
522
559
  example: e.optional(e.unknown())
523
560
  });
524
561
  }
525
- function Z(a) {
526
- return I().omit({
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(a.attributes).describe("Item name.")
568
+ name: e.enum(t.attributes).describe("Item name.")
532
569
  });
533
570
  }
534
- function G(a) {
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: t(4).describe("Cluster."),
577
+ cl: a(4).describe("Cluster."),
541
578
  report: e.optional(e.array(
542
579
  e.strictObject({
543
- at: t(4),
544
- dt: t(2),
545
- mf: e.optional(t(4)),
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(t().or(e.number()))
549
- }).refine((i) => i.min <= i.max, { message: "invalid report time, min should be smaller than max" })
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: t(4).describe("Cluster."),
592
+ cl: a(4).describe("Cluster."),
556
593
  "config.group": e.number().min(0).max(255)
557
594
  })
558
595
  ]);
559
596
  }
560
- function F(a) {
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(a.deviceTypes)),
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(a.attributes))
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 y(a) {
613
+ function x(t) {
576
614
  return e.discriminatedUnion("schema", [
577
- M(a),
578
- $(),
579
- x(),
615
+ G(t),
616
+ A(),
580
617
  I(),
581
- F(a)
582
- ]).superRefine((i, o) => {
583
- switch (i.schema) {
618
+ D(),
619
+ L(t)
620
+ ]).superRefine((r, f) => {
621
+ switch (r.schema) {
584
622
  case "devcap1.schema.json":
585
- g[i.schema].map((s) => s(i, o));
623
+ y[r.schema].map((o) => o(r, f, t));
586
624
  break;
587
625
  case "constants2.schema.json":
588
- g[i.schema].map((s) => s(i, o));
626
+ y[r.schema].map((o) => o(r, f, t));
589
627
  break;
590
628
  }
591
629
  });
592
630
  }
593
- function z(a = {
631
+ function W(t = {
594
632
  attributes: [],
595
633
  manufacturers: {},
596
634
  deviceTypes: {},
597
- resources: {}
635
+ resources: {},
636
+ subDevices: {}
598
637
  }) {
599
- let i = y(a);
600
- const o = () => {
601
- i = y(a);
638
+ let r = x(t);
639
+ const f = () => {
640
+ r = x(t);
602
641
  };
603
- return { generics: a, loadGeneric: (p) => {
604
- const r = i.parse(p);
605
- switch (r.schema) {
642
+ return { generics: t, loadGeneric: (n) => {
643
+ const s = r.parse(n);
644
+ switch (s.schema) {
606
645
  case "constants1.schema.json":
607
- a.manufacturers = {
608
- ...a.manufacturers,
609
- ...r.manufacturers
610
- }, a.deviceTypes = {
611
- ...a.deviceTypes,
612
- ...r["device-types"]
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(r).filter((n) => n.startsWith("$MF_")).forEach((n) => {
617
- a.manufacturers[n] = r[n];
618
- }), Object.keys(r).filter((n) => n.startsWith("$TYPE_")).forEach((n) => {
619
- a.deviceTypes[n] = r[n];
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 (a.attributes.includes(r.id))
625
- throw new Error(`Got duplicate resource item with attribute id '${r.id}'.`);
626
- const n = r, d = r.id;
627
- delete n.$schema, delete n.schema, delete n.id, a.resources[d] = n, a.attributes.push(d);
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 o(), !0;
636
- }, validate: (p) => i.parse(p), getSchema: () => i };
675
+ return f(), !0;
676
+ }, validate: (n) => r.parse(n), getSchema: () => r, version: O };
637
677
  }
638
678
  export {
639
- z as createValidator
679
+ W as createValidator
640
680
  };