meross-cli 0.1.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/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/cli/commands/control/execute.js +23 -0
- package/cli/commands/control/index.js +12 -0
- package/cli/commands/control/menu.js +193 -0
- package/cli/commands/control/params/generic.js +229 -0
- package/cli/commands/control/params/index.js +56 -0
- package/cli/commands/control/params/light.js +188 -0
- package/cli/commands/control/params/thermostat.js +166 -0
- package/cli/commands/control/params/timer.js +242 -0
- package/cli/commands/control/params/trigger.js +206 -0
- package/cli/commands/dump.js +35 -0
- package/cli/commands/index.js +34 -0
- package/cli/commands/info.js +221 -0
- package/cli/commands/list.js +112 -0
- package/cli/commands/mqtt.js +187 -0
- package/cli/commands/sniffer/device-sniffer.js +217 -0
- package/cli/commands/sniffer/fake-app.js +233 -0
- package/cli/commands/sniffer/index.js +7 -0
- package/cli/commands/sniffer/message-queue.js +65 -0
- package/cli/commands/sniffer/sniffer-menu.js +676 -0
- package/cli/commands/stats.js +90 -0
- package/cli/commands/status/device-status.js +1403 -0
- package/cli/commands/status/hub-status.js +72 -0
- package/cli/commands/status/index.js +50 -0
- package/cli/commands/status/subdevices/hub-smoke-detector.js +82 -0
- package/cli/commands/status/subdevices/hub-temp-hum-sensor.js +43 -0
- package/cli/commands/status/subdevices/hub-thermostat-valve.js +83 -0
- package/cli/commands/status/subdevices/hub-water-leak-sensor.js +27 -0
- package/cli/commands/status/subdevices/index.js +23 -0
- package/cli/commands/test/index.js +185 -0
- package/cli/config/users.js +108 -0
- package/cli/control-registry.js +875 -0
- package/cli/helpers/client.js +89 -0
- package/cli/helpers/meross.js +106 -0
- package/cli/menu/index.js +10 -0
- package/cli/menu/main.js +648 -0
- package/cli/menu/settings.js +789 -0
- package/cli/meross-cli.js +547 -0
- package/cli/tests/README.md +365 -0
- package/cli/tests/test-alarm.js +144 -0
- package/cli/tests/test-child-lock.js +248 -0
- package/cli/tests/test-config.js +133 -0
- package/cli/tests/test-control.js +189 -0
- package/cli/tests/test-diffuser.js +505 -0
- package/cli/tests/test-dnd.js +246 -0
- package/cli/tests/test-electricity.js +209 -0
- package/cli/tests/test-encryption.js +281 -0
- package/cli/tests/test-garage.js +259 -0
- package/cli/tests/test-helper.js +313 -0
- package/cli/tests/test-hub-mts100.js +355 -0
- package/cli/tests/test-hub-sensors.js +489 -0
- package/cli/tests/test-light.js +253 -0
- package/cli/tests/test-presence.js +497 -0
- package/cli/tests/test-registry.js +419 -0
- package/cli/tests/test-roller-shutter.js +628 -0
- package/cli/tests/test-runner.js +415 -0
- package/cli/tests/test-runtime.js +234 -0
- package/cli/tests/test-screen.js +133 -0
- package/cli/tests/test-sensor-history.js +146 -0
- package/cli/tests/test-smoke-config.js +138 -0
- package/cli/tests/test-spray.js +131 -0
- package/cli/tests/test-temp-unit.js +133 -0
- package/cli/tests/test-template.js +238 -0
- package/cli/tests/test-thermostat.js +919 -0
- package/cli/tests/test-timer.js +372 -0
- package/cli/tests/test-toggle.js +342 -0
- package/cli/tests/test-trigger.js +279 -0
- package/cli/utils/display.js +86 -0
- package/cli/utils/terminal.js +137 -0
- package/package.json +53 -0
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Control method registry for device control testing.
|
|
5
|
+
* Maps control method names to metadata including parameter schemas and categories.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Mapping from control method names to required ability namespaces.
|
|
10
|
+
* This is used to filter methods based on what the device actually supports.
|
|
11
|
+
*/
|
|
12
|
+
const METHOD_TO_NAMESPACE_MAP = {
|
|
13
|
+
// Power Control
|
|
14
|
+
setToggle: ['Appliance.Control.Toggle'],
|
|
15
|
+
setToggleX: ['Appliance.Control.ToggleX'],
|
|
16
|
+
|
|
17
|
+
// Light Control
|
|
18
|
+
setLight: ['Appliance.Control.Light'],
|
|
19
|
+
setLightColor: ['Appliance.Control.Light'],
|
|
20
|
+
setDiffuserLight: ['Appliance.Control.Diffuser.Light'],
|
|
21
|
+
|
|
22
|
+
// Climate Control
|
|
23
|
+
setThermostatMode: ['Appliance.Control.Thermostat.Mode'],
|
|
24
|
+
setThermostatModeB: ['Appliance.Control.Thermostat.ModeB'],
|
|
25
|
+
setSpray: ['Appliance.Control.Spray'],
|
|
26
|
+
setDiffuserSpray: ['Appliance.Control.Diffuser.Spray'],
|
|
27
|
+
|
|
28
|
+
// Cover Control
|
|
29
|
+
setGarageDoor: ['Appliance.GarageDoor.State'],
|
|
30
|
+
openGarageDoor: ['Appliance.GarageDoor.State'],
|
|
31
|
+
closeGarageDoor: ['Appliance.GarageDoor.State'],
|
|
32
|
+
setGarageDoorConfig: ['Appliance.GarageDoor.Config', 'Appliance.GarageDoor.MultipleConfig'],
|
|
33
|
+
setRollerShutterPosition: ['Appliance.RollerShutter.Position', 'Appliance.RollerShutter.State'],
|
|
34
|
+
setRollerShutterUp: ['Appliance.RollerShutter.Position', 'Appliance.RollerShutter.State'],
|
|
35
|
+
setRollerShutterDown: ['Appliance.RollerShutter.Position', 'Appliance.RollerShutter.State'],
|
|
36
|
+
setRollerShutterStop: ['Appliance.RollerShutter.Position', 'Appliance.RollerShutter.State'],
|
|
37
|
+
openRollerShutter: ['Appliance.RollerShutter.Position', 'Appliance.RollerShutter.State'],
|
|
38
|
+
closeRollerShutter: ['Appliance.RollerShutter.Position', 'Appliance.RollerShutter.State'],
|
|
39
|
+
stopRollerShutter: ['Appliance.RollerShutter.Position', 'Appliance.RollerShutter.State'],
|
|
40
|
+
setRollerShutterConfig: ['Appliance.RollerShutter.Config'],
|
|
41
|
+
|
|
42
|
+
// Configuration
|
|
43
|
+
setChildLock: ['Appliance.Control.PhysicalLock'],
|
|
44
|
+
setSystemLedMode: ['Appliance.System.LedMode'],
|
|
45
|
+
setScreenBrightness: ['Appliance.Control.Screen.Brightness'],
|
|
46
|
+
setTempUnit: ['Appliance.Control.TempUnit'],
|
|
47
|
+
setDNDMode: ['Appliance.System.DNDMode'],
|
|
48
|
+
setConfigOverTemp: ['Appliance.Config.OverTemp'],
|
|
49
|
+
setPresenceConfig: ['Appliance.Control.Presence.Config'],
|
|
50
|
+
setPresenceStudy: ['Appliance.Control.Presence.Study'],
|
|
51
|
+
|
|
52
|
+
// Timer and Trigger
|
|
53
|
+
setTimerX: ['Appliance.Control.TimerX'],
|
|
54
|
+
deleteTimerX: ['Appliance.Control.TimerX'],
|
|
55
|
+
setTriggerX: ['Appliance.Control.TriggerX'],
|
|
56
|
+
deleteTriggerX: ['Appliance.Control.TriggerX']
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Control method metadata registry.
|
|
61
|
+
* Each entry defines:
|
|
62
|
+
* - name: Human-readable name
|
|
63
|
+
* - category: Feature category for grouping
|
|
64
|
+
* - params: Parameter schema for input collection
|
|
65
|
+
* - description: Brief description
|
|
66
|
+
*/
|
|
67
|
+
const CONTROL_METHOD_REGISTRY = {
|
|
68
|
+
// Power Control
|
|
69
|
+
setToggle: {
|
|
70
|
+
name: 'Toggle (On/Off)',
|
|
71
|
+
category: 'Power Control',
|
|
72
|
+
description: 'Turn device on or off',
|
|
73
|
+
params: [
|
|
74
|
+
{
|
|
75
|
+
name: 'onoff',
|
|
76
|
+
type: 'boolean',
|
|
77
|
+
label: 'State',
|
|
78
|
+
choices: [
|
|
79
|
+
{ name: 'On', value: true },
|
|
80
|
+
{ name: 'Off', value: false }
|
|
81
|
+
],
|
|
82
|
+
required: true
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
setToggleX: {
|
|
87
|
+
name: 'Toggle Channel (On/Off)',
|
|
88
|
+
category: 'Power Control',
|
|
89
|
+
description: 'Turn device channel on or off',
|
|
90
|
+
params: [
|
|
91
|
+
{
|
|
92
|
+
name: 'channel',
|
|
93
|
+
type: 'number',
|
|
94
|
+
label: 'Channel',
|
|
95
|
+
required: true,
|
|
96
|
+
default: 0
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'onoff',
|
|
100
|
+
type: 'boolean',
|
|
101
|
+
label: 'State',
|
|
102
|
+
choices: [
|
|
103
|
+
{ name: 'On', value: true },
|
|
104
|
+
{ name: 'Off', value: false }
|
|
105
|
+
],
|
|
106
|
+
required: true
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// Light Control
|
|
112
|
+
setLight: {
|
|
113
|
+
name: 'Light Control',
|
|
114
|
+
category: 'Light Control',
|
|
115
|
+
description: 'Control light settings (advanced)',
|
|
116
|
+
params: [
|
|
117
|
+
{
|
|
118
|
+
name: 'light',
|
|
119
|
+
type: 'object',
|
|
120
|
+
label: 'Light Configuration',
|
|
121
|
+
required: true,
|
|
122
|
+
properties: [
|
|
123
|
+
{ name: 'channel', type: 'number', default: 0 },
|
|
124
|
+
{ name: 'onoff', type: 'number', default: 1 },
|
|
125
|
+
{ name: 'rgb', type: 'number' },
|
|
126
|
+
{ name: 'luminance', type: 'number', min: 0, max: 100 },
|
|
127
|
+
{ name: 'temperature', type: 'number', min: 0, max: 100 }
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
setLightColor: {
|
|
133
|
+
name: 'Light Color & Brightness',
|
|
134
|
+
category: 'Light Control',
|
|
135
|
+
description: 'Set light color, brightness, and temperature',
|
|
136
|
+
params: [
|
|
137
|
+
{
|
|
138
|
+
name: 'channel',
|
|
139
|
+
type: 'number',
|
|
140
|
+
label: 'Channel',
|
|
141
|
+
default: 0
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'onoff',
|
|
145
|
+
type: 'boolean',
|
|
146
|
+
label: 'Turn On/Off',
|
|
147
|
+
required: false
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'rgb',
|
|
151
|
+
type: 'rgb',
|
|
152
|
+
label: 'RGB Color (r,g,b)',
|
|
153
|
+
required: false
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: 'luminance',
|
|
157
|
+
type: 'number',
|
|
158
|
+
label: 'Brightness (0-100)',
|
|
159
|
+
min: 0,
|
|
160
|
+
max: 100,
|
|
161
|
+
required: false
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'temperature',
|
|
165
|
+
type: 'number',
|
|
166
|
+
label: 'Temperature (0-100)',
|
|
167
|
+
min: 0,
|
|
168
|
+
max: 100,
|
|
169
|
+
required: false
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: 'gradual',
|
|
173
|
+
type: 'boolean',
|
|
174
|
+
label: 'Transition Type',
|
|
175
|
+
required: false
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
setDiffuserLight: {
|
|
180
|
+
name: 'Diffuser Light',
|
|
181
|
+
category: 'Light Control',
|
|
182
|
+
description: 'Control diffuser light settings',
|
|
183
|
+
params: [
|
|
184
|
+
{
|
|
185
|
+
name: 'light',
|
|
186
|
+
type: 'object',
|
|
187
|
+
label: 'Light Configuration',
|
|
188
|
+
required: true,
|
|
189
|
+
properties: [
|
|
190
|
+
{ name: 'channel', type: 'number', default: 0 },
|
|
191
|
+
{ name: 'onoff', type: 'number', default: 1 },
|
|
192
|
+
{ name: 'rgb', type: 'number' },
|
|
193
|
+
{ name: 'luminance', type: 'number', min: 0, max: 100 }
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
// Climate Control
|
|
200
|
+
setThermostatMode: {
|
|
201
|
+
name: 'Thermostat Mode',
|
|
202
|
+
category: 'Climate Control',
|
|
203
|
+
description: 'Set thermostat mode and temperature',
|
|
204
|
+
params: [
|
|
205
|
+
{
|
|
206
|
+
name: 'channel',
|
|
207
|
+
type: 'number',
|
|
208
|
+
label: 'Channel',
|
|
209
|
+
default: 0
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: 'mode',
|
|
213
|
+
type: 'enum',
|
|
214
|
+
label: 'Mode',
|
|
215
|
+
choices: [
|
|
216
|
+
{ name: 'Heat', value: 0 },
|
|
217
|
+
{ name: 'Cool', value: 1 },
|
|
218
|
+
{ name: 'Economy', value: 2 },
|
|
219
|
+
{ name: 'Auto', value: 3 },
|
|
220
|
+
{ name: 'Manual', value: 4 }
|
|
221
|
+
],
|
|
222
|
+
required: false
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: 'onoff',
|
|
226
|
+
type: 'number',
|
|
227
|
+
label: 'On/Off (0=off, 1=on)',
|
|
228
|
+
required: false
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'heatTemperature',
|
|
232
|
+
type: 'number',
|
|
233
|
+
label: 'Heat Temperature (°C)',
|
|
234
|
+
required: false
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: 'coolTemperature',
|
|
238
|
+
type: 'number',
|
|
239
|
+
label: 'Cool Temperature (°C)',
|
|
240
|
+
required: false
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: 'ecoTemperature',
|
|
244
|
+
type: 'number',
|
|
245
|
+
label: 'Eco Temperature (°C)',
|
|
246
|
+
required: false
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: 'manualTemperature',
|
|
250
|
+
type: 'number',
|
|
251
|
+
label: 'Manual Temperature (°C)',
|
|
252
|
+
required: false
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
setThermostatModeB: {
|
|
257
|
+
name: 'Thermostat Mode B',
|
|
258
|
+
category: 'Climate Control',
|
|
259
|
+
description: 'Set thermostat mode B (advanced)',
|
|
260
|
+
params: [
|
|
261
|
+
{
|
|
262
|
+
name: 'channel',
|
|
263
|
+
type: 'number',
|
|
264
|
+
label: 'Channel',
|
|
265
|
+
default: 0
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: 'modeData',
|
|
269
|
+
type: 'object',
|
|
270
|
+
label: 'Mode Data',
|
|
271
|
+
required: true
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
},
|
|
275
|
+
setSpray: {
|
|
276
|
+
name: 'Spray/Humidifier',
|
|
277
|
+
category: 'Climate Control',
|
|
278
|
+
description: 'Control spray/humidifier mode',
|
|
279
|
+
params: [
|
|
280
|
+
{
|
|
281
|
+
name: 'channel',
|
|
282
|
+
type: 'number',
|
|
283
|
+
label: 'Channel',
|
|
284
|
+
default: 0
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
name: 'mode',
|
|
288
|
+
type: 'enum',
|
|
289
|
+
label: 'Spray Mode',
|
|
290
|
+
choices: [
|
|
291
|
+
{ name: 'Off', value: 0 },
|
|
292
|
+
{ name: 'Continuous', value: 1 },
|
|
293
|
+
{ name: 'Intermittent', value: 2 }
|
|
294
|
+
],
|
|
295
|
+
required: true
|
|
296
|
+
}
|
|
297
|
+
]
|
|
298
|
+
},
|
|
299
|
+
setDiffuserSpray: {
|
|
300
|
+
name: 'Diffuser Spray',
|
|
301
|
+
category: 'Climate Control',
|
|
302
|
+
description: 'Control diffuser spray mode',
|
|
303
|
+
params: [
|
|
304
|
+
{
|
|
305
|
+
name: 'channel',
|
|
306
|
+
type: 'number',
|
|
307
|
+
label: 'Channel',
|
|
308
|
+
default: 0
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
name: 'mode',
|
|
312
|
+
type: 'enum',
|
|
313
|
+
label: 'Spray Mode',
|
|
314
|
+
choices: [
|
|
315
|
+
{ name: 'Off', value: 0 },
|
|
316
|
+
{ name: 'Continuous', value: 1 },
|
|
317
|
+
{ name: 'Intermittent', value: 2 }
|
|
318
|
+
],
|
|
319
|
+
required: true
|
|
320
|
+
}
|
|
321
|
+
]
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
// Cover Control
|
|
325
|
+
setGarageDoor: {
|
|
326
|
+
name: 'Garage Door',
|
|
327
|
+
category: 'Cover Control',
|
|
328
|
+
description: 'Open or close garage door',
|
|
329
|
+
params: [
|
|
330
|
+
{
|
|
331
|
+
name: 'channel',
|
|
332
|
+
type: 'number',
|
|
333
|
+
label: 'Channel',
|
|
334
|
+
default: 0
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: 'open',
|
|
338
|
+
type: 'boolean',
|
|
339
|
+
label: 'Action',
|
|
340
|
+
choices: [
|
|
341
|
+
{ name: 'Open', value: true },
|
|
342
|
+
{ name: 'Close', value: false }
|
|
343
|
+
],
|
|
344
|
+
required: true
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
},
|
|
348
|
+
setRollerShutterPosition: {
|
|
349
|
+
name: 'Roller Shutter Position',
|
|
350
|
+
category: 'Cover Control',
|
|
351
|
+
description: 'Set roller shutter position (0-100, -1 to stop)',
|
|
352
|
+
params: [
|
|
353
|
+
{
|
|
354
|
+
name: 'channel',
|
|
355
|
+
type: 'number',
|
|
356
|
+
label: 'Channel',
|
|
357
|
+
default: 0
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: 'position',
|
|
361
|
+
type: 'number',
|
|
362
|
+
label: 'Position (0-100, -1=stop)',
|
|
363
|
+
min: -1,
|
|
364
|
+
max: 100,
|
|
365
|
+
required: true
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
},
|
|
369
|
+
setRollerShutterUp: {
|
|
370
|
+
name: 'Roller Shutter Open',
|
|
371
|
+
category: 'Cover Control',
|
|
372
|
+
description: 'Open roller shutter (position 100)',
|
|
373
|
+
params: [
|
|
374
|
+
{
|
|
375
|
+
name: 'channel',
|
|
376
|
+
type: 'number',
|
|
377
|
+
label: 'Channel',
|
|
378
|
+
default: 0
|
|
379
|
+
}
|
|
380
|
+
]
|
|
381
|
+
},
|
|
382
|
+
setRollerShutterDown: {
|
|
383
|
+
name: 'Roller Shutter Close',
|
|
384
|
+
category: 'Cover Control',
|
|
385
|
+
description: 'Close roller shutter (position 0)',
|
|
386
|
+
params: [
|
|
387
|
+
{
|
|
388
|
+
name: 'channel',
|
|
389
|
+
type: 'number',
|
|
390
|
+
label: 'Channel',
|
|
391
|
+
default: 0
|
|
392
|
+
}
|
|
393
|
+
]
|
|
394
|
+
},
|
|
395
|
+
setRollerShutterStop: {
|
|
396
|
+
name: 'Roller Shutter Stop',
|
|
397
|
+
category: 'Cover Control',
|
|
398
|
+
description: 'Stop roller shutter movement',
|
|
399
|
+
params: [
|
|
400
|
+
{
|
|
401
|
+
name: 'channel',
|
|
402
|
+
type: 'number',
|
|
403
|
+
label: 'Channel',
|
|
404
|
+
default: 0
|
|
405
|
+
}
|
|
406
|
+
]
|
|
407
|
+
},
|
|
408
|
+
openRollerShutter: {
|
|
409
|
+
name: 'Roller Shutter Open',
|
|
410
|
+
category: 'Cover Control',
|
|
411
|
+
description: 'Open roller shutter (convenience method)',
|
|
412
|
+
params: [
|
|
413
|
+
{
|
|
414
|
+
name: 'channel',
|
|
415
|
+
type: 'number',
|
|
416
|
+
label: 'Channel',
|
|
417
|
+
default: 0
|
|
418
|
+
}
|
|
419
|
+
]
|
|
420
|
+
},
|
|
421
|
+
closeRollerShutter: {
|
|
422
|
+
name: 'Roller Shutter Close',
|
|
423
|
+
category: 'Cover Control',
|
|
424
|
+
description: 'Close roller shutter (convenience method)',
|
|
425
|
+
params: [
|
|
426
|
+
{
|
|
427
|
+
name: 'channel',
|
|
428
|
+
type: 'number',
|
|
429
|
+
label: 'Channel',
|
|
430
|
+
default: 0
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
stopRollerShutter: {
|
|
435
|
+
name: 'Roller Shutter Stop',
|
|
436
|
+
category: 'Cover Control',
|
|
437
|
+
description: 'Stop roller shutter (convenience method)',
|
|
438
|
+
params: [
|
|
439
|
+
{
|
|
440
|
+
name: 'channel',
|
|
441
|
+
type: 'number',
|
|
442
|
+
label: 'Channel',
|
|
443
|
+
default: 0
|
|
444
|
+
}
|
|
445
|
+
]
|
|
446
|
+
},
|
|
447
|
+
setRollerShutterPosition: {
|
|
448
|
+
name: 'Roller Shutter Set Position',
|
|
449
|
+
category: 'Cover Control',
|
|
450
|
+
description: 'Set roller shutter to specific position (convenience method)',
|
|
451
|
+
params: [
|
|
452
|
+
{
|
|
453
|
+
name: 'position',
|
|
454
|
+
type: 'number',
|
|
455
|
+
label: 'Position (0-100)',
|
|
456
|
+
min: 0,
|
|
457
|
+
max: 100,
|
|
458
|
+
required: true
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
name: 'channel',
|
|
462
|
+
type: 'number',
|
|
463
|
+
label: 'Channel',
|
|
464
|
+
default: 0
|
|
465
|
+
}
|
|
466
|
+
]
|
|
467
|
+
},
|
|
468
|
+
setRollerShutterConfig: {
|
|
469
|
+
name: 'Roller Shutter Configuration',
|
|
470
|
+
category: 'Configuration',
|
|
471
|
+
description: 'Configure roller shutter settings',
|
|
472
|
+
params: [
|
|
473
|
+
{
|
|
474
|
+
name: 'config',
|
|
475
|
+
type: 'object',
|
|
476
|
+
label: 'Configuration Object',
|
|
477
|
+
required: true
|
|
478
|
+
}
|
|
479
|
+
]
|
|
480
|
+
},
|
|
481
|
+
openGarageDoor: {
|
|
482
|
+
name: 'Garage Door Open',
|
|
483
|
+
category: 'Cover Control',
|
|
484
|
+
description: 'Open garage door (convenience method)',
|
|
485
|
+
params: [
|
|
486
|
+
{
|
|
487
|
+
name: 'channel',
|
|
488
|
+
type: 'number',
|
|
489
|
+
label: 'Channel',
|
|
490
|
+
default: 0
|
|
491
|
+
}
|
|
492
|
+
]
|
|
493
|
+
},
|
|
494
|
+
closeGarageDoor: {
|
|
495
|
+
name: 'Garage Door Close',
|
|
496
|
+
category: 'Cover Control',
|
|
497
|
+
description: 'Close garage door (convenience method)',
|
|
498
|
+
params: [
|
|
499
|
+
{
|
|
500
|
+
name: 'channel',
|
|
501
|
+
type: 'number',
|
|
502
|
+
label: 'Channel',
|
|
503
|
+
default: 0
|
|
504
|
+
}
|
|
505
|
+
]
|
|
506
|
+
},
|
|
507
|
+
setGarageDoorConfig: {
|
|
508
|
+
name: 'Garage Door Configuration',
|
|
509
|
+
category: 'Configuration',
|
|
510
|
+
description: 'Configure garage door settings',
|
|
511
|
+
params: [
|
|
512
|
+
{
|
|
513
|
+
name: 'configData',
|
|
514
|
+
type: 'object',
|
|
515
|
+
label: 'Configuration Object',
|
|
516
|
+
required: true
|
|
517
|
+
}
|
|
518
|
+
]
|
|
519
|
+
},
|
|
520
|
+
|
|
521
|
+
// Configuration
|
|
522
|
+
setChildLock: {
|
|
523
|
+
name: 'Child Lock',
|
|
524
|
+
category: 'Configuration',
|
|
525
|
+
description: 'Enable or disable child lock',
|
|
526
|
+
params: [
|
|
527
|
+
{
|
|
528
|
+
name: 'lockData',
|
|
529
|
+
type: 'object',
|
|
530
|
+
label: 'Lock Configuration',
|
|
531
|
+
required: true,
|
|
532
|
+
properties: [
|
|
533
|
+
{ name: 'lock', type: 'number', label: 'Lock (0=unlock, 1=lock)', required: true }
|
|
534
|
+
]
|
|
535
|
+
}
|
|
536
|
+
]
|
|
537
|
+
},
|
|
538
|
+
setSystemLedMode: {
|
|
539
|
+
name: 'LED Indicator Mode',
|
|
540
|
+
category: 'Configuration',
|
|
541
|
+
description: 'Control LED indicator mode',
|
|
542
|
+
params: [
|
|
543
|
+
{
|
|
544
|
+
name: 'ledModeData',
|
|
545
|
+
type: 'object',
|
|
546
|
+
label: 'LED Mode Configuration',
|
|
547
|
+
required: true
|
|
548
|
+
}
|
|
549
|
+
]
|
|
550
|
+
},
|
|
551
|
+
setScreenBrightness: {
|
|
552
|
+
name: 'Screen Brightness',
|
|
553
|
+
category: 'Configuration',
|
|
554
|
+
description: 'Set device screen brightness',
|
|
555
|
+
params: [
|
|
556
|
+
{
|
|
557
|
+
name: 'brightnessData',
|
|
558
|
+
type: 'object',
|
|
559
|
+
label: 'Brightness Configuration',
|
|
560
|
+
required: true,
|
|
561
|
+
properties: [
|
|
562
|
+
{ name: 'brightness', type: 'number', min: 0, max: 100, required: true }
|
|
563
|
+
]
|
|
564
|
+
}
|
|
565
|
+
]
|
|
566
|
+
},
|
|
567
|
+
setTempUnit: {
|
|
568
|
+
name: 'Temperature Unit',
|
|
569
|
+
category: 'Configuration',
|
|
570
|
+
description: 'Set temperature unit (Celsius/Fahrenheit)',
|
|
571
|
+
params: [
|
|
572
|
+
{
|
|
573
|
+
name: 'tempUnitData',
|
|
574
|
+
type: 'object',
|
|
575
|
+
label: 'Temperature Unit Configuration',
|
|
576
|
+
required: true,
|
|
577
|
+
properties: [
|
|
578
|
+
{ name: 'unit', type: 'number', label: 'Unit (0=Celsius, 1=Fahrenheit)', required: true }
|
|
579
|
+
]
|
|
580
|
+
}
|
|
581
|
+
]
|
|
582
|
+
},
|
|
583
|
+
setDNDMode: {
|
|
584
|
+
name: 'Do Not Disturb Mode',
|
|
585
|
+
category: 'Configuration',
|
|
586
|
+
description: 'Enable or disable Do Not Disturb mode (turns off LED indicator)',
|
|
587
|
+
params: [
|
|
588
|
+
{
|
|
589
|
+
name: 'mode',
|
|
590
|
+
type: 'boolean',
|
|
591
|
+
label: 'DND Mode',
|
|
592
|
+
choices: [
|
|
593
|
+
{ name: 'Enable DND', value: true },
|
|
594
|
+
{ name: 'Disable DND', value: false }
|
|
595
|
+
],
|
|
596
|
+
required: true
|
|
597
|
+
}
|
|
598
|
+
]
|
|
599
|
+
},
|
|
600
|
+
setConfigOverTemp: {
|
|
601
|
+
name: 'Over-Temperature Protection',
|
|
602
|
+
category: 'Configuration',
|
|
603
|
+
description: 'Enable or disable over-temperature protection',
|
|
604
|
+
params: [
|
|
605
|
+
{
|
|
606
|
+
name: 'enable',
|
|
607
|
+
type: 'boolean',
|
|
608
|
+
label: 'Over-Temperature Protection',
|
|
609
|
+
choices: [
|
|
610
|
+
{ name: 'On', value: true },
|
|
611
|
+
{ name: 'Off', value: false }
|
|
612
|
+
],
|
|
613
|
+
required: true
|
|
614
|
+
}
|
|
615
|
+
]
|
|
616
|
+
},
|
|
617
|
+
setPresenceConfig: {
|
|
618
|
+
name: 'Presence Sensor Configuration',
|
|
619
|
+
category: 'Configuration',
|
|
620
|
+
description: 'Configure presence sensor settings (mode, sensitivity, distance, etc.)',
|
|
621
|
+
params: [
|
|
622
|
+
{
|
|
623
|
+
name: 'configData',
|
|
624
|
+
type: 'object',
|
|
625
|
+
label: 'Configuration Object',
|
|
626
|
+
required: true,
|
|
627
|
+
properties: [
|
|
628
|
+
{ name: 'channel', type: 'number', label: 'Channel', default: 0 },
|
|
629
|
+
{ name: 'mode', type: 'object', label: 'Mode Configuration' },
|
|
630
|
+
{ name: 'noBodyTime', type: 'object', label: 'No Body Time Configuration' },
|
|
631
|
+
{ name: 'distance', type: 'object', label: 'Distance Configuration' },
|
|
632
|
+
{ name: 'sensitivity', type: 'object', label: 'Sensitivity Configuration' },
|
|
633
|
+
{ name: 'mthx', type: 'object', label: 'Motion Threshold Configuration' }
|
|
634
|
+
]
|
|
635
|
+
}
|
|
636
|
+
]
|
|
637
|
+
},
|
|
638
|
+
setPresenceStudy: {
|
|
639
|
+
name: 'Presence Sensor Study/Calibration',
|
|
640
|
+
category: 'Configuration',
|
|
641
|
+
description: 'Start or stop presence sensor study/calibration mode',
|
|
642
|
+
params: [
|
|
643
|
+
{
|
|
644
|
+
name: 'studyData',
|
|
645
|
+
type: 'object',
|
|
646
|
+
label: 'Study Data Object',
|
|
647
|
+
required: true,
|
|
648
|
+
properties: [
|
|
649
|
+
{ name: 'channel', type: 'number', label: 'Channel', default: 0 },
|
|
650
|
+
{ name: 'value', type: 'number', label: 'Study Mode Value (typically 1-3)' },
|
|
651
|
+
{ name: 'status', type: 'number', label: 'Status (0=stop, 1=start)', required: true }
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
]
|
|
655
|
+
},
|
|
656
|
+
setTimerX: {
|
|
657
|
+
name: 'Timer Control',
|
|
658
|
+
category: 'Automation',
|
|
659
|
+
description: 'Create or update a timer',
|
|
660
|
+
params: [
|
|
661
|
+
{
|
|
662
|
+
name: 'timerx',
|
|
663
|
+
type: 'object',
|
|
664
|
+
label: 'Timer Configuration',
|
|
665
|
+
required: true,
|
|
666
|
+
properties: [
|
|
667
|
+
{ name: 'id', type: 'string', label: 'Timer ID (for updates)' },
|
|
668
|
+
{ name: 'channel', type: 'number', default: 0 },
|
|
669
|
+
{ name: 'onoff', type: 'number', label: 'Action (0=off, 1=on)', required: true },
|
|
670
|
+
{ name: 'type', type: 'number', label: 'Timer Type', required: true },
|
|
671
|
+
{ name: 'time', type: 'number', label: 'Time Value', required: true }
|
|
672
|
+
]
|
|
673
|
+
}
|
|
674
|
+
]
|
|
675
|
+
},
|
|
676
|
+
deleteTimerX: {
|
|
677
|
+
name: 'Delete Timer',
|
|
678
|
+
category: 'Automation',
|
|
679
|
+
description: 'Delete a timer',
|
|
680
|
+
params: [
|
|
681
|
+
{
|
|
682
|
+
name: 'timerId',
|
|
683
|
+
type: 'string',
|
|
684
|
+
label: 'Timer ID',
|
|
685
|
+
required: true
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
name: 'channel',
|
|
689
|
+
type: 'number',
|
|
690
|
+
label: 'Channel',
|
|
691
|
+
default: 0
|
|
692
|
+
}
|
|
693
|
+
]
|
|
694
|
+
},
|
|
695
|
+
setTriggerX: {
|
|
696
|
+
name: 'Trigger Control',
|
|
697
|
+
category: 'Automation',
|
|
698
|
+
description: 'Create or update a trigger',
|
|
699
|
+
params: [
|
|
700
|
+
{
|
|
701
|
+
name: 'triggerx',
|
|
702
|
+
type: 'object',
|
|
703
|
+
label: 'Trigger Configuration',
|
|
704
|
+
required: true
|
|
705
|
+
}
|
|
706
|
+
]
|
|
707
|
+
},
|
|
708
|
+
deleteTriggerX: {
|
|
709
|
+
name: 'Delete Trigger',
|
|
710
|
+
category: 'Automation',
|
|
711
|
+
description: 'Delete a trigger',
|
|
712
|
+
params: [
|
|
713
|
+
{
|
|
714
|
+
name: 'triggerId',
|
|
715
|
+
type: 'string',
|
|
716
|
+
label: 'Trigger ID',
|
|
717
|
+
required: true
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
name: 'channel',
|
|
721
|
+
type: 'number',
|
|
722
|
+
label: 'Channel',
|
|
723
|
+
required: false,
|
|
724
|
+
default: 0
|
|
725
|
+
}
|
|
726
|
+
]
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Get metadata for a control method.
|
|
732
|
+
* @param {string} methodName - Name of the control method
|
|
733
|
+
* @returns {Object|null} Method metadata or null if not found
|
|
734
|
+
*/
|
|
735
|
+
function getMethodMetadata(methodName) {
|
|
736
|
+
return CONTROL_METHOD_REGISTRY[methodName] || null;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Get all methods grouped by category.
|
|
741
|
+
* @returns {Object} Methods grouped by category
|
|
742
|
+
*/
|
|
743
|
+
function getMethodsByCategory() {
|
|
744
|
+
const categories = {};
|
|
745
|
+
for (const [methodName, metadata] of Object.entries(CONTROL_METHOD_REGISTRY)) {
|
|
746
|
+
const category = metadata.category || 'Other';
|
|
747
|
+
if (!categories[category]) {
|
|
748
|
+
categories[category] = [];
|
|
749
|
+
}
|
|
750
|
+
categories[category].push({
|
|
751
|
+
methodName,
|
|
752
|
+
...metadata
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
return categories;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Check if device supports a required namespace.
|
|
760
|
+
* @param {Object} device - Device instance
|
|
761
|
+
* @param {string} namespace - Namespace to check
|
|
762
|
+
* @returns {boolean} True if device supports the namespace
|
|
763
|
+
*/
|
|
764
|
+
function deviceSupportsNamespace(device, namespace) {
|
|
765
|
+
if (!device._abilities || typeof device._abilities !== 'object') {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
return !!device._abilities[namespace];
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Check if device supports any of the required namespaces for a method.
|
|
773
|
+
* @param {Object} device - Device instance
|
|
774
|
+
* @param {Array<string>} namespaces - Array of namespace strings (any match is sufficient)
|
|
775
|
+
* @returns {boolean} True if device supports at least one namespace
|
|
776
|
+
*/
|
|
777
|
+
function deviceSupportsAnyNamespace(device, namespaces) {
|
|
778
|
+
if (!namespaces || namespaces.length === 0) {
|
|
779
|
+
return true; // No namespace requirement means always available
|
|
780
|
+
}
|
|
781
|
+
return namespaces.some(namespace => deviceSupportsNamespace(device, namespace));
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Detect available control methods on a device based on device abilities.
|
|
786
|
+
* Only shows methods that are in the registry AND the device supports the required namespaces.
|
|
787
|
+
* @param {Object} device - Device instance
|
|
788
|
+
* @returns {Array} Array of available control methods with metadata
|
|
789
|
+
*/
|
|
790
|
+
function detectControlMethods(device) {
|
|
791
|
+
const availableMethods = [];
|
|
792
|
+
|
|
793
|
+
// Only show methods that are in our registry and device supports
|
|
794
|
+
// Iterate through registry instead of device methods to ensure we only show known methods
|
|
795
|
+
for (const [methodName, metadata] of Object.entries(CONTROL_METHOD_REGISTRY)) {
|
|
796
|
+
// Check if method exists on device (check both exact name and common variations)
|
|
797
|
+
const deviceMethod = device[methodName];
|
|
798
|
+
if (typeof deviceMethod !== 'function') {
|
|
799
|
+
// Try alternative naming (e.g., setDNDMode might be on device)
|
|
800
|
+
continue; // Method doesn't exist on device, skip
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Check if this method requires specific namespaces
|
|
804
|
+
const requiredNamespaces = METHOD_TO_NAMESPACE_MAP[methodName];
|
|
805
|
+
|
|
806
|
+
// If method has namespace requirements, check if device supports them
|
|
807
|
+
if (requiredNamespaces && requiredNamespaces.length > 0) {
|
|
808
|
+
if (!deviceSupportsAnyNamespace(device, requiredNamespaces)) {
|
|
809
|
+
// Device doesn't support required namespaces, skip this method
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
} else {
|
|
813
|
+
// Method has no namespace requirement - this shouldn't happen for control methods
|
|
814
|
+
// Skip it to be safe, or we could add it but it's better to be strict
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Method exists, has namespace requirements, and device supports them - add it
|
|
819
|
+
availableMethods.push({
|
|
820
|
+
methodName,
|
|
821
|
+
...metadata
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Also check for any control/set methods on device that might not be in registry
|
|
826
|
+
// but have namespace requirements (for future extensibility)
|
|
827
|
+
for (const prop in device) {
|
|
828
|
+
if ((prop.startsWith('control') || prop.startsWith('set')) && typeof device[prop] === 'function') {
|
|
829
|
+
// Skip if already in our list
|
|
830
|
+
if (availableMethods.some(m => m.methodName === prop)) {
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// Check if this method has namespace requirements
|
|
835
|
+
const requiredNamespaces = METHOD_TO_NAMESPACE_MAP[prop];
|
|
836
|
+
|
|
837
|
+
// Only include if it has namespace requirements AND device supports them
|
|
838
|
+
if (requiredNamespaces && requiredNamespaces.length > 0) {
|
|
839
|
+
if (deviceSupportsAnyNamespace(device, requiredNamespaces)) {
|
|
840
|
+
// Unknown method but device supports it - add with basic info
|
|
841
|
+
const displayName = prop.replace(/^(control|set)/, '').replace(/([A-Z])/g, ' $1').trim();
|
|
842
|
+
availableMethods.push({
|
|
843
|
+
methodName: prop,
|
|
844
|
+
name: displayName,
|
|
845
|
+
category: 'Other',
|
|
846
|
+
description: 'Control method',
|
|
847
|
+
params: []
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
// If no namespace requirement, skip it (don't show unknown methods without namespace checks)
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Sort by category, then by name
|
|
856
|
+
availableMethods.sort((a, b) => {
|
|
857
|
+
if (a.category !== b.category) {
|
|
858
|
+
return a.category.localeCompare(b.category);
|
|
859
|
+
}
|
|
860
|
+
return a.name.localeCompare(b.name);
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
return availableMethods;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
module.exports = {
|
|
867
|
+
CONTROL_METHOD_REGISTRY,
|
|
868
|
+
METHOD_TO_NAMESPACE_MAP,
|
|
869
|
+
getMethodMetadata,
|
|
870
|
+
getMethodsByCategory,
|
|
871
|
+
detectControlMethods,
|
|
872
|
+
deviceSupportsNamespace,
|
|
873
|
+
deviceSupportsAnyNamespace
|
|
874
|
+
};
|
|
875
|
+
|