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.
Files changed (72) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +110 -0
  4. package/cli/commands/control/execute.js +23 -0
  5. package/cli/commands/control/index.js +12 -0
  6. package/cli/commands/control/menu.js +193 -0
  7. package/cli/commands/control/params/generic.js +229 -0
  8. package/cli/commands/control/params/index.js +56 -0
  9. package/cli/commands/control/params/light.js +188 -0
  10. package/cli/commands/control/params/thermostat.js +166 -0
  11. package/cli/commands/control/params/timer.js +242 -0
  12. package/cli/commands/control/params/trigger.js +206 -0
  13. package/cli/commands/dump.js +35 -0
  14. package/cli/commands/index.js +34 -0
  15. package/cli/commands/info.js +221 -0
  16. package/cli/commands/list.js +112 -0
  17. package/cli/commands/mqtt.js +187 -0
  18. package/cli/commands/sniffer/device-sniffer.js +217 -0
  19. package/cli/commands/sniffer/fake-app.js +233 -0
  20. package/cli/commands/sniffer/index.js +7 -0
  21. package/cli/commands/sniffer/message-queue.js +65 -0
  22. package/cli/commands/sniffer/sniffer-menu.js +676 -0
  23. package/cli/commands/stats.js +90 -0
  24. package/cli/commands/status/device-status.js +1403 -0
  25. package/cli/commands/status/hub-status.js +72 -0
  26. package/cli/commands/status/index.js +50 -0
  27. package/cli/commands/status/subdevices/hub-smoke-detector.js +82 -0
  28. package/cli/commands/status/subdevices/hub-temp-hum-sensor.js +43 -0
  29. package/cli/commands/status/subdevices/hub-thermostat-valve.js +83 -0
  30. package/cli/commands/status/subdevices/hub-water-leak-sensor.js +27 -0
  31. package/cli/commands/status/subdevices/index.js +23 -0
  32. package/cli/commands/test/index.js +185 -0
  33. package/cli/config/users.js +108 -0
  34. package/cli/control-registry.js +875 -0
  35. package/cli/helpers/client.js +89 -0
  36. package/cli/helpers/meross.js +106 -0
  37. package/cli/menu/index.js +10 -0
  38. package/cli/menu/main.js +648 -0
  39. package/cli/menu/settings.js +789 -0
  40. package/cli/meross-cli.js +547 -0
  41. package/cli/tests/README.md +365 -0
  42. package/cli/tests/test-alarm.js +144 -0
  43. package/cli/tests/test-child-lock.js +248 -0
  44. package/cli/tests/test-config.js +133 -0
  45. package/cli/tests/test-control.js +189 -0
  46. package/cli/tests/test-diffuser.js +505 -0
  47. package/cli/tests/test-dnd.js +246 -0
  48. package/cli/tests/test-electricity.js +209 -0
  49. package/cli/tests/test-encryption.js +281 -0
  50. package/cli/tests/test-garage.js +259 -0
  51. package/cli/tests/test-helper.js +313 -0
  52. package/cli/tests/test-hub-mts100.js +355 -0
  53. package/cli/tests/test-hub-sensors.js +489 -0
  54. package/cli/tests/test-light.js +253 -0
  55. package/cli/tests/test-presence.js +497 -0
  56. package/cli/tests/test-registry.js +419 -0
  57. package/cli/tests/test-roller-shutter.js +628 -0
  58. package/cli/tests/test-runner.js +415 -0
  59. package/cli/tests/test-runtime.js +234 -0
  60. package/cli/tests/test-screen.js +133 -0
  61. package/cli/tests/test-sensor-history.js +146 -0
  62. package/cli/tests/test-smoke-config.js +138 -0
  63. package/cli/tests/test-spray.js +131 -0
  64. package/cli/tests/test-temp-unit.js +133 -0
  65. package/cli/tests/test-template.js +238 -0
  66. package/cli/tests/test-thermostat.js +919 -0
  67. package/cli/tests/test-timer.js +372 -0
  68. package/cli/tests/test-toggle.js +342 -0
  69. package/cli/tests/test-trigger.js +279 -0
  70. package/cli/utils/display.js +86 -0
  71. package/cli/utils/terminal.js +137 -0
  72. package/package.json +53 -0
