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,238 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Test Template - Example of new test file structure
5
+ *
6
+ * This file demonstrates the new test structure. Copy this template
7
+ * when creating new tests or migrating existing tests.
8
+ *
9
+ * Key changes from old structure:
10
+ * - No Mocha describe/it blocks
11
+ * - No globals or environment variables
12
+ * - Explicit context object passed to runTests()
13
+ * - Structured test results returned as array
14
+ * - Metadata exported separately
15
+ */
16
+
17
+ const { findDevicesByAbility, waitForDeviceConnection, getDeviceName, OnlineStatus } = require('./test-helper');
18
+ const { runSingleTest } = require('./test-runner');
19
+
20
+ /**
21
+ * Test metadata
22
+ * This information is also stored in test-registry.js, but exporting it here
23
+ * allows the test file to be self-documenting and enables auto-discovery.
24
+ */
25
+ const metadata = {
26
+ name: 'example',
27
+ description: 'Example test demonstrating the new test structure',
28
+ requiredAbilities: ['Appliance.Control.ToggleX', 'Appliance.Control.Toggle'],
29
+ minDevices: 1
30
+ };
31
+
32
+ /**
33
+ * Runs all tests for this test type
34
+ * @param {Object} context - Test context object
35
+ * @param {Object} context.manager - MerossManager instance (already connected)
36
+ * @param {Array<Object>} context.devices - Pre-filtered devices (from CLI selection or auto-discovery)
37
+ * @param {Object} context.options - Test options (timeout, verbose, etc.)
38
+ * @returns {Promise<Array>} Array of test result objects
39
+ */
40
+ async function runTests(context) {
41
+ const { manager, devices, options = {} } = context;
42
+ const timeout = options.timeout || 30000;
43
+ const results = [];
44
+
45
+ // If no devices provided, discover them
46
+ let testDevices = devices || [];
47
+ if (testDevices.length === 0) {
48
+ // Find devices with required abilities
49
+ const toggleXDevices = await findDevicesByAbility(manager, 'Appliance.Control.ToggleX', OnlineStatus.ONLINE);
50
+ const toggleDevices = await findDevicesByAbility(manager, 'Appliance.Control.Toggle', OnlineStatus.ONLINE);
51
+
52
+ // Combine and deduplicate
53
+ testDevices = [...toggleXDevices];
54
+ for (const device of toggleDevices) {
55
+ const uuid = device.dev?.uuid || device.uuid;
56
+ if (!testDevices.find(d => (d.dev?.uuid || d.uuid) === uuid)) {
57
+ testDevices.push(device);
58
+ }
59
+ }
60
+ }
61
+
62
+ // Wait for devices to be connected
63
+ for (const device of testDevices) {
64
+ await waitForDeviceConnection(device, timeout);
65
+ await new Promise(resolve => setTimeout(resolve, 1000));
66
+ }
67
+
68
+ // Test 1: Check if devices were found
69
+ if (testDevices.length === 0) {
70
+ results.push({
71
+ name: 'should find devices with toggle capability',
72
+ passed: false,
73
+ skipped: true,
74
+ error: 'No devices with toggle capability found',
75
+ device: null
76
+ });
77
+ return results; // Early return if no devices
78
+ }
79
+
80
+ results.push({
81
+ name: 'should find devices with toggle capability',
82
+ passed: true,
83
+ skipped: false,
84
+ error: null,
85
+ device: null
86
+ });
87
+
88
+ // Test 2: Get toggle state
89
+ const testDevice = testDevices[0];
90
+ const deviceName = getDeviceName(testDevice);
91
+
92
+ try {
93
+ if (typeof testDevice.getToggleState === 'function') {
94
+ const toggleState = await testDevice.getToggleState(0);
95
+
96
+ if (!toggleState) {
97
+ results.push({
98
+ name: 'should get toggle state',
99
+ passed: false,
100
+ skipped: false,
101
+ error: 'getToggleState returned null or undefined',
102
+ device: deviceName
103
+ });
104
+ } else {
105
+ // Check cached toggle state
106
+ const cachedState = testDevice.getCachedToggleState(0);
107
+ const isOn = testDevice.isOn(0);
108
+
109
+ results.push({
110
+ name: 'should get toggle state',
111
+ passed: true,
112
+ skipped: false,
113
+ error: null,
114
+ device: deviceName,
115
+ details: {
116
+ toggleState: toggleState,
117
+ cachedState: cachedState,
118
+ isOn: isOn
119
+ }
120
+ });
121
+ }
122
+ } else {
123
+ results.push({
124
+ name: 'should get toggle state',
125
+ passed: false,
126
+ skipped: true,
127
+ error: 'Device does not support getToggleState',
128
+ device: deviceName
129
+ });
130
+ }
131
+ } catch (error) {
132
+ results.push({
133
+ name: 'should get toggle state',
134
+ passed: false,
135
+ skipped: false,
136
+ error: error.message,
137
+ device: deviceName
138
+ });
139
+ }
140
+
141
+ // Test 3: Control toggle state (turn on/off)
142
+ try {
143
+ // Get initial state
144
+ let initialState = undefined;
145
+ if (typeof testDevice.getToggleState === 'function') {
146
+ const stateResponse = await testDevice.getToggleState(0);
147
+ if (stateResponse && stateResponse.togglex) {
148
+ initialState = stateResponse.togglex[0]?.onoff || stateResponse.togglex.onoff;
149
+ }
150
+ } else if (typeof testDevice.isOn === 'function') {
151
+ initialState = testDevice.isOn(0);
152
+ }
153
+
154
+ // Test turnOn if available
155
+ if (typeof testDevice.turnOn === 'function') {
156
+ await testDevice.turnOn(0);
157
+ await new Promise(resolve => setTimeout(resolve, 2000));
158
+
159
+ // Verify state
160
+ if (typeof testDevice.isOn === 'function') {
161
+ const isOnAfter = testDevice.isOn(0);
162
+ if (!isOnAfter) {
163
+ results.push({
164
+ name: 'should control toggle state (turn on)',
165
+ passed: false,
166
+ skipped: false,
167
+ error: 'Device did not turn on after turnOn() call',
168
+ device: deviceName
169
+ });
170
+ } else {
171
+ results.push({
172
+ name: 'should control toggle state (turn on)',
173
+ passed: true,
174
+ skipped: false,
175
+ error: null,
176
+ device: deviceName
177
+ });
178
+ }
179
+ }
180
+ }
181
+
182
+ // Test turnOff if available
183
+ if (typeof testDevice.turnOff === 'function') {
184
+ await testDevice.turnOff(0);
185
+ await new Promise(resolve => setTimeout(resolve, 2000));
186
+
187
+ // Verify state
188
+ if (typeof testDevice.isOn === 'function') {
189
+ const isOnAfter = testDevice.isOn(0);
190
+ if (isOnAfter) {
191
+ results.push({
192
+ name: 'should control toggle state (turn off)',
193
+ passed: false,
194
+ skipped: false,
195
+ error: 'Device did not turn off after turnOff() call',
196
+ device: deviceName
197
+ });
198
+ } else {
199
+ results.push({
200
+ name: 'should control toggle state (turn off)',
201
+ passed: true,
202
+ skipped: false,
203
+ error: null,
204
+ device: deviceName
205
+ });
206
+ }
207
+ }
208
+ }
209
+
210
+ // Restore initial state if we changed it
211
+ if (initialState !== undefined && typeof testDevice.turnOn === 'function' && typeof testDevice.turnOff === 'function') {
212
+ if (initialState === 1 || initialState === true) {
213
+ await testDevice.turnOn(0);
214
+ } else {
215
+ await testDevice.turnOff(0);
216
+ }
217
+ await new Promise(resolve => setTimeout(resolve, 2000));
218
+ }
219
+
220
+ } catch (error) {
221
+ results.push({
222
+ name: 'should control toggle state',
223
+ passed: false,
224
+ skipped: false,
225
+ error: error.message,
226
+ device: deviceName
227
+ });
228
+ }
229
+
230
+ return results;
231
+ }
232
+
233
+ // Export metadata and runTests function
234
+ module.exports = {
235
+ metadata,
236
+ runTests
237
+ };
238
+