@deconz-community/ddf-validator 1.2.0 → 2.0.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/README.md CHANGED
@@ -21,19 +21,47 @@ Example :
21
21
  import { readFile } from 'fs/promises'
22
22
  import glob from 'glob'
23
23
  import { fromZodError } from 'zod-validation-error'
24
- import { validate } from '@deconz-community/ddf-validator'
24
+ import { validator } from '@deconz-community/ddf-validator'
25
25
 
26
26
  (async () => {
27
- const jsonfiles = await glob('devices/**/*.json', { ignore: '**/generic/**' })
28
- jsonfiles.forEach((filePath) => {
27
+
28
+ const validator = createValidator()
29
+
30
+ const genericFiles = await glob('test-data/generic/**/*.json')
31
+ const ddfFiles = await glob('test-data/**/*.json', {
32
+ ignore: '**/generic/**',
33
+ })
34
+
35
+ const genericFilesData = await Promise.all(genericFiles.map(
36
+ async (filePath) => {
37
+ const data = await readFile(filePath, 'utf-8')
38
+ const decoded = JSON.parse(data)
39
+ return { path: filePath, data: decoded }
40
+ },
41
+ ))
42
+
43
+ // Sort to load consts first
44
+ genericFilesData.sort((a, b) => a.data.schema.localeCompare(b.data.schema))
45
+
46
+ genericFilesData.forEach((file) => {
47
+ try {
48
+ const result = validator.loadGeneric(file.data)
49
+ console.log(`Loaded generic file${file.path}`)
50
+ }
51
+ catch (error) {
52
+ console.error(`Error while loading file ${file.path} : ${fromZodError(error).message}`)
53
+ }
54
+ })
55
+
56
+ ddfFiles.forEach((filePath) => {
29
57
  const data = await readFile(filePath, 'utf-8')
30
58
  const decoded = JSON.parse(data)
31
59
  try {
32
- const result = validate(decoded)
33
- console.log(result)
60
+ const result = validator.validate(decoded)
61
+ console.log(`Validated file ${file.path}`)
34
62
  }
35
63
  catch (error) {
36
- throw new Error(fromZodError(error).message)
64
+ console.error(`Error while validating file ${file.path} : ${fromZodError(error).message}`)
37
65
  }
38
66
  })
39
67
  })()
@@ -41,35 +69,122 @@ import { validate } from '@deconz-community/ddf-validator'
41
69
 
42
70
  ## API
43
71
 
44
- ### validate
72
+ ### createValidator()
45
73
 
46
74
  Main function to validate the DDF data object.
47
75
 
48
76
  #### Arguments
49
- - `data` - object; The DDF data parsed from JSON (required)
77
+ - `generics` - : GenericsData; Base generic data to validate DDF.
78
+
79
+ #### Return
80
+ Return a new validator instance.
50
81
 
51
82
  #### Example
52
83
 
53
84
  ```typescript
54
- import { validate } from '@deconz-community/ddf-validator'
55
- import { fromZodError } from 'zod-validation-error'
85
+ import { createValidator } from '@deconz-community/ddf-validator'
86
+
87
+ const validator = createValidator({
88
+ attributes: ['attr/id']
89
+ manufacturers: { "$MF_FOO": "Foo inc." }
90
+ deviceTypes: { "$TYPE_COLOR_LIGHT": "Color light" }
91
+ })
92
+
93
+ ```
94
+
95
+
96
+ ### validator.generics
97
+
98
+ Currently loaded generics.
99
+
100
+ #### Return
101
+ - `generics` - : GenericsData; Generic data to validate DDF.
102
+
103
+ ### validator.loadGeneric()
104
+
105
+ Load generic data from an object.
106
+ Support files with schema `constants1.schema.json`, `resourceitem1.schema.json` and `subdevice1.schema.json`.
107
+
108
+ #### Arguments
109
+ - `data` - : object; File data.
110
+
111
+ #### Return
112
+ - `data` - : object; File data.
56
113
 
57
- const decoded = JSON.parse("{...}")
114
+ Or throw [Zod Error](https://github.com/colinhacks/zod/blob/master/ERROR_HANDLING.md)
115
+
116
+ #### Example
117
+
118
+ ```typescript
119
+ import { createValidator } from '@deconz-community/ddf-validator'
120
+
121
+ const validator = createValidator()
122
+ validator.loadGeneric({
123
+ "schema": "constants1.schema.json",
124
+ "manufacturers" : {
125
+ "$MF_FOO": "Foo inc."
126
+ },
127
+ "device-types": {
128
+ "$TYPE_COLOR_LIGHT": "Color light"
129
+ }
130
+ })
131
+
132
+ ```
133
+
134
+ ### validator.validate()
135
+
136
+ Validate DDF data from an object.
137
+ Support files with schema `constants1.schema.json`, `resourceitem1.schema.json`, `subdevice1.schema.json` and `devcap1.schema.json`.
138
+ Make sure to load any need generic first.
139
+
140
+ #### Arguments
141
+ - `data` - : object; File data.
142
+
143
+ #### Return
144
+ - `data` - : object; File data.
145
+
146
+ Or throw [Zod Error](https://github.com/colinhacks/zod/blob/master/ERROR_HANDLING.md)
147
+
148
+ #### Example
149
+
150
+ ```typescript
151
+ import { createValidator } from '@deconz-community/ddf-validator'
152
+
153
+ const validator = createValidator()
154
+ validator.validate({
155
+ "schema": "constants1.schema.json",
156
+ "manufacturers" : {
157
+ "$MF_FOO": "Foo inc."
158
+ },
159
+ "device-types": {
160
+ "$TYPE_COLOR_LIGHT": "Color light"
161
+ }
162
+ })
163
+
164
+ ```
165
+
166
+ ### validator.getSchema()
167
+
168
+ Return Zod schema with loaded generic data.
169
+
170
+ #### Return
171
+ - `schema` - : ZodType<DDF>; Zod Schema.
172
+
173
+ #### Example
174
+
175
+ ```typescript
176
+ import { createValidator } from '@deconz-community/ddf-validator'
177
+ import { zodToJsonSchema } from 'zod-to-json-schema'
58
178
 
59
- try {
60
- const result = validate(decoded)
61
- console.log(result) // DDF type
62
- }
63
- catch (error) {
64
- throw new Error(fromZodError(error).message)
65
- }
179
+ const validator = createValidator()
180
+ const schemaJson = zodToJsonSchema(validator.getSchema(), 'DDF')
66
181
  ```
67
182
 
68
183
  ### Type definition
69
184
 
70
185
  ### DDF
71
186
 
72
- The type definition of a valid DDF file.
187
+ The type definition of a valid DDF file. Contain union type for `constants1.schema.json`, `resourceitem1.schema.json`, `subdevice1.schema.json` and `devcap1.schema.json`.
73
188
 
74
189
  #### Example
75
190
 
@@ -1 +1 @@
1
- {"$ref":"#/definitions/DDF","definitions":{"DDF":{"anyOf":[{"type":"object","properties":{"$schema":{"type":"string"},"schema":{"type":"string","const":"devcap1.schema.json"},"doc:path":{"type":"string"},"doc:hdr":{"type":"string"},"md:known_issues":{"type":"array","items":{"type":"string"}},"manufacturername":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"modelid":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"vendor":{"type":"string"},"comment":{"type":"string"},"matchexpr":{"type":"string"},"path":{"type":"string"},"product":{"type":"string"},"sleeper":{"type":"boolean"},"supportsMgmtBind":{"type":"boolean"},"status":{"type":"string","enum":["Draft","Bronze","Silver","Gold"],"description":"The code quality of the DDF file."},"subdevices":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["$TYPE_AIR_PURIFIER","$TYPE_AIR_QUALITY_SENSOR","$TYPE_ALARM_SENSOR","$TYPE_BATTERY_SENSOR","$TYPE_COLOR_DIMMABLE_LIGHT","$TYPE_COLOR_LIGHT","$TYPE_COLOR_TEMPERATURE_LIGHT","$TYPE_CONSUMPTION_SENSOR","$TYPE_DIMMABLE_LIGHT","$TYPE_DIMMABLE_PLUGIN_UNIT","$TYPE_DIMMER_SWITCH","$TYPE_DOOR_LOCK_CONTROLLER","$TYPE_DOOR_LOCK","$TYPE_EXTENDED_COLOR_LIGHT","$TYPE_FIRE_SENSOR","$TYPE_HUMIDITY_SENSOR","$TYPE_LIGHT_LEVEL_SENSOR","$TYPE_ON_OFF_LIGHT","$TYPE_ON_OFF_OUTPUT","$TYPE_ON_OFF_PLUGIN_UNIT","$TYPE_OPEN_CLOSE_SENSOR","$TYPE_POWER_SENSOR","$TYPE_PRESENCE_SENSOR","$TYPE_PRESSURE_SENSOR","$TYPE_RANGE_EXTENDER","$TYPE_RELATIVE_ROTARY","$TYPE_SMART_PLUG","$TYPE_SPECTRAL_SENSOR","$TYPE_SWITCH","$TYPE_TEMPERATURE_SENSOR","$TYPE_THERMOSTAT","$TYPE_VIBRATION_SENSOR","$TYPE_WARNING_DEVICE","$TYPE_WATER_LEAK_SENSOR","$TYPE_WINDOW_COVERING_DEVICE","$TYPE_ZGP_SWITCH","ZHAAirPurifier","ZHAAirQuality","ZHAAlarm","ZHABattery","Color dimmable light","Color light","Color temperature light","ZHAConsumption","Dimmable light","Dimmable plug-in unit","Dimmer switch","Door lock controller","Door Lock","Extended color light","ZHAFire","ZHAHumidity","ZHALightLevel","On/Off light","On/Off output","On/Off plug-in unit","ZHAOpenClose","ZHAPower","ZHAPresence","ZHAPressure","Range extender","ZHARelativeRotary","Smart plug","ZHASpectral","ZHASwitch","ZHATemperature","ZHAThermostat","ZHAVibration","Warning device","ZHAWater","Window covering device","ZGPSwitch","ZHAAncillaryControl","ZHATime","ZHACarbonMonoxide","ZHADoorLock"]},"restapi":{"type":"string","enum":["/lights","/sensors"]},"uuid":{"anyOf":[{"type":"array","minItems":2,"maxItems":2,"items":[{"type":"string","const":"$address.ext"},{"type":"string","minLength":4,"maxLength":4}]},{"type":"array","minItems":3,"maxItems":3,"items":[{"type":"string","const":"$address.ext"},{"type":"string","minLength":4,"maxLength":4},{"type":"string","minLength":6,"maxLength":6}]}]},"fingerprint":{"type":"object","properties":{"profile":{"type":"string","minLength":6,"maxLength":6},"device":{"type":"string","minLength":6,"maxLength":6},"endpoint":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"in":{"type":"array","items":{"type":"string","minLength":6,"maxLength":6}},"out":{"type":"array","items":{"type":"string","minLength":6,"maxLength":6}}},"required":["profile","device","endpoint"],"additionalProperties":false},"meta":{"type":"object","properties":{"values":{},"group.endpoints":{"type":"array","items":{"type":"number"}}},"additionalProperties":false},"buttons":{},"buttonevents":{},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"comment":{"type":"string"},"public":{"type":"boolean"},"static":{"type":["string","number","boolean"]},"range":{"type":"array","minItems":2,"maxItems":2,"items":[{"type":"number"},{"type":"number"}]},"deprecated":{"type":"string"},"access":{"type":"string","const":"R"},"read":{"anyOf":[{"type":"object","properties":{"fn":{"type":"string","const":"none"}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"not":{}},"at":{"anyOf":[{"type":"string","minLength":6,"maxLength":6},{"type":"array","items":{"type":"string","minLength":6,"maxLength":6}}]},"cl":{"type":"string","minLength":6,"maxLength":6},"ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","minLength":6,"maxLength":6},"eval":{"type":"string"}},"required":["cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"anyOf":[{"type":"string","minLength":6,"maxLength":6},{"type":"array","items":{"type":"string","minLength":6,"maxLength":6}}]},"cl":{"type":"string","minLength":6,"maxLength":6},"ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","minLength":6,"maxLength":6},"eval":{"type":"string"}},"required":["fn","cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"}},"required":["fn"],"additionalProperties":false}]},"parse":{"anyOf":[{"type":"object","properties":{"fn":{"not":{}},"at":{"type":"string","minLength":6,"maxLength":6},"cl":{"type":"string","minLength":6,"maxLength":6},"cppsrc":{"type":"string"},"ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"cmd":{"type":"string","minLength":4,"maxLength":4},"mf":{"type":"string","minLength":6,"maxLength":6},"eval":{"type":"string"},"script":{"type":"string"}},"required":["cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"type":"string","minLength":6,"maxLength":6},"cl":{"type":"string","minLength":6,"maxLength":6},"cppsrc":{"type":"string"},"ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"cmd":{"type":"string","minLength":4,"maxLength":4},"mf":{"type":"string","minLength":6,"maxLength":6},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"ias:zonestatus"},"mask":{"type":"string","enum":["alarm1","alarm2"]}},"required":["fn","mask"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"numtostr"},"srcitem":{"type":"string","enum":["state/airqualityppb","state/pm2_5"]},"op":{"type":"string","const":"le"},"to":{}},"required":["fn","srcitem","op","to"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"xiaomi:special"},"ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"at":{"type":"string","minLength":6,"maxLength":6},"idx":{"type":"string","minLength":4,"maxLength":4},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","idx"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"},"dpid":{"type":"number"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","dpid"],"additionalProperties":false}]},"write":{"anyOf":[{"type":"object","properties":{"fn":{"type":"string","const":"none"}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"not":{}},"at":{"anyOf":[{"type":"string","minLength":6,"maxLength":6},{"type":"array","items":{"type":"string","minLength":6,"maxLength":6}}]},"state.timeout":{"type":"number"},"change.timeout":{"type":"number"},"cl":{"type":"string","minLength":6,"maxLength":6},"dt":{"type":"string","minLength":4,"maxLength":4},"ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","minLength":6,"maxLength":6},"eval":{"type":"string"},"script":{"type":"string"}},"required":["cl","dt"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"anyOf":[{"type":"string","minLength":6,"maxLength":6},{"type":"array","items":{"type":"string","minLength":6,"maxLength":6}}]},"state.timeout":{"type":"number"},"change.timeout":{"type":"number"},"cl":{"type":"string","minLength":6,"maxLength":6},"dt":{"type":"string","minLength":4,"maxLength":4},"ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","minLength":6,"maxLength":6},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","cl","dt"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"},"dpid":{"type":"number"},"dt":{"type":"string","minLength":4,"maxLength":4},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","dpid","dt"],"additionalProperties":false}]},"awake":{"type":"boolean"},"default":{},"values":{},"refresh.interval":{"type":"number"}},"required":["name"],"additionalProperties":false}},"example":{}},"required":["type","restapi","uuid","items"],"additionalProperties":false}},"bindings":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"bind":{"type":"string","const":"unicast"},"src.ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"dst.ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"cl":{"type":"string","minLength":6,"maxLength":6},"report":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","minLength":6,"maxLength":6},"dt":{"type":"string","minLength":4,"maxLength":4},"mf":{"type":"string","minLength":6,"maxLength":6},"min":{"type":"number"},"max":{"type":"number"},"change":{"type":["string","number"]}},"required":["at","dt","min","max"],"additionalProperties":false}}},"required":["bind","src.ep","cl"],"additionalProperties":false},{"type":"object","properties":{"bind":{"type":"string","const":"groupcast"},"src.ep":{"anyOf":[{"type":"string","minLength":4,"maxLength":4},{"type":"number","minimum":0,"maximum":255}]},"cl":{"type":"string","minLength":6,"maxLength":6},"config.group":{"type":"number"}},"required":["bind","src.ep","cl","config.group"],"additionalProperties":false}]}}},"required":["schema","manufacturername","modelid","status","subdevices"],"additionalProperties":false}]}},"$schema":"http://json-schema.org/draft-07/schema#"}
1
+ {"$ref":"#/definitions/DDF","definitions":{"DDF":{"anyOf":[{"type":"object","properties":{"$schema":{"type":"string"},"schema":{"type":"string","const":"devcap1.schema.json"},"doc:path":{"type":"string"},"doc:hdr":{"type":"string"},"md:known_issues":{"type":"array","items":{"type":"string"}},"manufacturername":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"modelid":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"vendor":{"type":"string"},"comment":{"type":"string"},"matchexpr":{"type":"string"},"path":{"type":"string"},"product":{"type":"string"},"sleeper":{"type":"boolean"},"supportsMgmtBind":{"type":"boolean"},"status":{"type":"string","enum":["Draft","Bronze","Silver","Gold"],"description":"The code quality of the DDF file."},"subdevices":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["$TYPE_AIR_PURIFIER","$TYPE_AIR_QUALITY_SENSOR","$TYPE_ALARM_SENSOR","$TYPE_ANCILLARY_CONTROL","$TYPE_BATTERY_SENSOR","$TYPE_CARBON_MONOXIDE","$TYPE_COLOR_DIMMABLE_LIGHT","$TYPE_COLOR_LIGHT","$TYPE_COLOR_TEMPERATURE_LIGHT","$TYPE_CONSUMPTION_SENSOR","$TYPE_DIMMABLE_LIGHT","$TYPE_DIMMABLE_PLUGIN_UNIT","$TYPE_DIMMER_SWITCH","$TYPE_DOOR_LOCK_CONTROLLER","$TYPE_DOOR_LOCK","$TYPE_EXTENDED_COLOR_LIGHT","$TYPE_FIRE_SENSOR","$TYPE_HUMIDITY_SENSOR","$TYPE_LIGHT_LEVEL_SENSOR","$TYPE_ON_OFF_LIGHT","$TYPE_ON_OFF_OUTPUT","$TYPE_ON_OFF_PLUGIN_UNIT","$TYPE_OPEN_CLOSE_SENSOR","$TYPE_POWER_SENSOR","$TYPE_PRESENCE_SENSOR","$TYPE_PRESSURE_SENSOR","$TYPE_RANGE_EXTENDER","$TYPE_RELATIVE_ROTARY","$TYPE_SMART_PLUG","$TYPE_SPECTRAL_SENSOR","$TYPE_SWITCH","$TYPE_TEMPERATURE_SENSOR","$TYPE_THERMOSTAT","$TYPE_TIME","$TYPE_VIBRATION_SENSOR","$TYPE_WARNING_DEVICE","$TYPE_WATER_LEAK_SENSOR","$TYPE_WINDOW_COVERING_DEVICE","$TYPE_ZGP_SWITCH","ZHAAirPurifier","ZHAAirQuality","ZHAAlarm","ZHAAncillaryControl","ZHABattery","ZHACarbonMonoxide","Color dimmable light","Color light","Color temperature light","ZHAConsumption","Dimmable light","Dimmable plug-in unit","Dimmer switch","Door lock controller","ZHADoorLock","Extended color light","ZHAFire","ZHAHumidity","ZHALightLevel","On/Off light","On/Off output","On/Off plug-in unit","ZHAOpenClose","ZHAPower","ZHAPresence","ZHAPressure","Range extender","ZHARelativeRotary","Smart plug","ZHASpectral","ZHASwitch","ZHATemperature","ZHAThermostat","ZHATime","ZHAVibration","Warning device","ZHAWater","Window covering device","ZGPSwitch"]},"restapi":{"type":"string","enum":["/lights","/sensors"]},"uuid":{"anyOf":[{"type":"array","minItems":2,"maxItems":2,"items":[{"type":"string","const":"$address.ext"},{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"}]},{"type":"array","minItems":3,"maxItems":3,"items":[{"type":"string","const":"$address.ext"},{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}]}]},"fingerprint":{"type":"object","properties":{"profile":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"device":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"endpoint":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"in":{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}},"out":{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}},"required":["profile","device","endpoint"],"additionalProperties":false},"meta":{"type":"object","properties":{"values":{},"group.endpoints":{"type":"array","items":{"type":"number"}}},"additionalProperties":false},"buttons":{},"buttonevents":{},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","enum":["state/windowopen","state/water","state/voltage","state/vibrationstrength","state/vibration","state/valve","state/utc","state/tiltangle","state/tilt","state/test","state/temperature","state/tampered","state/speed","state/seconds_remaining","state/sat","state/rotaryevent","state/replacefilter","state/reachable","state/production","state/pressure","state/presenceevent","state/presence","state/power","state/pm2_5","state/panel","state/orientation_z","state/orientation_y","state/orientation_x","state/orientation","state/open","state/on","state/mountingmodeactive","state/lux","state/lowbattery","state/lockstate","state/localtime","state/lightlevel","state/lift","state/lastupdated","state/lastset","state/lastcheckin","state/humidity","state/hue","state/heating","state/gradient","state/gesture","state/fire","state/filterruntime","state/expectedrotation","state/expectedeventduration","state/eventduration","state/errorcode","state/effect","state/deviceruntime","state/daylight","state/dark","state/current","state/current_P3","state/current_P2","state/current_P1","state/ct","state/consumption","state/consumption_2","state/y","state/x","state/colormode","state/charging","state/carbonmonoxide","state/buttonevent","state/bri","state/battery","state/angle","state/alert","state/alarm","state/airqualityppb","state/airquality","state/action","config/windowopen_set","config/windowcoveringtype","config/usertest","config/unoccupiedheatsetpoint","config/triggerdistance","config/tholdoffset","config/tholddark","config/temperature","config/swingmode","config/sensitivitymax","config/sensitivity","config/selftest","config/schedule_on","config/schedule","config/resetpresence","config/reachable","config/pulseconfiguration","config/preset","config/pending","config/on/startup","config/on","config/offset","config/mountingmode","config/mode","config/locked","config/lock","config/ledindication","config/interfacemode","config/heatsetpoint","config/group","config/filterlifetime","config/fanmode","config/externalwindowopen","config/externalsensortemp","config/enrolled","config/duration","config/displayflipped","config/devicemode","config/delay","config/ctmin","config/ctmax","config/coolsetpoint","config/controlsequence","config/configured","config/colorcapabilities","config/color/xy/startup_y","config/color/xy/startup_x","config/color/gradient/reversed","config/color/execute_if_off","config/color/ct/startup","config/clickmode","config/checkin","config/bri/startup","config/bri/onoff_transitiontime","config/bri/on_level","config/bri/min","config/bri/max","config/bri/execute_if_off","config/battery","config/allowtouchlink","config/alert","cap/transition_block","cap/sleeper","cap/on/off_with_effect","cap/groups/not_supported","cap/color/xy/red_y","cap/color/xy/red_x","cap/color/xy/green_y","cap/color/xy/green_x","cap/color/xy/blue_y","cap/color/xy/blue_x","cap/color/gradient/styles","cap/color/gradient/pixel_length","cap/color/gradient/pixel_count","cap/color/gradient/max_segments","cap/color/gamut_type","cap/color/effects","cap/color/ct/min","cap/color/ct/max","cap/color/ct/computes_xy","cap/color/capabilities","cap/bri/move_with_onoff","cap/bri/min_dim_level","cap/alert/trigger_effect","attr/uniqueid","attr/type","attr/swversion","attr/swconfigid","attr/productname","attr/productid","attr/powerup","attr/poweronlevel","attr/poweronct","attr/name","attr/modelid","attr/mode","attr/manufacturername","attr/lastseen","attr/lastannounced","attr/id"]},"description":{"type":"string"},"comment":{"type":"string"},"public":{"type":"boolean"},"static":{"type":["string","number","boolean"]},"range":{"type":"array","minItems":2,"maxItems":2,"items":[{"type":"number"},{"type":"number"}]},"deprecated":{"type":"string","pattern":"^(\\d{4})-(?:(?:0[1-9])|(?:1[0-2]))-(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01]))$"},"access":{"type":"string","const":"R"},"read":{"anyOf":[{"type":"object","properties":{"fn":{"type":"string","const":"none"}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"not":{}},"at":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}]},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"}},"required":["cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}]},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"}},"required":["fn","cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"}},"required":["fn"],"additionalProperties":false}]},"parse":{"anyOf":[{"type":"object","properties":{"fn":{"not":{}},"at":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"cppsrc":{"type":"string"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"cmd":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"cppsrc":{"type":"string"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"cmd":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"ias:zonestatus"},"mask":{"anyOf":[{"type":"string","enum":["alarm1","alarm2"]},{"type":"string","const":"alarm1,alarm2"}]}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"numtostr"},"srcitem":{"type":"string","enum":["state/airqualityppb","state/pm2_5"]},"op":{"type":"string","const":"le"},"to":{}},"required":["fn","srcitem","op","to"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"time"}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"xiaomi:special"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"at":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"idx":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","idx"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"},"dpid":{"type":"number"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","dpid"],"additionalProperties":false}]},"write":{"anyOf":[{"type":"object","properties":{"fn":{"type":"string","const":"none"}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"not":{}},"at":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}]},"state.timeout":{"type":"number"},"change.timeout":{"type":"number"},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"dt":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["cl","dt"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}]},"state.timeout":{"type":"number"},"change.timeout":{"type":"number"},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"dt":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","cl","dt"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"},"dpid":{"type":"number"},"dt":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","dpid","dt"],"additionalProperties":false}]},"awake":{"type":"boolean"},"default":{},"values":{},"refresh.interval":{"type":"number"}},"required":["name"],"additionalProperties":false}},"example":{}},"required":["type","restapi","uuid","items"],"additionalProperties":false}},"bindings":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"bind":{"type":"string","const":"unicast"},"src.ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"dst.ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"report":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"dt":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"min":{"type":"number"},"max":{"type":"number"},"change":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]+$"},{"type":"number"}]}},"required":["at","dt","min","max"],"additionalProperties":false}}},"required":["bind","src.ep","cl"],"additionalProperties":false},{"type":"object","properties":{"bind":{"type":"string","const":"groupcast"},"src.ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"config.group":{"type":"number"}},"required":["bind","src.ep","cl","config.group"],"additionalProperties":false}]}}},"required":["schema","manufacturername","modelid","status","subdevices"],"additionalProperties":false},{"type":"object","properties":{"$schema":{"type":"string"},"schema":{"type":"string","const":"constants1.schema.json"},"manufacturers":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"pattern":"^\\$MF\\_"}},"device-types":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"pattern":"^\\$TYPE\\_"}}},"required":["schema","manufacturers","device-types"],"additionalProperties":false},{"type":"object","properties":{"$schema":{"type":"string"},"schema":{"type":"string","const":"resourceitem1.schema.json"},"id":{"type":"string"},"description":{"type":"string"},"deprecated":{"type":"string","pattern":"^(\\d{4})-(?:(?:0[1-9])|(?:1[0-2]))-(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01]))$"},"datatype":{"type":"string","enum":["String","Bool","Int8","Int16","Int32","Int64","UInt8","UInt16","UInt32","UInt64","Array","Array[3]","ISO 8601 timestamp"]},"access":{"type":"string","enum":["R","W","RW"]},"public":{"type":"boolean"},"implicit":{"type":"boolean"},"managed":{"type":"boolean"},"static":{"type":"boolean"},"virtual":{"type":"boolean"},"parse":{"anyOf":[{"type":"object","properties":{"fn":{"not":{}},"at":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"cppsrc":{"type":"string"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"cmd":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"cppsrc":{"type":"string"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"cmd":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"ias:zonestatus"},"mask":{"anyOf":[{"type":"string","enum":["alarm1","alarm2"]},{"type":"string","const":"alarm1,alarm2"}]}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"numtostr"},"srcitem":{"type":"string","enum":["state/airqualityppb","state/pm2_5"]},"op":{"type":"string","const":"le"},"to":{}},"required":["fn","srcitem","op","to"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"time"}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"xiaomi:special"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"at":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"idx":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","idx"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"},"dpid":{"type":"number"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","dpid"],"additionalProperties":false}]},"read":{"anyOf":[{"type":"object","properties":{"fn":{"type":"string","const":"none"}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"not":{}},"at":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}]},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"}},"required":["cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}]},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"}},"required":["fn","cl"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"}},"required":["fn"],"additionalProperties":false}]},"write":{"anyOf":[{"type":"object","properties":{"fn":{"type":"string","const":"none"}},"required":["fn"],"additionalProperties":false},{"type":"object","properties":{"fn":{"not":{}},"at":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}]},"state.timeout":{"type":"number"},"change.timeout":{"type":"number"},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"dt":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["cl","dt"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"zcl"},"at":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},{"type":"array","items":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}}]},"state.timeout":{"type":"number"},"change.timeout":{"type":"number"},"cl":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"dt":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"ep":{"anyOf":[{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"number","minimum":0,"maximum":255}]},"mf":{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","cl","dt"],"additionalProperties":false},{"type":"object","properties":{"fn":{"type":"string","const":"tuya"},"dpid":{"type":"number"},"dt":{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},"eval":{"type":"string"},"script":{"type":"string"}},"required":["fn","dpid","dt"],"additionalProperties":false}]},"refresh.interval":{"type":"number"},"values":{},"range":{"type":"array","minItems":2,"maxItems":2,"items":[{"type":"number"},{"type":"number"}]},"default":{}},"required":["schema","id","description","datatype","access","public"],"additionalProperties":false},{"type":"object","properties":{"$schema":{"type":"string"},"schema":{"type":"string","const":"subdevice1.schema.json"},"type":{"type":"string","enum":["$TYPE_AIR_PURIFIER","$TYPE_AIR_QUALITY_SENSOR","$TYPE_ALARM_SENSOR","$TYPE_ANCILLARY_CONTROL","$TYPE_BATTERY_SENSOR","$TYPE_CARBON_MONOXIDE","$TYPE_COLOR_DIMMABLE_LIGHT","$TYPE_COLOR_LIGHT","$TYPE_COLOR_TEMPERATURE_LIGHT","$TYPE_CONSUMPTION_SENSOR","$TYPE_DIMMABLE_LIGHT","$TYPE_DIMMABLE_PLUGIN_UNIT","$TYPE_DIMMER_SWITCH","$TYPE_DOOR_LOCK_CONTROLLER","$TYPE_DOOR_LOCK","$TYPE_EXTENDED_COLOR_LIGHT","$TYPE_FIRE_SENSOR","$TYPE_HUMIDITY_SENSOR","$TYPE_LIGHT_LEVEL_SENSOR","$TYPE_ON_OFF_LIGHT","$TYPE_ON_OFF_OUTPUT","$TYPE_ON_OFF_PLUGIN_UNIT","$TYPE_OPEN_CLOSE_SENSOR","$TYPE_POWER_SENSOR","$TYPE_PRESENCE_SENSOR","$TYPE_PRESSURE_SENSOR","$TYPE_RANGE_EXTENDER","$TYPE_RELATIVE_ROTARY","$TYPE_SMART_PLUG","$TYPE_SPECTRAL_SENSOR","$TYPE_SWITCH","$TYPE_TEMPERATURE_SENSOR","$TYPE_THERMOSTAT","$TYPE_TIME","$TYPE_VIBRATION_SENSOR","$TYPE_WARNING_DEVICE","$TYPE_WATER_LEAK_SENSOR","$TYPE_WINDOW_COVERING_DEVICE","$TYPE_ZGP_SWITCH"]},"name":{"type":"string","enum":["ZHAAirPurifier","ZHAAirQuality","ZHAAlarm","ZHAAncillaryControl","ZHABattery","ZHACarbonMonoxide","Color dimmable light","Color light","Color temperature light","ZHAConsumption","Dimmable light","Dimmable plug-in unit","Dimmer switch","Door lock controller","ZHADoorLock","Extended color light","ZHAFire","ZHAHumidity","ZHALightLevel","On/Off light","On/Off output","On/Off plug-in unit","ZHAOpenClose","ZHAPower","ZHAPresence","ZHAPressure","Range extender","ZHARelativeRotary","Smart plug","ZHASpectral","ZHASwitch","ZHATemperature","ZHAThermostat","ZHATime","ZHAVibration","Warning device","ZHAWater","Window covering device","ZGPSwitch"]},"restapi":{"type":"string","enum":["/lights","/sensors"]},"order":{"type":"number"},"uuid":{"anyOf":[{"type":"array","minItems":2,"maxItems":2,"items":[{"type":"string","const":"$address.ext"},{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"}]},{"type":"array","minItems":3,"maxItems":3,"items":[{"type":"string","const":"$address.ext"},{"type":"string","pattern":"^0x[0-9a-fA-F]{2}$"},{"type":"string","pattern":"^0x[0-9a-fA-F]{4}$"}]}]},"items":{"type":"array","items":{"type":"string","enum":["state/windowopen","state/water","state/voltage","state/vibrationstrength","state/vibration","state/valve","state/utc","state/tiltangle","state/tilt","state/test","state/temperature","state/tampered","state/speed","state/seconds_remaining","state/sat","state/rotaryevent","state/replacefilter","state/reachable","state/production","state/pressure","state/presenceevent","state/presence","state/power","state/pm2_5","state/panel","state/orientation_z","state/orientation_y","state/orientation_x","state/orientation","state/open","state/on","state/mountingmodeactive","state/lux","state/lowbattery","state/lockstate","state/localtime","state/lightlevel","state/lift","state/lastupdated","state/lastset","state/lastcheckin","state/humidity","state/hue","state/heating","state/gradient","state/gesture","state/fire","state/filterruntime","state/expectedrotation","state/expectedeventduration","state/eventduration","state/errorcode","state/effect","state/deviceruntime","state/daylight","state/dark","state/current","state/current_P3","state/current_P2","state/current_P1","state/ct","state/consumption","state/consumption_2","state/y","state/x","state/colormode","state/charging","state/carbonmonoxide","state/buttonevent","state/bri","state/battery","state/angle","state/alert","state/alarm","state/airqualityppb","state/airquality","state/action","config/windowopen_set","config/windowcoveringtype","config/usertest","config/unoccupiedheatsetpoint","config/triggerdistance","config/tholdoffset","config/tholddark","config/temperature","config/swingmode","config/sensitivitymax","config/sensitivity","config/selftest","config/schedule_on","config/schedule","config/resetpresence","config/reachable","config/pulseconfiguration","config/preset","config/pending","config/on/startup","config/on","config/offset","config/mountingmode","config/mode","config/locked","config/lock","config/ledindication","config/interfacemode","config/heatsetpoint","config/group","config/filterlifetime","config/fanmode","config/externalwindowopen","config/externalsensortemp","config/enrolled","config/duration","config/displayflipped","config/devicemode","config/delay","config/ctmin","config/ctmax","config/coolsetpoint","config/controlsequence","config/configured","config/colorcapabilities","config/color/xy/startup_y","config/color/xy/startup_x","config/color/gradient/reversed","config/color/execute_if_off","config/color/ct/startup","config/clickmode","config/checkin","config/bri/startup","config/bri/onoff_transitiontime","config/bri/on_level","config/bri/min","config/bri/max","config/bri/execute_if_off","config/battery","config/allowtouchlink","config/alert","cap/transition_block","cap/sleeper","cap/on/off_with_effect","cap/groups/not_supported","cap/color/xy/red_y","cap/color/xy/red_x","cap/color/xy/green_y","cap/color/xy/green_x","cap/color/xy/blue_y","cap/color/xy/blue_x","cap/color/gradient/styles","cap/color/gradient/pixel_length","cap/color/gradient/pixel_count","cap/color/gradient/max_segments","cap/color/gamut_type","cap/color/effects","cap/color/ct/min","cap/color/ct/max","cap/color/ct/computes_xy","cap/color/capabilities","cap/bri/move_with_onoff","cap/bri/min_dim_level","cap/alert/trigger_effect","attr/uniqueid","attr/type","attr/swversion","attr/swconfigid","attr/productname","attr/productid","attr/powerup","attr/poweronlevel","attr/poweronct","attr/name","attr/modelid","attr/mode","attr/manufacturername","attr/lastseen","attr/lastannounced","attr/id"]}}},"required":["schema","type","name","restapi","order","uuid","items"],"additionalProperties":false}]}},"$schema":"http://json-schema.org/draft-07/schema#"}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("zod"),s=["$TYPE_AIR_PURIFIER","$TYPE_AIR_QUALITY_SENSOR","$TYPE_ALARM_SENSOR","$TYPE_BATTERY_SENSOR","$TYPE_COLOR_DIMMABLE_LIGHT","$TYPE_COLOR_LIGHT","$TYPE_COLOR_TEMPERATURE_LIGHT","$TYPE_CONSUMPTION_SENSOR","$TYPE_DIMMABLE_LIGHT","$TYPE_DIMMABLE_PLUGIN_UNIT","$TYPE_DIMMER_SWITCH","$TYPE_DOOR_LOCK_CONTROLLER","$TYPE_DOOR_LOCK","$TYPE_EXTENDED_COLOR_LIGHT","$TYPE_FIRE_SENSOR","$TYPE_HUMIDITY_SENSOR","$TYPE_LIGHT_LEVEL_SENSOR","$TYPE_ON_OFF_LIGHT","$TYPE_ON_OFF_OUTPUT","$TYPE_ON_OFF_PLUGIN_UNIT","$TYPE_OPEN_CLOSE_SENSOR","$TYPE_POWER_SENSOR","$TYPE_PRESENCE_SENSOR","$TYPE_PRESSURE_SENSOR","$TYPE_RANGE_EXTENDER","$TYPE_RELATIVE_ROTARY","$TYPE_SMART_PLUG","$TYPE_SPECTRAL_SENSOR","$TYPE_SWITCH","$TYPE_TEMPERATURE_SENSOR","$TYPE_THERMOSTAT","$TYPE_VIBRATION_SENSOR","$TYPE_WARNING_DEVICE","$TYPE_WATER_LEAK_SENSOR","$TYPE_WINDOW_COVERING_DEVICE","$TYPE_ZGP_SWITCH","ZHAAirPurifier","ZHAAirQuality","ZHAAlarm","ZHABattery","Color dimmable light","Color light","Color temperature light","ZHAConsumption","Dimmable light","Dimmable plug-in unit","Dimmer switch","Door lock controller","Door Lock","Extended color light","ZHAFire","ZHAHumidity","ZHALightLevel","On/Off light","On/Off output","On/Off plug-in unit","ZHAOpenClose","ZHAPower","ZHAPresence","ZHAPressure","Range extender","ZHARelativeRotary","Smart plug","ZHASpectral","ZHASwitch","ZHATemperature","ZHAThermostat","ZHAVibration","Warning device","ZHAWater","Window covering device","ZGPSwitch","ZHAAncillaryControl","ZHATime","ZHACarbonMonoxide","ZHADoorLock"];function n(e=void 0){return e===void 0?t.z.string():t.z.string().length(2+e)}function o(){return t.z.string()}function p(){return t.z.string()}function i(){return t.z.union([n(2),t.z.number().min(0).max(255)])}function r(){return t.z.string()}function c(){return t.z.custom(e=>{if(!Array.isArray(e)||e.length%2!==0)return!1;for(let a=0;a<e.length;a+=2){const l=e[a],z=e[a+1];if(typeof l!="number"||typeof z!="string")return!1}return!0},"The value must be an array with an even number of values and alternating between number and string.")}function u(e){return m().parse(e)}function m(){return t.z.discriminatedUnion("schema",[d().innerType()])}function d(){return t.z.strictObject({$schema:t.z.optional(t.z.string()),schema:t.z.literal("devcap1.schema.json"),"doc:path":t.z.optional(t.z.string()),"doc:hdr":t.z.optional(t.z.string()),"md:known_issues":t.z.optional(t.z.array(t.z.string())),manufacturername:t.z.string().or(t.z.array(t.z.string())),modelid:t.z.string().or(t.z.array(t.z.string())),vendor:t.z.optional(t.z.string()),comment:t.z.optional(t.z.string()),matchexpr:t.z.optional(o()),path:t.z.optional(r()),product:t.z.optional(t.z.string()),sleeper:t.z.optional(t.z.boolean()),supportsMgmtBind:t.z.optional(t.z.boolean()),status:t.z.enum(["Draft","Bronze","Silver","Gold"]).describe("The code quality of the DDF file."),subdevices:t.z.array(E()),bindings:t.z.optional(t.z.array(b()))}).refine(e=>typeof e.manufacturername=="string"&&typeof e.modelid=="string"||Array.isArray(e.manufacturername)&&Array.isArray(e.modelid)&&e.manufacturername.length===e.modelid.length,{message:"manufacturername and modelid should be both strings or arrays with the same length.",path:["manufacturername","modelid"]})}function E(){return t.z.strictObject({type:t.z.enum(s),restapi:t.z.enum(["/lights","/sensors"]),uuid:t.z.union([t.z.tuple([t.z.literal("$address.ext"),n(2)]),t.z.tuple([t.z.literal("$address.ext"),n(2),n(4)])]),fingerprint:t.z.optional(t.z.strictObject({profile:n(4),device:n(4),endpoint:i(),in:t.z.optional(t.z.array(n(4))),out:t.z.optional(t.z.array(n(4)))})),meta:t.z.optional(t.z.strictObject({values:t.z.any(),"group.endpoints":t.z.optional(t.z.array(t.z.number()))})),buttons:t.z.optional(t.z.any()),buttonevents:t.z.optional(t.z.any()),items:t.z.array(T()),example:t.z.optional(t.z.unknown())})}function T(){return t.z.strictObject({name:t.z.string(),description:t.z.optional(t.z.string()),comment:t.z.optional(t.z.string()),public:t.z.optional(t.z.boolean()),static:t.z.optional(t.z.union([t.z.string(),t.z.number(),t.z.boolean()])),range:t.z.optional(t.z.tuple([t.z.number(),t.z.number()])),deprecated:t.z.optional(p()),access:t.z.optional(t.z.literal("R")),read:t.z.optional(t.z.discriminatedUnion("fn",[t.z.strictObject({fn:t.z.literal("none")}),t.z.strictObject({fn:t.z.undefined(),at:t.z.optional(n(4).or(t.z.array(n(4)))),cl:n(4),ep:t.z.optional(i()),mf:t.z.optional(n(4)),eval:t.z.optional(o())}),t.z.strictObject({fn:t.z.literal("zcl"),at:t.z.optional(n(4).or(t.z.array(n(4)))),cl:n(4),ep:t.z.optional(i()),mf:t.z.optional(n(4)),eval:t.z.optional(o())}),t.z.strictObject({fn:t.z.literal("tuya")})])),parse:t.z.optional(t.z.discriminatedUnion("fn",[t.z.strictObject({fn:t.z.undefined(),at:t.z.optional(n(4)),cl:n(4),cppsrc:t.z.optional(t.z.string()),ep:t.z.optional(i()),cmd:t.z.optional(n(2)),mf:t.z.optional(n(4)),eval:t.z.optional(o()),script:t.z.optional(r())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("zcl"),at:t.z.optional(n(4)),cl:n(4),cppsrc:t.z.optional(t.z.string()),ep:t.z.optional(i()),cmd:t.z.optional(n(2)),mf:t.z.optional(n(4)),eval:t.z.optional(o()),script:t.z.optional(r())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("ias:zonestatus"),mask:t.z.enum(["alarm1","alarm2"])}),t.z.strictObject({fn:t.z.literal("numtostr"),srcitem:t.z.enum(["state/airqualityppb","state/pm2_5"]),op:t.z.literal("le"),to:c()}),t.z.strictObject({fn:t.z.literal("xiaomi:special"),ep:t.z.optional(i()),at:t.z.optional(n(4)),idx:n(2),eval:t.z.optional(o()),script:t.z.optional(r())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("tuya"),dpid:t.z.number(),eval:t.z.optional(o()),script:t.z.optional(r())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType()])),write:t.z.optional(t.z.discriminatedUnion("fn",[t.z.strictObject({fn:t.z.literal("none")}),t.z.strictObject({fn:t.z.undefined(),at:t.z.optional(n(4).or(t.z.array(n(4)))),"state.timeout":t.z.optional(t.z.number()),"change.timeout":t.z.optional(t.z.number()),cl:n(4),dt:n(2),ep:t.z.optional(i()),mf:t.z.optional(n(4)),eval:t.z.optional(o()),script:t.z.optional(r())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("zcl"),at:t.z.optional(n(4).or(t.z.array(n(4)))),"state.timeout":t.z.optional(t.z.number()),"change.timeout":t.z.optional(t.z.number()),cl:n(4),dt:n(2),ep:t.z.optional(i()),mf:t.z.optional(n(4)),eval:t.z.optional(o()),script:t.z.optional(r())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("tuya"),dpid:t.z.number(),dt:n(2),eval:t.z.optional(o()),script:t.z.optional(r())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType()])),awake:t.z.optional(t.z.boolean()),default:t.z.optional(t.z.unknown()),values:t.z.optional(t.z.unknown()),"refresh.interval":t.z.optional(t.z.number())})}function b(){return t.z.discriminatedUnion("bind",[t.z.strictObject({bind:t.z.literal("unicast"),"src.ep":i(),"dst.ep":t.z.optional(i()),cl:n(4),report:t.z.optional(t.z.array(t.z.strictObject({at:n(4),dt:n(2),mf:t.z.optional(n(4)),min:t.z.number(),max:t.z.number(),change:t.z.optional(n().or(t.z.number()))})))}),t.z.strictObject({bind:t.z.literal("groupcast"),"src.ep":i(),cl:n(4),"config.group":t.z.number()})])}exports.validate=u;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("zod");function h(e){return t.z.strictObject({$schema:t.z.optional(t.z.string()),schema:t.z.literal("constants1.schema.json"),manufacturers:t.z.record(t.z.string().startsWith("$MF_"),t.z.string()),"device-types":t.z.record(t.z.string().startsWith("$TYPE_"),t.z.string())})}function u(){return t.z.string().regex(/^(\d{4})-(?:(?:0[1-9])|(?:1[0-2]))-(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01]))$/,"Invalid date value")}function n(e=void 0){const i="Invalid hexadecimal value";return e===void 0?t.z.string().regex(/^0x[0-9a-fA-F]+$/,i):t.z.string().regex(new RegExp(`^0x[0-9a-fA-F]{${e}}$`),i)}function a(){return t.z.union([n(2),t.z.number().min(0).max(255)])}function v(){return t.z.custom(e=>{if(!Array.isArray(e)||e.length%2!==0)return!1;for(let i=0;i<e.length;i+=2){const l=e[i],c=e[i+1];if(typeof l!="number"||typeof c!="string")return!1}return!0},"The value must be an array with an even number of values and alternating between number and string.")}function m(){return t.z.union([t.z.tuple([t.z.literal("$address.ext"),n(2)]),t.z.tuple([t.z.literal("$address.ext"),n(2),n(4)])])}function o(){return t.z.string()}function r(){return t.z.string()}function d(){return t.z.discriminatedUnion("fn",[t.z.strictObject({fn:t.z.literal("none")}),t.z.strictObject({fn:t.z.undefined(),at:t.z.optional(n(4).or(t.z.array(n(4)))),cl:n(4),ep:t.z.optional(a()),mf:t.z.optional(n(4)),eval:t.z.optional(r())}),t.z.strictObject({fn:t.z.literal("zcl"),at:t.z.optional(n(4).or(t.z.array(n(4)))),cl:n(4),ep:t.z.optional(a()),mf:t.z.optional(n(4)),eval:t.z.optional(r())}),t.z.strictObject({fn:t.z.literal("tuya")})])}function b(){return t.z.discriminatedUnion("fn",[t.z.strictObject({fn:t.z.undefined(),at:t.z.optional(n(4)),cl:n(4),cppsrc:t.z.optional(t.z.string()),ep:t.z.optional(a()),cmd:t.z.optional(n(2)),mf:t.z.optional(n(4)),eval:t.z.optional(r()),script:t.z.optional(o())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("zcl"),at:t.z.optional(n(4)),cl:n(4),cppsrc:t.z.optional(t.z.string()),ep:t.z.optional(a()),cmd:t.z.optional(n(2)),mf:t.z.optional(n(4)),eval:t.z.optional(r()),script:t.z.optional(o())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("ias:zonestatus"),mask:t.z.optional(t.z.enum(["alarm1","alarm2"]).or(t.z.literal("alarm1,alarm2")))}),t.z.strictObject({fn:t.z.literal("numtostr"),srcitem:t.z.enum(["state/airqualityppb","state/pm2_5"]),op:t.z.literal("le"),to:v()}),t.z.strictObject({fn:t.z.literal("time")}),t.z.strictObject({fn:t.z.literal("xiaomi:special"),ep:t.z.optional(a()),at:t.z.optional(n(4)),idx:n(2),eval:t.z.optional(r()),script:t.z.optional(o())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("tuya"),dpid:t.z.number(),eval:t.z.optional(r()),script:t.z.optional(o())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType()])}function f(){return t.z.discriminatedUnion("fn",[t.z.strictObject({fn:t.z.literal("none")}),t.z.strictObject({fn:t.z.undefined(),at:t.z.optional(n(4).or(t.z.array(n(4)))),"state.timeout":t.z.optional(t.z.number()),"change.timeout":t.z.optional(t.z.number()),cl:n(4),dt:n(2),ep:t.z.optional(a()),mf:t.z.optional(n(4)),eval:t.z.optional(r()),script:t.z.optional(o())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("zcl"),at:t.z.optional(n(4).or(t.z.array(n(4)))),"state.timeout":t.z.optional(t.z.number()),"change.timeout":t.z.optional(t.z.number()),cl:n(4),dt:n(2),ep:t.z.optional(a()),mf:t.z.optional(n(4)),eval:t.z.optional(r()),script:t.z.optional(o())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType(),t.z.strictObject({fn:t.z.literal("tuya"),dpid:t.z.number(),dt:n(2),eval:t.z.optional(r()),script:t.z.optional(o())}).refine(e=>!("eval"in e&&"script"in e),{message:"eval and script should not both be present"}).innerType()])}function g(e){return t.z.strictObject({$schema:t.z.optional(t.z.string()),schema:t.z.literal("devcap1.schema.json"),"doc:path":t.z.optional(t.z.string()),"doc:hdr":t.z.optional(t.z.string()),"md:known_issues":t.z.optional(t.z.array(t.z.string())),manufacturername:t.z.string().or(t.z.array(t.z.string())),modelid:t.z.string().or(t.z.array(t.z.string())),vendor:t.z.optional(t.z.string()),comment:t.z.optional(t.z.string()),matchexpr:t.z.optional(r()),path:t.z.optional(o()),product:t.z.optional(t.z.string()),sleeper:t.z.optional(t.z.boolean()),supportsMgmtBind:t.z.optional(t.z.boolean()),status:t.z.enum(["Draft","Bronze","Silver","Gold"]).describe("The code quality of the DDF file."),subdevices:t.z.array(y(e)),bindings:t.z.optional(t.z.array(O()))}).refine(i=>typeof i.manufacturername=="string"&&typeof i.modelid=="string"||Array.isArray(i.manufacturername)&&Array.isArray(i.modelid)&&i.manufacturername.length===i.modelid.length,{message:"manufacturername and modelid should be both strings or arrays with the same length.",path:["manufacturername","modelid"]}).innerType()}function y(e){return t.z.strictObject({type:t.z.union([t.z.enum(Object.keys(e.deviceTypes)),t.z.enum(Object.values(e.deviceTypes))]),restapi:t.z.enum(["/lights","/sensors"]),uuid:m(),fingerprint:t.z.optional(t.z.strictObject({profile:n(4),device:n(4),endpoint:a(),in:t.z.optional(t.z.array(n(4))),out:t.z.optional(t.z.array(n(4)))})),meta:t.z.optional(t.z.strictObject({values:t.z.any(),"group.endpoints":t.z.optional(t.z.array(t.z.number()))})),buttons:t.z.optional(t.z.any()),buttonevents:t.z.optional(t.z.any()),items:t.z.array(j(e)),example:t.z.optional(t.z.unknown())})}function j(e){return t.z.strictObject({name:t.z.enum(e.attributes),description:t.z.optional(t.z.string()),comment:t.z.optional(t.z.string()),public:t.z.optional(t.z.boolean()),static:t.z.optional(t.z.union([t.z.string(),t.z.number(),t.z.boolean()])),range:t.z.optional(t.z.tuple([t.z.number(),t.z.number()])),deprecated:t.z.optional(u()),access:t.z.optional(t.z.literal("R")),read:t.z.optional(d()),parse:t.z.optional(b()),write:t.z.optional(f()),awake:t.z.optional(t.z.boolean()),default:t.z.optional(t.z.unknown()),values:t.z.optional(t.z.unknown()),"refresh.interval":t.z.optional(t.z.number())})}function O(e){return t.z.discriminatedUnion("bind",[t.z.strictObject({bind:t.z.literal("unicast"),"src.ep":a(),"dst.ep":t.z.optional(a()),cl:n(4),report:t.z.optional(t.z.array(t.z.strictObject({at:n(4),dt:n(2),mf:t.z.optional(n(4)),min:t.z.number(),max:t.z.number(),change:t.z.optional(n().or(t.z.number()))})))}),t.z.strictObject({bind:t.z.literal("groupcast"),"src.ep":a(),cl:n(4),"config.group":t.z.number()})])}function T(e){return t.z.strictObject({$schema:t.z.optional(t.z.string()),schema:t.z.literal("resourceitem1.schema.json"),id:t.z.string(),description:t.z.string(),deprecated:t.z.optional(u()),datatype:t.z.enum(["String","Bool","Int8","Int16","Int32","Int64","UInt8","UInt16","UInt32","UInt64","Array","Array[3]","ISO 8601 timestamp"]),access:t.z.enum(["R","W","RW"]),public:t.z.boolean(),implicit:t.z.optional(t.z.boolean()),managed:t.z.optional(t.z.boolean()),static:t.z.optional(t.z.boolean()),virtual:t.z.optional(t.z.boolean()),parse:t.z.optional(b()),read:t.z.optional(d()),write:t.z.optional(f()),"refresh.interval":t.z.optional(t.z.number()),values:t.z.optional(t.z.unknown()),range:t.z.optional(t.z.tuple([t.z.number(),t.z.number()])),default:t.z.optional(t.z.unknown())})}function w(e){return t.z.strictObject({$schema:t.z.optional(t.z.string()),schema:t.z.literal("subdevice1.schema.json"),type:t.z.enum(Object.keys(e.deviceTypes)),name:t.z.enum(Object.values(e.deviceTypes)),restapi:t.z.enum(["/lights","/sensors"]),order:t.z.number(),uuid:m(),items:t.z.array(t.z.enum(e.attributes))})}function p(e){return t.z.discriminatedUnion("schema",[g(e),h(),T(),w(e)])}function S(e={attributes:[],manufacturers:{},deviceTypes:{}}){let i=p(e);const l=()=>{i=p(e)};return{generics:e,loadGeneric:z=>{const s=i.parse(z);switch(s.schema){case"constants1.schema.json":e.manufacturers={...e.manufacturers,...s.manufacturers},e.deviceTypes={...e.deviceTypes,...s["device-types"]};break;case"resourceitem1.schema.json":e.attributes.includes(s.id)||e.attributes.push(s.id);break;case"subdevice1.schema.json":break;case"devcap1.schema.json":throw new Error("Got invalid generic file, got data with schema 'devcap1.schema.json'.")}return l(),s},validate:z=>i.parse(z),getSchema:()=>i}}exports.createValidator=S;
@@ -1,3 +1,4 @@
1
+ import { ZodType } from "zod";
1
2
 
2
3
  export type DDF = {
3
4
  $schema?: string | undefined;
@@ -17,7 +18,7 @@ export type DDF = {
17
18
  /** The code quality of the DDF file. */
18
19
  status: "Draft" | "Bronze" | "Silver" | "Gold";
19
20
  subdevices: {
20
- type: "$TYPE_AIR_PURIFIER" | "$TYPE_AIR_QUALITY_SENSOR" | "$TYPE_ALARM_SENSOR" | "$TYPE_BATTERY_SENSOR" | "$TYPE_COLOR_DIMMABLE_LIGHT" | "$TYPE_COLOR_LIGHT" | "$TYPE_COLOR_TEMPERATURE_LIGHT" | "$TYPE_CONSUMPTION_SENSOR" | "$TYPE_DIMMABLE_LIGHT" | "$TYPE_DIMMABLE_PLUGIN_UNIT" | "$TYPE_DIMMER_SWITCH" | "$TYPE_DOOR_LOCK_CONTROLLER" | "$TYPE_DOOR_LOCK" | "$TYPE_EXTENDED_COLOR_LIGHT" | "$TYPE_FIRE_SENSOR" | "$TYPE_HUMIDITY_SENSOR" | "$TYPE_LIGHT_LEVEL_SENSOR" | "$TYPE_ON_OFF_LIGHT" | "$TYPE_ON_OFF_OUTPUT" | "$TYPE_ON_OFF_PLUGIN_UNIT" | "$TYPE_OPEN_CLOSE_SENSOR" | "$TYPE_POWER_SENSOR" | "$TYPE_PRESENCE_SENSOR" | "$TYPE_PRESSURE_SENSOR" | "$TYPE_RANGE_EXTENDER" | "$TYPE_RELATIVE_ROTARY" | "$TYPE_SMART_PLUG" | "$TYPE_SPECTRAL_SENSOR" | "$TYPE_SWITCH" | "$TYPE_TEMPERATURE_SENSOR" | "$TYPE_THERMOSTAT" | "$TYPE_VIBRATION_SENSOR" | "$TYPE_WARNING_DEVICE" | "$TYPE_WATER_LEAK_SENSOR" | "$TYPE_WINDOW_COVERING_DEVICE" | "$TYPE_ZGP_SWITCH" | "ZHAAirPurifier" | "ZHAAirQuality" | "ZHAAlarm" | "ZHABattery" | "Color dimmable light" | "Color light" | "Color temperature light" | "ZHAConsumption" | "Dimmable light" | "Dimmable plug-in unit" | "Dimmer switch" | "Door lock controller" | "Door Lock" | "Extended color light" | "ZHAFire" | "ZHAHumidity" | "ZHALightLevel" | "On/Off light" | "On/Off output" | "On/Off plug-in unit" | "ZHAOpenClose" | "ZHAPower" | "ZHAPresence" | "ZHAPressure" | "Range extender" | "ZHARelativeRotary" | "Smart plug" | "ZHASpectral" | "ZHASwitch" | "ZHATemperature" | "ZHAThermostat" | "ZHAVibration" | "Warning device" | "ZHAWater" | "Window covering device" | "ZGPSwitch" | "ZHAAncillaryControl" | "ZHATime" | "ZHACarbonMonoxide" | "ZHADoorLock";
21
+ type: ("$TYPE_AIR_PURIFIER" | "$TYPE_AIR_QUALITY_SENSOR" | "$TYPE_ALARM_SENSOR" | "$TYPE_ANCILLARY_CONTROL" | "$TYPE_BATTERY_SENSOR" | "$TYPE_CARBON_MONOXIDE" | "$TYPE_COLOR_DIMMABLE_LIGHT" | "$TYPE_COLOR_LIGHT" | "$TYPE_COLOR_TEMPERATURE_LIGHT" | "$TYPE_CONSUMPTION_SENSOR" | "$TYPE_DIMMABLE_LIGHT" | "$TYPE_DIMMABLE_PLUGIN_UNIT" | "$TYPE_DIMMER_SWITCH" | "$TYPE_DOOR_LOCK_CONTROLLER" | "$TYPE_DOOR_LOCK" | "$TYPE_EXTENDED_COLOR_LIGHT" | "$TYPE_FIRE_SENSOR" | "$TYPE_HUMIDITY_SENSOR" | "$TYPE_LIGHT_LEVEL_SENSOR" | "$TYPE_ON_OFF_LIGHT" | "$TYPE_ON_OFF_OUTPUT" | "$TYPE_ON_OFF_PLUGIN_UNIT" | "$TYPE_OPEN_CLOSE_SENSOR" | "$TYPE_POWER_SENSOR" | "$TYPE_PRESENCE_SENSOR" | "$TYPE_PRESSURE_SENSOR" | "$TYPE_RANGE_EXTENDER" | "$TYPE_RELATIVE_ROTARY" | "$TYPE_SMART_PLUG" | "$TYPE_SPECTRAL_SENSOR" | "$TYPE_SWITCH" | "$TYPE_TEMPERATURE_SENSOR" | "$TYPE_THERMOSTAT" | "$TYPE_TIME" | "$TYPE_VIBRATION_SENSOR" | "$TYPE_WARNING_DEVICE" | "$TYPE_WATER_LEAK_SENSOR" | "$TYPE_WINDOW_COVERING_DEVICE" | "$TYPE_ZGP_SWITCH") | ("ZHAAirPurifier" | "ZHAAirQuality" | "ZHAAlarm" | "ZHAAncillaryControl" | "ZHABattery" | "ZHACarbonMonoxide" | "Color dimmable light" | "Color light" | "Color temperature light" | "ZHAConsumption" | "Dimmable light" | "Dimmable plug-in unit" | "Dimmer switch" | "Door lock controller" | "ZHADoorLock" | "Extended color light" | "ZHAFire" | "ZHAHumidity" | "ZHALightLevel" | "On/Off light" | "On/Off output" | "On/Off plug-in unit" | "ZHAOpenClose" | "ZHAPower" | "ZHAPresence" | "ZHAPressure" | "Range extender" | "ZHARelativeRotary" | "Smart plug" | "ZHASpectral" | "ZHASwitch" | "ZHATemperature" | "ZHAThermostat" | "ZHATime" | "ZHAVibration" | "Warning device" | "ZHAWater" | "Window covering device" | "ZGPSwitch");
21
22
  restapi: "/lights" | "/sensors";
22
23
  uuid: [
23
24
  "$address.ext",
@@ -41,7 +42,7 @@ export type DDF = {
41
42
  buttons?: any | undefined;
42
43
  buttonevents?: any | undefined;
43
44
  items: {
44
- name: string;
45
+ name: "state/windowopen" | "state/water" | "state/voltage" | "state/vibrationstrength" | "state/vibration" | "state/valve" | "state/utc" | "state/tiltangle" | "state/tilt" | "state/test" | "state/temperature" | "state/tampered" | "state/speed" | "state/seconds_remaining" | "state/sat" | "state/rotaryevent" | "state/replacefilter" | "state/reachable" | "state/production" | "state/pressure" | "state/presenceevent" | "state/presence" | "state/power" | "state/pm2_5" | "state/panel" | "state/orientation_z" | "state/orientation_y" | "state/orientation_x" | "state/orientation" | "state/open" | "state/on" | "state/mountingmodeactive" | "state/lux" | "state/lowbattery" | "state/lockstate" | "state/localtime" | "state/lightlevel" | "state/lift" | "state/lastupdated" | "state/lastset" | "state/lastcheckin" | "state/humidity" | "state/hue" | "state/heating" | "state/gradient" | "state/gesture" | "state/fire" | "state/filterruntime" | "state/expectedrotation" | "state/expectedeventduration" | "state/eventduration" | "state/errorcode" | "state/effect" | "state/deviceruntime" | "state/daylight" | "state/dark" | "state/current" | "state/current_P3" | "state/current_P2" | "state/current_P1" | "state/ct" | "state/consumption" | "state/consumption_2" | "state/y" | "state/x" | "state/colormode" | "state/charging" | "state/carbonmonoxide" | "state/buttonevent" | "state/bri" | "state/battery" | "state/angle" | "state/alert" | "state/alarm" | "state/airqualityppb" | "state/airquality" | "state/action" | "config/windowopen_set" | "config/windowcoveringtype" | "config/usertest" | "config/unoccupiedheatsetpoint" | "config/triggerdistance" | "config/tholdoffset" | "config/tholddark" | "config/temperature" | "config/swingmode" | "config/sensitivitymax" | "config/sensitivity" | "config/selftest" | "config/schedule_on" | "config/schedule" | "config/resetpresence" | "config/reachable" | "config/pulseconfiguration" | "config/preset" | "config/pending" | "config/on/startup" | "config/on" | "config/offset" | "config/mountingmode" | "config/mode" | "config/locked" | "config/lock" | "config/ledindication" | "config/interfacemode" | "config/heatsetpoint" | "config/group" | "config/filterlifetime" | "config/fanmode" | "config/externalwindowopen" | "config/externalsensortemp" | "config/enrolled" | "config/duration" | "config/displayflipped" | "config/devicemode" | "config/delay" | "config/ctmin" | "config/ctmax" | "config/coolsetpoint" | "config/controlsequence" | "config/configured" | "config/colorcapabilities" | "config/color/xy/startup_y" | "config/color/xy/startup_x" | "config/color/gradient/reversed" | "config/color/execute_if_off" | "config/color/ct/startup" | "config/clickmode" | "config/checkin" | "config/bri/startup" | "config/bri/onoff_transitiontime" | "config/bri/on_level" | "config/bri/min" | "config/bri/max" | "config/bri/execute_if_off" | "config/battery" | "config/allowtouchlink" | "config/alert" | "cap/transition_block" | "cap/sleeper" | "cap/on/off_with_effect" | "cap/groups/not_supported" | "cap/color/xy/red_y" | "cap/color/xy/red_x" | "cap/color/xy/green_y" | "cap/color/xy/green_x" | "cap/color/xy/blue_y" | "cap/color/xy/blue_x" | "cap/color/gradient/styles" | "cap/color/gradient/pixel_length" | "cap/color/gradient/pixel_count" | "cap/color/gradient/max_segments" | "cap/color/gamut_type" | "cap/color/effects" | "cap/color/ct/min" | "cap/color/ct/max" | "cap/color/ct/computes_xy" | "cap/color/capabilities" | "cap/bri/move_with_onoff" | "cap/bri/min_dim_level" | "cap/alert/trigger_effect" | "attr/uniqueid" | "attr/type" | "attr/swversion" | "attr/swconfigid" | "attr/productname" | "attr/productid" | "attr/powerup" | "attr/poweronlevel" | "attr/poweronct" | "attr/name" | "attr/modelid" | "attr/mode" | "attr/manufacturername" | "attr/lastseen" | "attr/lastannounced" | "attr/id";
45
46
  description?: string | undefined;
46
47
  comment?: string | undefined;
47
48
  public?: boolean | undefined;
@@ -93,12 +94,14 @@ export type DDF = {
93
94
  script?: string | undefined;
94
95
  } | {
95
96
  fn: "ias:zonestatus";
96
- mask: "alarm1" | "alarm2";
97
+ mask?: (("alarm1" | "alarm2") | "alarm1,alarm2") | undefined;
97
98
  } | {
98
99
  fn: "numtostr";
99
100
  srcitem: "state/airqualityppb" | "state/pm2_5";
100
101
  op: "le";
101
102
  to: any;
103
+ } | {
104
+ fn: "time";
102
105
  } | {
103
106
  fn: "xiaomi:special";
104
107
  ep?: (string | number) | undefined;
@@ -169,8 +172,158 @@ export type DDF = {
169
172
  cl: string;
170
173
  "config.group": number;
171
174
  })[] | undefined;
175
+ } | {
176
+ $schema?: string | undefined;
177
+ schema: "constants1.schema.json";
178
+ manufacturers: {
179
+ [x: string]: string;
180
+ };
181
+ "device-types": {
182
+ [x: string]: string;
183
+ };
184
+ } | {
185
+ $schema?: string | undefined;
186
+ schema: "resourceitem1.schema.json";
187
+ id: string;
188
+ description: string;
189
+ deprecated?: string | undefined;
190
+ datatype: "String" | "Bool" | "Int8" | "Int16" | "Int32" | "Int64" | "UInt8" | "UInt16" | "UInt32" | "UInt64" | "Array" | "Array[3]" | "ISO 8601 timestamp";
191
+ access: "R" | "W" | "RW";
192
+ public: boolean;
193
+ implicit?: boolean | undefined;
194
+ managed?: boolean | undefined;
195
+ static?: boolean | undefined;
196
+ virtual?: boolean | undefined;
197
+ parse?: ({
198
+ fn?: undefined;
199
+ at?: string | undefined;
200
+ cl: string;
201
+ cppsrc?: string | undefined;
202
+ ep?: (string | number) | undefined;
203
+ cmd?: string | undefined;
204
+ mf?: string | undefined;
205
+ eval?: string | undefined;
206
+ script?: string | undefined;
207
+ } | {
208
+ fn: "zcl";
209
+ at?: string | undefined;
210
+ cl: string;
211
+ cppsrc?: string | undefined;
212
+ ep?: (string | number) | undefined;
213
+ cmd?: string | undefined;
214
+ mf?: string | undefined;
215
+ eval?: string | undefined;
216
+ script?: string | undefined;
217
+ } | {
218
+ fn: "ias:zonestatus";
219
+ mask?: (("alarm1" | "alarm2") | "alarm1,alarm2") | undefined;
220
+ } | {
221
+ fn: "numtostr";
222
+ srcitem: "state/airqualityppb" | "state/pm2_5";
223
+ op: "le";
224
+ to: any;
225
+ } | {
226
+ fn: "time";
227
+ } | {
228
+ fn: "xiaomi:special";
229
+ ep?: (string | number) | undefined;
230
+ at?: string | undefined;
231
+ idx: string;
232
+ eval?: string | undefined;
233
+ script?: string | undefined;
234
+ } | {
235
+ fn: "tuya";
236
+ dpid: number;
237
+ eval?: string | undefined;
238
+ script?: string | undefined;
239
+ }) | undefined;
240
+ read?: ({
241
+ fn: "none";
242
+ } | {
243
+ fn?: undefined;
244
+ at?: (string | string[]) | undefined;
245
+ cl: string;
246
+ ep?: (string | number) | undefined;
247
+ mf?: string | undefined;
248
+ eval?: string | undefined;
249
+ } | {
250
+ fn: "zcl";
251
+ at?: (string | string[]) | undefined;
252
+ cl: string;
253
+ ep?: (string | number) | undefined;
254
+ mf?: string | undefined;
255
+ eval?: string | undefined;
256
+ } | {
257
+ fn: "tuya";
258
+ }) | undefined;
259
+ write?: ({
260
+ fn: "none";
261
+ } | {
262
+ fn?: undefined;
263
+ at?: (string | string[]) | undefined;
264
+ "state.timeout"?: number | undefined;
265
+ "change.timeout"?: number | undefined;
266
+ cl: string;
267
+ dt: string;
268
+ ep?: (string | number) | undefined;
269
+ mf?: string | undefined;
270
+ eval?: string | undefined;
271
+ script?: string | undefined;
272
+ } | {
273
+ fn: "zcl";
274
+ at?: (string | string[]) | undefined;
275
+ "state.timeout"?: number | undefined;
276
+ "change.timeout"?: number | undefined;
277
+ cl: string;
278
+ dt: string;
279
+ ep?: (string | number) | undefined;
280
+ mf?: string | undefined;
281
+ eval?: string | undefined;
282
+ script?: string | undefined;
283
+ } | {
284
+ fn: "tuya";
285
+ dpid: number;
286
+ dt: string;
287
+ eval?: string | undefined;
288
+ script?: string | undefined;
289
+ }) | undefined;
290
+ "refresh.interval"?: number | undefined;
291
+ values?: unknown | undefined;
292
+ range?: [
293
+ number,
294
+ number
295
+ ] | undefined;
296
+ default?: unknown | undefined;
297
+ } | {
298
+ $schema?: string | undefined;
299
+ schema: "subdevice1.schema.json";
300
+ type: "$TYPE_AIR_PURIFIER" | "$TYPE_AIR_QUALITY_SENSOR" | "$TYPE_ALARM_SENSOR" | "$TYPE_ANCILLARY_CONTROL" | "$TYPE_BATTERY_SENSOR" | "$TYPE_CARBON_MONOXIDE" | "$TYPE_COLOR_DIMMABLE_LIGHT" | "$TYPE_COLOR_LIGHT" | "$TYPE_COLOR_TEMPERATURE_LIGHT" | "$TYPE_CONSUMPTION_SENSOR" | "$TYPE_DIMMABLE_LIGHT" | "$TYPE_DIMMABLE_PLUGIN_UNIT" | "$TYPE_DIMMER_SWITCH" | "$TYPE_DOOR_LOCK_CONTROLLER" | "$TYPE_DOOR_LOCK" | "$TYPE_EXTENDED_COLOR_LIGHT" | "$TYPE_FIRE_SENSOR" | "$TYPE_HUMIDITY_SENSOR" | "$TYPE_LIGHT_LEVEL_SENSOR" | "$TYPE_ON_OFF_LIGHT" | "$TYPE_ON_OFF_OUTPUT" | "$TYPE_ON_OFF_PLUGIN_UNIT" | "$TYPE_OPEN_CLOSE_SENSOR" | "$TYPE_POWER_SENSOR" | "$TYPE_PRESENCE_SENSOR" | "$TYPE_PRESSURE_SENSOR" | "$TYPE_RANGE_EXTENDER" | "$TYPE_RELATIVE_ROTARY" | "$TYPE_SMART_PLUG" | "$TYPE_SPECTRAL_SENSOR" | "$TYPE_SWITCH" | "$TYPE_TEMPERATURE_SENSOR" | "$TYPE_THERMOSTAT" | "$TYPE_TIME" | "$TYPE_VIBRATION_SENSOR" | "$TYPE_WARNING_DEVICE" | "$TYPE_WATER_LEAK_SENSOR" | "$TYPE_WINDOW_COVERING_DEVICE" | "$TYPE_ZGP_SWITCH";
301
+ name: "ZHAAirPurifier" | "ZHAAirQuality" | "ZHAAlarm" | "ZHAAncillaryControl" | "ZHABattery" | "ZHACarbonMonoxide" | "Color dimmable light" | "Color light" | "Color temperature light" | "ZHAConsumption" | "Dimmable light" | "Dimmable plug-in unit" | "Dimmer switch" | "Door lock controller" | "ZHADoorLock" | "Extended color light" | "ZHAFire" | "ZHAHumidity" | "ZHALightLevel" | "On/Off light" | "On/Off output" | "On/Off plug-in unit" | "ZHAOpenClose" | "ZHAPower" | "ZHAPresence" | "ZHAPressure" | "Range extender" | "ZHARelativeRotary" | "Smart plug" | "ZHASpectral" | "ZHASwitch" | "ZHATemperature" | "ZHAThermostat" | "ZHATime" | "ZHAVibration" | "Warning device" | "ZHAWater" | "Window covering device" | "ZGPSwitch";
302
+ restapi: "/lights" | "/sensors";
303
+ order: number;
304
+ uuid: [
305
+ "$address.ext",
306
+ string
307
+ ] | [
308
+ "$address.ext",
309
+ string,
310
+ string
311
+ ];
312
+ items: ("state/windowopen" | "state/water" | "state/voltage" | "state/vibrationstrength" | "state/vibration" | "state/valve" | "state/utc" | "state/tiltangle" | "state/tilt" | "state/test" | "state/temperature" | "state/tampered" | "state/speed" | "state/seconds_remaining" | "state/sat" | "state/rotaryevent" | "state/replacefilter" | "state/reachable" | "state/production" | "state/pressure" | "state/presenceevent" | "state/presence" | "state/power" | "state/pm2_5" | "state/panel" | "state/orientation_z" | "state/orientation_y" | "state/orientation_x" | "state/orientation" | "state/open" | "state/on" | "state/mountingmodeactive" | "state/lux" | "state/lowbattery" | "state/lockstate" | "state/localtime" | "state/lightlevel" | "state/lift" | "state/lastupdated" | "state/lastset" | "state/lastcheckin" | "state/humidity" | "state/hue" | "state/heating" | "state/gradient" | "state/gesture" | "state/fire" | "state/filterruntime" | "state/expectedrotation" | "state/expectedeventduration" | "state/eventduration" | "state/errorcode" | "state/effect" | "state/deviceruntime" | "state/daylight" | "state/dark" | "state/current" | "state/current_P3" | "state/current_P2" | "state/current_P1" | "state/ct" | "state/consumption" | "state/consumption_2" | "state/y" | "state/x" | "state/colormode" | "state/charging" | "state/carbonmonoxide" | "state/buttonevent" | "state/bri" | "state/battery" | "state/angle" | "state/alert" | "state/alarm" | "state/airqualityppb" | "state/airquality" | "state/action" | "config/windowopen_set" | "config/windowcoveringtype" | "config/usertest" | "config/unoccupiedheatsetpoint" | "config/triggerdistance" | "config/tholdoffset" | "config/tholddark" | "config/temperature" | "config/swingmode" | "config/sensitivitymax" | "config/sensitivity" | "config/selftest" | "config/schedule_on" | "config/schedule" | "config/resetpresence" | "config/reachable" | "config/pulseconfiguration" | "config/preset" | "config/pending" | "config/on/startup" | "config/on" | "config/offset" | "config/mountingmode" | "config/mode" | "config/locked" | "config/lock" | "config/ledindication" | "config/interfacemode" | "config/heatsetpoint" | "config/group" | "config/filterlifetime" | "config/fanmode" | "config/externalwindowopen" | "config/externalsensortemp" | "config/enrolled" | "config/duration" | "config/displayflipped" | "config/devicemode" | "config/delay" | "config/ctmin" | "config/ctmax" | "config/coolsetpoint" | "config/controlsequence" | "config/configured" | "config/colorcapabilities" | "config/color/xy/startup_y" | "config/color/xy/startup_x" | "config/color/gradient/reversed" | "config/color/execute_if_off" | "config/color/ct/startup" | "config/clickmode" | "config/checkin" | "config/bri/startup" | "config/bri/onoff_transitiontime" | "config/bri/on_level" | "config/bri/min" | "config/bri/max" | "config/bri/execute_if_off" | "config/battery" | "config/allowtouchlink" | "config/alert" | "cap/transition_block" | "cap/sleeper" | "cap/on/off_with_effect" | "cap/groups/not_supported" | "cap/color/xy/red_y" | "cap/color/xy/red_x" | "cap/color/xy/green_y" | "cap/color/xy/green_x" | "cap/color/xy/blue_y" | "cap/color/xy/blue_x" | "cap/color/gradient/styles" | "cap/color/gradient/pixel_length" | "cap/color/gradient/pixel_count" | "cap/color/gradient/max_segments" | "cap/color/gamut_type" | "cap/color/effects" | "cap/color/ct/min" | "cap/color/ct/max" | "cap/color/ct/computes_xy" | "cap/color/capabilities" | "cap/bri/move_with_onoff" | "cap/bri/min_dim_level" | "cap/alert/trigger_effect" | "attr/uniqueid" | "attr/type" | "attr/swversion" | "attr/swconfigid" | "attr/productname" | "attr/productid" | "attr/powerup" | "attr/poweronlevel" | "attr/poweronct" | "attr/name" | "attr/modelid" | "attr/mode" | "attr/manufacturername" | "attr/lastseen" | "attr/lastannounced" | "attr/id")[];
172
313
  };
173
314
 
174
- export declare function validate(data: unknown): DDF
315
+ export interface GenericsData {
316
+ attributes: string[]
317
+ manufacturers: Record<string, string>
318
+ deviceTypes: Record<string, string>
319
+ }
320
+
321
+
322
+ export declare function createValidator(generics?: GenericsData): {
323
+ generics: GenericsData;
324
+ loadGeneric: (data: unknown) => DDF;
325
+ validate: (data: unknown) => DDF;
326
+ getSchema: () => ZodType<DDF>;
327
+ };
175
328
 
176
329
  export {};
@@ -1,121 +1,192 @@
1
1
  import { z as t } from "zod";
2
- const p = [
3
- "$TYPE_AIR_PURIFIER",
4
- "$TYPE_AIR_QUALITY_SENSOR",
5
- "$TYPE_ALARM_SENSOR",
6
- "$TYPE_BATTERY_SENSOR",
7
- "$TYPE_COLOR_DIMMABLE_LIGHT",
8
- "$TYPE_COLOR_LIGHT",
9
- "$TYPE_COLOR_TEMPERATURE_LIGHT",
10
- "$TYPE_CONSUMPTION_SENSOR",
11
- "$TYPE_DIMMABLE_LIGHT",
12
- "$TYPE_DIMMABLE_PLUGIN_UNIT",
13
- "$TYPE_DIMMER_SWITCH",
14
- "$TYPE_DOOR_LOCK_CONTROLLER",
15
- "$TYPE_DOOR_LOCK",
16
- "$TYPE_EXTENDED_COLOR_LIGHT",
17
- "$TYPE_FIRE_SENSOR",
18
- "$TYPE_HUMIDITY_SENSOR",
19
- "$TYPE_LIGHT_LEVEL_SENSOR",
20
- "$TYPE_ON_OFF_LIGHT",
21
- "$TYPE_ON_OFF_OUTPUT",
22
- "$TYPE_ON_OFF_PLUGIN_UNIT",
23
- "$TYPE_OPEN_CLOSE_SENSOR",
24
- "$TYPE_POWER_SENSOR",
25
- "$TYPE_PRESENCE_SENSOR",
26
- "$TYPE_PRESSURE_SENSOR",
27
- "$TYPE_RANGE_EXTENDER",
28
- "$TYPE_RELATIVE_ROTARY",
29
- "$TYPE_SMART_PLUG",
30
- "$TYPE_SPECTRAL_SENSOR",
31
- "$TYPE_SWITCH",
32
- "$TYPE_TEMPERATURE_SENSOR",
33
- "$TYPE_THERMOSTAT",
34
- "$TYPE_VIBRATION_SENSOR",
35
- "$TYPE_WARNING_DEVICE",
36
- "$TYPE_WATER_LEAK_SENSOR",
37
- "$TYPE_WINDOW_COVERING_DEVICE",
38
- "$TYPE_ZGP_SWITCH",
39
- "ZHAAirPurifier",
40
- "ZHAAirQuality",
41
- "ZHAAlarm",
42
- "ZHABattery",
43
- "Color dimmable light",
44
- "Color light",
45
- "Color temperature light",
46
- "ZHAConsumption",
47
- "Dimmable light",
48
- "Dimmable plug-in unit",
49
- "Dimmer switch",
50
- "Door lock controller",
51
- "Door Lock",
52
- "Extended color light",
53
- "ZHAFire",
54
- "ZHAHumidity",
55
- "ZHALightLevel",
56
- "On/Off light",
57
- "On/Off output",
58
- "On/Off plug-in unit",
59
- "ZHAOpenClose",
60
- "ZHAPower",
61
- "ZHAPresence",
62
- "ZHAPressure",
63
- "Range extender",
64
- "ZHARelativeRotary",
65
- "Smart plug",
66
- "ZHASpectral",
67
- "ZHASwitch",
68
- "ZHATemperature",
69
- "ZHAThermostat",
70
- "ZHAVibration",
71
- "Warning device",
72
- "ZHAWater",
73
- "Window covering device",
74
- "ZGPSwitch",
75
- "ZHAAncillaryControl",
76
- "ZHATime",
77
- "ZHACarbonMonoxide",
78
- "ZHADoorLock"
79
- ];
80
- function n(e = void 0) {
81
- return e === void 0 ? t.string() : t.string().length(2 + e);
2
+ function v(e) {
3
+ return t.strictObject({
4
+ $schema: t.optional(t.string()),
5
+ schema: t.literal("constants1.schema.json"),
6
+ manufacturers: t.record(t.string().startsWith("$MF_"), t.string()),
7
+ "device-types": t.record(t.string().startsWith("$TYPE_"), t.string())
8
+ });
82
9
  }
83
- function o() {
84
- return t.string();
10
+ function m() {
11
+ return t.string().regex(
12
+ // Regex for AAAA-MM-JJ
13
+ /^(\d{4})-(?:(?:0[1-9])|(?:1[0-2]))-(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01]))$/,
14
+ "Invalid date value"
15
+ );
85
16
  }
86
- function c() {
87
- return t.string();
17
+ function n(e = void 0) {
18
+ const i = "Invalid hexadecimal value";
19
+ return e === void 0 ? t.string().regex(/^0x[0-9a-fA-F]+$/, i) : t.string().regex(new RegExp(`^0x[0-9a-fA-F]{${e}}$`), i);
88
20
  }
89
- function i() {
21
+ function a() {
90
22
  return t.union([
91
23
  n(2),
92
24
  t.number().min(0).max(255)
93
25
  ]);
94
26
  }
95
- function r() {
96
- return t.string();
97
- }
98
- function u() {
27
+ function g() {
99
28
  return t.custom((e) => {
100
29
  if (!Array.isArray(e) || e.length % 2 !== 0)
101
30
  return !1;
102
- for (let a = 0; a < e.length; a += 2) {
103
- const l = e[a], s = e[a + 1];
104
- if (typeof l != "number" || typeof s != "string")
31
+ for (let i = 0; i < e.length; i += 2) {
32
+ const l = e[i], p = e[i + 1];
33
+ if (typeof l != "number" || typeof p != "string")
105
34
  return !1;
106
35
  }
107
36
  return !0;
108
37
  }, "The value must be an array with an even number of values and alternating between number and string.");
109
38
  }
110
- function b(e) {
111
- return m().parse(e);
39
+ function d() {
40
+ return t.union([
41
+ t.tuple([
42
+ t.literal("$address.ext"),
43
+ n(2)
44
+ ]),
45
+ t.tuple([
46
+ t.literal("$address.ext"),
47
+ n(2),
48
+ n(4)
49
+ ])
50
+ ]);
112
51
  }
113
- function m() {
114
- return t.discriminatedUnion("schema", [
115
- E().innerType()
52
+ function o() {
53
+ return t.string();
54
+ }
55
+ function r() {
56
+ return t.string();
57
+ }
58
+ function b() {
59
+ return t.discriminatedUnion("fn", [
60
+ t.strictObject({
61
+ fn: t.literal("none")
62
+ }),
63
+ t.strictObject({
64
+ fn: t.undefined(),
65
+ at: t.optional(n(4).or(t.array(n(4)))),
66
+ cl: n(4),
67
+ ep: t.optional(a()),
68
+ mf: t.optional(n(4)),
69
+ eval: t.optional(r())
70
+ }),
71
+ t.strictObject({
72
+ fn: t.literal("zcl"),
73
+ at: t.optional(n(4).or(t.array(n(4)))),
74
+ cl: n(4),
75
+ ep: t.optional(a()),
76
+ mf: t.optional(n(4)),
77
+ eval: t.optional(r())
78
+ }),
79
+ t.strictObject({
80
+ fn: t.literal("tuya")
81
+ })
116
82
  ]);
117
83
  }
118
- function E() {
84
+ function f() {
85
+ return t.discriminatedUnion("fn", [
86
+ t.strictObject({
87
+ fn: t.undefined(),
88
+ at: t.optional(n(4)),
89
+ cl: n(4),
90
+ cppsrc: t.optional(t.string()),
91
+ ep: t.optional(a()),
92
+ cmd: t.optional(n(2)),
93
+ mf: t.optional(n(4)),
94
+ eval: t.optional(r()),
95
+ script: t.optional(o())
96
+ }).refine((e) => !("eval" in e && "script" in e), {
97
+ message: "eval and script should not both be present"
98
+ }).innerType(),
99
+ t.strictObject({
100
+ fn: t.literal("zcl"),
101
+ at: t.optional(n(4)),
102
+ cl: n(4),
103
+ cppsrc: t.optional(t.string()),
104
+ ep: t.optional(a()),
105
+ cmd: t.optional(n(2)),
106
+ mf: t.optional(n(4)),
107
+ eval: t.optional(r()),
108
+ script: t.optional(o())
109
+ }).refine((e) => !("eval" in e && "script" in e), {
110
+ message: "eval and script should not both be present"
111
+ }).innerType(),
112
+ t.strictObject({
113
+ fn: t.literal("ias:zonestatus"),
114
+ mask: t.optional(t.enum(["alarm1", "alarm2"]).or(t.literal("alarm1,alarm2")))
115
+ }),
116
+ t.strictObject({
117
+ fn: t.literal("numtostr"),
118
+ srcitem: t.enum(["state/airqualityppb", "state/pm2_5"]),
119
+ op: t.literal("le"),
120
+ to: g()
121
+ }),
122
+ t.strictObject({
123
+ fn: t.literal("time")
124
+ }),
125
+ t.strictObject({
126
+ fn: t.literal("xiaomi:special"),
127
+ ep: t.optional(a()),
128
+ at: t.optional(n(4)),
129
+ idx: n(2),
130
+ eval: t.optional(r()),
131
+ script: t.optional(o())
132
+ }).refine((e) => !("eval" in e && "script" in e), {
133
+ message: "eval and script should not both be present"
134
+ }).innerType(),
135
+ t.strictObject({
136
+ fn: t.literal("tuya"),
137
+ dpid: t.number(),
138
+ eval: t.optional(r()),
139
+ script: t.optional(o())
140
+ }).refine((e) => !("eval" in e && "script" in e), {
141
+ message: "eval and script should not both be present"
142
+ }).innerType()
143
+ ]);
144
+ }
145
+ function h() {
146
+ return t.discriminatedUnion("fn", [
147
+ t.strictObject({
148
+ fn: t.literal("none")
149
+ }),
150
+ t.strictObject({
151
+ fn: t.undefined(),
152
+ at: t.optional(n(4).or(t.array(n(4)))),
153
+ "state.timeout": t.optional(t.number()),
154
+ "change.timeout": t.optional(t.number()),
155
+ cl: n(4),
156
+ dt: n(2),
157
+ ep: t.optional(a()),
158
+ mf: t.optional(n(4)),
159
+ eval: t.optional(r()),
160
+ script: t.optional(o())
161
+ }).refine((e) => !("eval" in e && "script" in e), {
162
+ message: "eval and script should not both be present"
163
+ }).innerType(),
164
+ t.strictObject({
165
+ fn: t.literal("zcl"),
166
+ at: t.optional(n(4).or(t.array(n(4)))),
167
+ "state.timeout": t.optional(t.number()),
168
+ "change.timeout": t.optional(t.number()),
169
+ cl: n(4),
170
+ dt: n(2),
171
+ ep: t.optional(a()),
172
+ mf: t.optional(n(4)),
173
+ eval: t.optional(r()),
174
+ script: t.optional(o())
175
+ }).refine((e) => !("eval" in e && "script" in e), {
176
+ message: "eval and script should not both be present"
177
+ }).innerType(),
178
+ t.strictObject({
179
+ fn: t.literal("tuya"),
180
+ dpid: t.number(),
181
+ dt: n(2),
182
+ eval: t.optional(r()),
183
+ script: t.optional(o())
184
+ }).refine((e) => !("eval" in e && "script" in e), {
185
+ message: "eval and script should not both be present"
186
+ }).innerType()
187
+ ]);
188
+ }
189
+ function y(e) {
119
190
  return t.strictObject({
120
191
  $schema: t.optional(t.string()),
121
192
  schema: t.literal("devcap1.schema.json"),
@@ -126,38 +197,31 @@ function E() {
126
197
  modelid: t.string().or(t.array(t.string())),
127
198
  vendor: t.optional(t.string()),
128
199
  comment: t.optional(t.string()),
129
- matchexpr: t.optional(o()),
130
- path: t.optional(r()),
200
+ matchexpr: t.optional(r()),
201
+ path: t.optional(o()),
131
202
  product: t.optional(t.string()),
132
203
  sleeper: t.optional(t.boolean()),
133
204
  supportsMgmtBind: t.optional(t.boolean()),
134
205
  status: t.enum(["Draft", "Bronze", "Silver", "Gold"]).describe("The code quality of the DDF file."),
135
- subdevices: t.array(d()),
136
- bindings: t.optional(t.array(_()))
137
- }).refine((e) => typeof e.manufacturername == "string" && typeof e.modelid == "string" || Array.isArray(e.manufacturername) && Array.isArray(e.modelid) && e.manufacturername.length === e.modelid.length, {
206
+ subdevices: t.array(j(e)),
207
+ bindings: t.optional(t.array(T()))
208
+ }).refine((i) => typeof i.manufacturername == "string" && typeof i.modelid == "string" || Array.isArray(i.manufacturername) && Array.isArray(i.modelid) && i.manufacturername.length === i.modelid.length, {
138
209
  message: "manufacturername and modelid should be both strings or arrays with the same length.",
139
210
  path: ["manufacturername", "modelid"]
140
- });
211
+ }).innerType();
141
212
  }
142
- function d() {
213
+ function j(e) {
143
214
  return t.strictObject({
144
- type: t.enum(p),
145
- restapi: t.enum(["/lights", "/sensors"]),
146
- uuid: t.union([
147
- t.tuple([
148
- t.literal("$address.ext"),
149
- n(2)
150
- ]),
151
- t.tuple([
152
- t.literal("$address.ext"),
153
- n(2),
154
- n(4)
155
- ])
215
+ type: t.union([
216
+ t.enum(Object.keys(e.deviceTypes)),
217
+ t.enum(Object.values(e.deviceTypes))
156
218
  ]),
219
+ restapi: t.enum(["/lights", "/sensors"]),
220
+ uuid: d(),
157
221
  fingerprint: t.optional(t.strictObject({
158
222
  profile: n(4),
159
223
  device: n(4),
160
- endpoint: i(),
224
+ endpoint: a(),
161
225
  in: t.optional(t.array(n(4))),
162
226
  out: t.optional(t.array(n(4)))
163
227
  })),
@@ -170,160 +234,35 @@ function d() {
170
234
  buttons: t.optional(t.any()),
171
235
  // TODO validate this
172
236
  buttonevents: t.optional(t.any()),
173
- items: t.array(T()),
237
+ items: t.array(O(e)),
174
238
  example: t.optional(t.unknown())
175
239
  });
176
240
  }
177
- function T() {
241
+ function O(e) {
178
242
  return t.strictObject({
179
- name: t.string(),
243
+ name: t.enum(e.attributes),
180
244
  description: t.optional(t.string()),
181
245
  comment: t.optional(t.string()),
182
246
  public: t.optional(t.boolean()),
183
247
  static: t.optional(t.union([t.string(), t.number(), t.boolean()])),
184
248
  range: t.optional(t.tuple([t.number(), t.number()])),
185
- deprecated: t.optional(c()),
249
+ deprecated: t.optional(m()),
186
250
  access: t.optional(t.literal("R")),
187
- read: t.optional(
188
- t.discriminatedUnion("fn", [
189
- t.strictObject({
190
- fn: t.literal("none")
191
- }),
192
- t.strictObject({
193
- fn: t.undefined(),
194
- at: t.optional(n(4).or(t.array(n(4)))),
195
- cl: n(4),
196
- ep: t.optional(i()),
197
- mf: t.optional(n(4)),
198
- eval: t.optional(o())
199
- }),
200
- t.strictObject({
201
- fn: t.literal("zcl"),
202
- at: t.optional(n(4).or(t.array(n(4)))),
203
- cl: n(4),
204
- ep: t.optional(i()),
205
- mf: t.optional(n(4)),
206
- eval: t.optional(o())
207
- }),
208
- t.strictObject({
209
- fn: t.literal("tuya")
210
- })
211
- ])
212
- ),
213
- parse: t.optional(
214
- t.discriminatedUnion("fn", [
215
- t.strictObject({
216
- fn: t.undefined(),
217
- at: t.optional(n(4)),
218
- cl: n(4),
219
- cppsrc: t.optional(t.string()),
220
- ep: t.optional(i()),
221
- cmd: t.optional(n(2)),
222
- mf: t.optional(n(4)),
223
- eval: t.optional(o()),
224
- script: t.optional(r())
225
- }).refine((e) => !("eval" in e && "script" in e), {
226
- message: "eval and script should not both be present"
227
- }).innerType(),
228
- t.strictObject({
229
- fn: t.literal("zcl"),
230
- at: t.optional(n(4)),
231
- cl: n(4),
232
- cppsrc: t.optional(t.string()),
233
- ep: t.optional(i()),
234
- cmd: t.optional(n(2)),
235
- mf: t.optional(n(4)),
236
- eval: t.optional(o()),
237
- script: t.optional(r())
238
- }).refine((e) => !("eval" in e && "script" in e), {
239
- message: "eval and script should not both be present"
240
- }).innerType(),
241
- t.strictObject({
242
- fn: t.literal("ias:zonestatus"),
243
- mask: t.enum(["alarm1", "alarm2"])
244
- }),
245
- t.strictObject({
246
- fn: t.literal("numtostr"),
247
- srcitem: t.enum(["state/airqualityppb", "state/pm2_5"]),
248
- op: t.literal("le"),
249
- to: u()
250
- }),
251
- t.strictObject({
252
- fn: t.literal("xiaomi:special"),
253
- ep: t.optional(i()),
254
- at: t.optional(n(4)),
255
- idx: n(2),
256
- eval: t.optional(o()),
257
- script: t.optional(r())
258
- }).refine((e) => !("eval" in e && "script" in e), {
259
- message: "eval and script should not both be present"
260
- }).innerType(),
261
- t.strictObject({
262
- fn: t.literal("tuya"),
263
- dpid: t.number(),
264
- eval: t.optional(o()),
265
- script: t.optional(r())
266
- }).refine((e) => !("eval" in e && "script" in e), {
267
- message: "eval and script should not both be present"
268
- }).innerType()
269
- ])
270
- ),
271
- write: t.optional(
272
- t.discriminatedUnion("fn", [
273
- t.strictObject({
274
- fn: t.literal("none")
275
- }),
276
- t.strictObject({
277
- fn: t.undefined(),
278
- at: t.optional(n(4).or(t.array(n(4)))),
279
- "state.timeout": t.optional(t.number()),
280
- "change.timeout": t.optional(t.number()),
281
- cl: n(4),
282
- dt: n(2),
283
- ep: t.optional(i()),
284
- mf: t.optional(n(4)),
285
- eval: t.optional(o()),
286
- script: t.optional(r())
287
- }).refine((e) => !("eval" in e && "script" in e), {
288
- message: "eval and script should not both be present"
289
- }).innerType(),
290
- t.strictObject({
291
- fn: t.literal("zcl"),
292
- at: t.optional(n(4).or(t.array(n(4)))),
293
- "state.timeout": t.optional(t.number()),
294
- "change.timeout": t.optional(t.number()),
295
- cl: n(4),
296
- dt: n(2),
297
- ep: t.optional(i()),
298
- mf: t.optional(n(4)),
299
- eval: t.optional(o()),
300
- script: t.optional(r())
301
- }).refine((e) => !("eval" in e && "script" in e), {
302
- message: "eval and script should not both be present"
303
- }).innerType(),
304
- t.strictObject({
305
- fn: t.literal("tuya"),
306
- dpid: t.number(),
307
- dt: n(2),
308
- eval: t.optional(o()),
309
- script: t.optional(r())
310
- }).refine((e) => !("eval" in e && "script" in e), {
311
- message: "eval and script should not both be present"
312
- }).innerType()
313
- ])
314
- ),
251
+ read: t.optional(b()),
252
+ parse: t.optional(f()),
253
+ write: t.optional(h()),
315
254
  awake: t.optional(t.boolean()),
316
255
  default: t.optional(t.unknown()),
317
256
  values: t.optional(t.unknown()),
318
257
  "refresh.interval": t.optional(t.number())
319
258
  });
320
259
  }
321
- function _() {
260
+ function T(e) {
322
261
  return t.discriminatedUnion("bind", [
323
262
  t.strictObject({
324
263
  bind: t.literal("unicast"),
325
- "src.ep": i(),
326
- "dst.ep": t.optional(i()),
264
+ "src.ep": a(),
265
+ "dst.ep": t.optional(a()),
327
266
  cl: n(4),
328
267
  report: t.optional(t.array(t.strictObject({
329
268
  at: n(4),
@@ -336,12 +275,84 @@ function _() {
336
275
  }),
337
276
  t.strictObject({
338
277
  bind: t.literal("groupcast"),
339
- "src.ep": i(),
278
+ "src.ep": a(),
340
279
  cl: n(4),
341
280
  "config.group": t.number()
342
281
  })
343
282
  ]);
344
283
  }
284
+ function w(e) {
285
+ return t.strictObject({
286
+ $schema: t.optional(t.string()),
287
+ schema: t.literal("resourceitem1.schema.json"),
288
+ id: t.string(),
289
+ description: t.string(),
290
+ deprecated: t.optional(m()),
291
+ datatype: t.enum(["String", "Bool", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Array", "Array[3]", "ISO 8601 timestamp"]),
292
+ access: t.enum(["R", "W", "RW"]),
293
+ public: t.boolean(),
294
+ implicit: t.optional(t.boolean()),
295
+ managed: t.optional(t.boolean()),
296
+ static: t.optional(t.boolean()),
297
+ virtual: t.optional(t.boolean()),
298
+ parse: t.optional(f()),
299
+ read: t.optional(b()),
300
+ write: t.optional(h()),
301
+ "refresh.interval": t.optional(t.number()),
302
+ // TODO Validate this
303
+ values: t.optional(t.unknown()),
304
+ range: t.optional(t.tuple([t.number(), t.number()])),
305
+ default: t.optional(t.unknown())
306
+ });
307
+ }
308
+ function x(e) {
309
+ return t.strictObject({
310
+ $schema: t.optional(t.string()),
311
+ schema: t.literal("subdevice1.schema.json"),
312
+ type: t.enum(Object.keys(e.deviceTypes)),
313
+ name: t.enum(Object.values(e.deviceTypes)),
314
+ restapi: t.enum(["/lights", "/sensors"]),
315
+ order: t.number(),
316
+ uuid: d(),
317
+ items: t.array(t.enum(e.attributes))
318
+ });
319
+ }
320
+ function u(e) {
321
+ return t.discriminatedUnion("schema", [
322
+ y(e),
323
+ v(),
324
+ w(),
325
+ x(e)
326
+ ]);
327
+ }
328
+ function I(e = { attributes: [], manufacturers: {}, deviceTypes: {} }) {
329
+ let i = u(e);
330
+ const l = () => {
331
+ i = u(e);
332
+ };
333
+ return { generics: e, loadGeneric: (c) => {
334
+ const s = i.parse(c);
335
+ switch (s.schema) {
336
+ case "constants1.schema.json":
337
+ e.manufacturers = {
338
+ ...e.manufacturers,
339
+ ...s.manufacturers
340
+ }, e.deviceTypes = {
341
+ ...e.deviceTypes,
342
+ ...s["device-types"]
343
+ };
344
+ break;
345
+ case "resourceitem1.schema.json":
346
+ e.attributes.includes(s.id) || e.attributes.push(s.id);
347
+ break;
348
+ case "subdevice1.schema.json":
349
+ break;
350
+ case "devcap1.schema.json":
351
+ throw new Error("Got invalid generic file, got data with schema 'devcap1.schema.json'.");
352
+ }
353
+ return l(), s;
354
+ }, validate: (c) => i.parse(c), getSchema: () => i };
355
+ }
345
356
  export {
346
- b as validate
357
+ I as createValidator
347
358
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deconz-community/ddf-validator",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "Validating DDF files for deconz",
5
5
  "keywords": [
6
6
  "deconz",
@@ -56,7 +56,6 @@
56
56
  "@typescript-eslint/eslint-plugin": "^5.51.0",
57
57
  "@typescript-eslint/parser": "^5.51.0",
58
58
  "degit": "^2.8.4",
59
- "dts-bundle-generator": "^7.2.0",
60
59
  "eslint": "^8.33.0",
61
60
  "eslint-config-prettier": "^8.6.0",
62
61
  "eslint-plugin-prettier": "^4.2.1",