@@ -0,0 +1,419 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+
6
+ /**
7
+ * Test Registry - Centralized metadata and auto-discovery for test files
8
+ *
9
+ * This registry maintains metadata about all available tests including:
10
+ * - Test type names and aliases
11
+ * - File mappings
12
+ * - Descriptions
13
+ * - Required device abilities
14
+ * - Minimum device requirements
15
+ */
16
+
17
+ /**
18
+ * Static test metadata
19
+ * Maps test type names to their configuration
20
+ *
21
+ * Structure:
22
+ * {
23
+ * 'test-type': {
24
+ * file: 'test-file.js',
25
+ * description: 'Test description',
26
+ * requiredAbilities: ['Appliance.Control.X', ...],
27
+ * minDevices: 1,
28
+ * aliases: ['alias1', 'alias2'] // Optional alternative names
29
+ * }
30
+ * }
31
+ */
32
+ const TEST_METADATA = {
33
+ 'switch': {
34
+ file: 'test-toggle.js',
35
+ description: 'Tests on/off control for switches and smart plugs',
36
+ requiredAbilities: ['Appliance.Control.ToggleX', 'Appliance.Control.Toggle'],
37
+ minDevices: 1,
38
+ aliases: ['toggle']
39
+ },
40
+ 'light': {
41
+ file: 'test-light.js',
42
+ description: 'Tests RGB color, brightness, and temperature control for light devices',
43
+ requiredAbilities: ['Appliance.Control.Light'],
44
+ minDevices: 1,
45
+ aliases: ['rgb', 'lamp']
46
+ },
47
+ 'thermostat': {
48
+ file: 'test-thermostat.js',
49
+ description: 'Tests thermostat mode control, temperature settings, and ambient temperature reading',
50
+ requiredAbilities: ['Appliance.Control.Thermostat.Mode'],
51
+ minDevices: 1
52
+ },
53
+ 'shutter': {
54
+ file: 'test-roller-shutter.js',
55
+ description: 'Tests open/close control and position setting for roller shutters',
56
+ requiredAbilities: ['Appliance.RollerShutter.State'],
57
+ minDevices: 1,
58
+ aliases: ['roller-shutter', 'blind']
59
+ },
60
+ 'garage': {
61
+ file: 'test-garage.js',
62
+ description: 'Tests open/close control for garage door openers',
63
+ requiredAbilities: ['Appliance.GarageDoor.State'],
64
+ minDevices: 1
65
+ },
66
+ 'spray': {
67
+ file: 'test-spray.js',
68
+ description: 'Tests spray mode control for spray devices',
69
+ requiredAbilities: ['Appliance.Control.Spray'],
70
+ minDevices: 1
71
+ },
72
+ 'diffuser': {
73
+ file: 'test-diffuser.js',
74
+ description: 'Tests light RGB control, brightness, and spray mode for diffuser devices',
75
+ requiredAbilities: ['Appliance.Control.Diffuser.Light', 'Appliance.Control.Diffuser.Spray'],
76
+ minDevices: 1
77
+ },
78
+ 'electricity': {
79
+ file: 'test-electricity.js',
80
+ description: 'Tests power consumption metrics and daily consumption data',
81
+ requiredAbilities: ['Appliance.Control.ConsumptionX', 'Appliance.Control.Consumption', 'Appliance.Control.Electricity'],
82
+ minDevices: 1
83
+ },
84
+ 'dnd': {
85
+ file: 'test-dnd.js',
86
+ description: 'Tests do-not-disturb mode functionality',
87
+ requiredAbilities: ['Appliance.System.DNDMode'],
88
+ minDevices: 1
89
+ },
90
+ 'child-lock': {
91
+ file: 'test-child-lock.js',
92
+ description: 'Tests physical lock/child lock safety features',
93
+ requiredAbilities: ['Appliance.Control.PhysicalLock'],
94
+ minDevices: 1
95
+ },
96
+ 'timer': {
97
+ file: 'test-timer.js',
98
+ description: 'Tests timer creation, management, and execution',
99
+ requiredAbilities: ['Appliance.Control.TimerX', 'Appliance.Digest.TimerX'],
100
+ minDevices: 1
101
+ },
102
+ 'trigger': {
103
+ file: 'test-trigger.js',
104
+ description: 'Tests trigger configuration and execution',
105
+ requiredAbilities: ['Appliance.Control.TriggerX', 'Appliance.Digest.TriggerX'],
106
+ minDevices: 1
107
+ },
108
+ 'alarm': {
109
+ file: 'test-alarm.js',
110
+ description: 'Tests alarm functionality and notifications',
111
+ requiredAbilities: ['Appliance.Control.Alarm'],
112
+ minDevices: 1
113
+ },
114
+ 'runtime': {
115
+ file: 'test-runtime.js',
116
+ description: 'Tests device runtime and system runtime information',
117
+ requiredAbilities: ['Appliance.System.Runtime'],
118
+ minDevices: 1
119
+ },
120
+ 'encryption': {
121
+ file: 'test-encryption.js',
122
+ description: 'Tests encryption capabilities and secure communication',
123
+ requiredAbilities: ['Appliance.Encrypt.ECDHE', 'Appliance.Encrypt.Suite'],
124
+ minDevices: 1
125
+ },
126
+ 'hub': {
127
+ file: 'test-hub-sensors.js',
128
+ description: 'Tests hub sensor discovery and temperature/humidity readings',
129
+ requiredAbilities: ['Appliance.Hub.Sensor.All', 'Appliance.Hub.Sensor.TempHum', 'Appliance.Hub.Battery'],
130
+ minDevices: 1,
131
+ aliases: ['hub-sensors']
132
+ },
133
+ 'mts100': {
134
+ file: 'test-hub-mts100.js',
135
+ description: 'Tests MTS100 thermostat hub functionality',
136
+ requiredAbilities: ['Appliance.Hub.Mts100.All'],
137
+ minDevices: 1,
138
+ aliases: ['hub-mts100']
139
+ },
140
+ 'screen': {
141
+ file: 'test-screen.js',
142
+ description: 'Tests screen brightness control',
143
+ requiredAbilities: ['Appliance.Control.Screen.Brightness'],
144
+ minDevices: 1
145
+ },
146
+ 'sensor-history': {
147
+ file: 'test-sensor-history.js',
148
+ description: 'Tests sensor history data retrieval',
149
+ requiredAbilities: ['Appliance.Control.Sensor.History'],
150
+ minDevices: 1
151
+ },
152
+ 'smoke-config': {
153
+ file: 'test-smoke-config.js',
154
+ description: 'Tests smoke detector configuration settings',
155
+ requiredAbilities: ['Appliance.Control.Smoke.Config'],
156
+ minDevices: 1
157
+ },
158
+ 'temp-unit': {
159
+ file: 'test-temp-unit.js',
160
+ description: 'Tests temperature unit settings (Celsius/Fahrenheit)',
161
+ requiredAbilities: ['Appliance.Control.TempUnit'],
162
+ minDevices: 1
163
+ },
164
+ 'config': {
165
+ file: 'test-config.js',
166
+ description: 'Tests device configuration and settings',
167
+ requiredAbilities: ['Appliance.Config.OverTemp'],
168
+ minDevices: 1
169
+ },
170
+ 'control': {
171
+ file: 'test-control.js',
172
+ description: 'Tests multiple control features and device capabilities',
173
+ requiredAbilities: ['Appliance.Control.Multiple', 'Appliance.Control.Upgrade', 'Appliance.Control.OverTemp'],
174
+ minDevices: 1
175
+ },
176
+ 'presence': {
177
+ file: 'test-presence.js',
178
+ description: 'Tests presence detection, light readings, and configuration for presence sensor devices',
179
+ requiredAbilities: ['Appliance.Control.Sensor.LatestX'],
180
+ minDevices: 1
181
+ }
182
+ };
183
+
184
+ /**
185
+ * Reverse mapping: alias -> canonical test type name
186
+ * Built automatically from TEST_METADATA
187
+ */
188
+ let aliasMap = null;
189
+
190
+ /**
191
+ * Build alias map from metadata
192
+ * @returns {Object} Map of alias -> canonical name
193
+ */
194
+ function buildAliasMap() {
195
+ if (aliasMap) {
196
+ return aliasMap;
197
+ }
198
+
199
+ aliasMap = {};
200
+ for (const [canonicalName, metadata] of Object.entries(TEST_METADATA)) {
201
+ if (metadata.aliases) {
202
+ for (const alias of metadata.aliases) {
203
+ aliasMap[alias.toLowerCase()] = canonicalName;
204
+ }
205
+ }
206
+ // Also map canonical name to itself
207
+ aliasMap[canonicalName.toLowerCase()] = canonicalName;
208
+ }
209
+
210
+ return aliasMap;
211
+ }
212
+
213
+ /**
214
+ * Resolves a test type name (handles aliases)
215
+ * @param {string} testType - Test type name or alias
216
+ * @returns {string|null} Canonical test type name or null if not found
217
+ */
218
+ function resolveTestType(testType) {
219
+ if (!testType) {
220
+ return null;
221
+ }
222
+
223
+ const aliases = buildAliasMap();
224
+ const normalized = testType.toLowerCase();
225
+
226
+ return aliases[normalized] || (TEST_METADATA[normalized] ? normalized : null);
227
+ }
228
+
229
+ /**
230
+ * Gets metadata for a test type
231
+ * @param {string} testType - Test type name or alias
232
+ * @returns {Object|null} Test metadata or null if not found
233
+ */
234
+ function getTestMetadata(testType) {
235
+ const canonicalName = resolveTestType(testType);
236
+ if (!canonicalName) {
237
+ return null;
238
+ }
239
+
240
+ return TEST_METADATA[canonicalName] || null;
241
+ }
242
+
243
+ /**
244
+ * Gets available test types
245
+ * @returns {Array<string>} Array of canonical test type names
246
+ */
247
+ function getAvailableTestTypes() {
248
+ return Object.keys(TEST_METADATA);
249
+ }
250
+
251
+ /**
252
+ * Gets description for a test type
253
+ * @param {string} testType - Test type name or alias
254
+ * @returns {string} Description of the test type
255
+ */
256
+ function getTestDescription(testType) {
257
+ const metadata = getTestMetadata(testType);
258
+ return metadata ? metadata.description : `Tests ${testType} device functionality`;
259
+ }
260
+
261
+ /**
262
+ * Gets required abilities for a test type
263
+ * @param {string} testType - Test type name or alias
264
+ * @returns {Array<string>} Array of required ability namespaces
265
+ */
266
+ function getRequiredAbilities(testType) {
267
+ const metadata = getTestMetadata(testType);
268
+ return metadata ? (metadata.requiredAbilities || []) : [];
269
+ }
270
+
271
+ /**
272
+ * Gets minimum number of devices required for a test
273
+ * @param {string} testType - Test type name or alias
274
+ * @returns {number} Minimum number of devices (default: 1)
275
+ */
276
+ function getMinDevices(testType) {
277
+ const metadata = getTestMetadata(testType);
278
+ return metadata ? (metadata.minDevices || 1) : 1;
279
+ }
280
+
281
+ /**
282
+ * Gets test file path for a given test type
283
+ * @param {string} testType - Test type name or alias
284
+ * @param {string} baseDir - Base directory for test files (default: __dirname)
285
+ * @returns {string|null} Path to test file or null if not found
286
+ */
287
+ function getTestFile(testType, baseDir = __dirname) {
288
+ const metadata = getTestMetadata(testType);
289
+ if (!metadata || !metadata.file) {
290
+ return null;
291
+ }
292
+
293
+ const testPath = path.join(baseDir, metadata.file);
294
+ if (fs.existsSync(testPath)) {
295
+ return testPath;
296
+ }
297
+
298
+ return null;
299
+ }
300
+
301
+ /**
302
+ * Auto-discovers test files in the tests directory
303
+ * Scans for test-*.js files and attempts to load their metadata
304
+ * @param {string} baseDir - Base directory to scan (default: __dirname)
305
+ * @returns {Array<Object>} Array of discovered test info objects
306
+ */
307
+ function discoverTestFiles(baseDir = __dirname) {
308
+ const discovered = [];
309
+
310
+ if (!fs.existsSync(baseDir)) {
311
+ return discovered;
312
+ }
313
+
314
+ const files = fs.readdirSync(baseDir);
315
+
316
+ for (const file of files) {
317
+ // Look for test-*.js files
318
+ if (!file.startsWith('test-') || !file.endsWith('.js')) {
319
+ continue;
320
+ }
321
+
322
+ // Skip helper files
323
+ if (file === 'test-helper.js' || file === 'test-runner.js' || file === 'test-registry.js') {
324
+ continue;
325
+ }
326
+
327
+ const filePath = path.join(baseDir, file);
328
+
329
+ try {
330
+ // Try to load the test file and get its metadata
331
+ delete require.cache[require.resolve(filePath)];
332
+ const testModule = require(filePath);
333
+
334
+ if (testModule.metadata) {
335
+ // Test file exports metadata - use it
336
+ discovered.push({
337
+ file: file,
338
+ path: filePath,
339
+ metadata: testModule.metadata,
340
+ source: 'file'
341
+ });
342
+ } else {
343
+ // Test file doesn't export metadata yet - use static registry if available
344
+ // Find matching entry in static registry
345
+ for (const [type, metadata] of Object.entries(TEST_METADATA)) {
346
+ if (metadata.file === file) {
347
+ discovered.push({
348
+ file: file,
349
+ path: filePath,
350
+ metadata: {
351
+ name: type,
352
+ description: metadata.description,
353
+ requiredAbilities: metadata.requiredAbilities,
354
+ minDevices: metadata.minDevices
355
+ },
356
+ source: 'registry'
357
+ });
358
+ break;
359
+ }
360
+ }
361
+ }
362
+ } catch (error) {
363
+ // File exists but couldn't be loaded - skip it
364
+ // This might happen if the file has syntax errors or missing dependencies
365
+ continue;
366
+ }
367
+ }
368
+
369
+ return discovered;
370
+ }
371
+
372
+ /**
373
+ * Lists all tests with their metadata
374
+ * @returns {Object} Object mapping test types to their metadata
375
+ */
376
+ function listTests() {
377
+ const tests = {};
378
+
379
+ for (const [type, metadata] of Object.entries(TEST_METADATA)) {
380
+ tests[type] = {
381
+ file: metadata.file,
382
+ description: metadata.description,
383
+ requiredAbilities: metadata.requiredAbilities,
384
+ minDevices: metadata.minDevices,
385
+ aliases: metadata.aliases || []
386
+ };
387
+ }
388
+
389
+ return tests;
390
+ }
391
+
392
+ /**
393
+ * Validates that a test type exists
394
+ * @param {string} testType - Test type name or alias
395
+ * @returns {boolean} True if test type exists
396
+ */
397
+ function testTypeExists(testType) {
398
+ return resolveTestType(testType) !== null;
399
+ }
400
+
401
+ module.exports = {
402
+ // Core functions
403
+ getTestMetadata,
404
+ getAvailableTestTypes,
405
+ getTestDescription,
406
+ getRequiredAbilities,
407
+ getMinDevices,
408
+ getTestFile,
409
+ resolveTestType,
410
+ testTypeExists,
411
+
412
+ // Discovery
413
+ discoverTestFiles,
414
+ listTests,
415
+
416
+ // Direct access to metadata (for advanced use cases)
417
+ TEST_METADATA
418
+ };
419
+