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