meross-cli 0.4.0 → 0.5.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 (42) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +28 -2
  3. package/cli/commands/control/execute.js +36 -6
  4. package/cli/commands/control/params/index.js +16 -12
  5. package/cli/commands/control/params/light.js +55 -25
  6. package/cli/commands/control/params/thermostat.js +24 -22
  7. package/cli/commands/control/params/timer.js +18 -15
  8. package/cli/commands/control/params/trigger.js +24 -13
  9. package/cli/commands/info.js +38 -14
  10. package/cli/commands/sniffer/sniffer-menu.js +2 -2
  11. package/cli/commands/status/device-status.js +418 -1292
  12. package/cli/commands/status/hub-status.js +14 -6
  13. package/cli/control-registry.js +211 -406
  14. package/cli/meross-cli.js +1 -1
  15. package/cli/tests/README.md +2 -0
  16. package/cli/tests/test-alarm.js +22 -2
  17. package/cli/tests/test-child-lock.js +40 -10
  18. package/cli/tests/test-config.js +22 -2
  19. package/cli/tests/test-control.js +8 -8
  20. package/cli/tests/test-diffuser.js +7 -7
  21. package/cli/tests/test-dnd.js +87 -66
  22. package/cli/tests/test-electricity.js +37 -33
  23. package/cli/tests/test-encryption.js +13 -13
  24. package/cli/tests/test-garage.js +12 -14
  25. package/cli/tests/test-helper.js +1 -1
  26. package/cli/tests/test-hub-sensors.js +3 -3
  27. package/cli/tests/test-light.js +497 -105
  28. package/cli/tests/test-presence.js +10 -55
  29. package/cli/tests/test-registry.js +7 -1
  30. package/cli/tests/test-roller-shutter.js +78 -90
  31. package/cli/tests/test-screen.js +1 -1
  32. package/cli/tests/test-sensor-history.js +6 -2
  33. package/cli/tests/test-smoke-config.js +24 -4
  34. package/cli/tests/test-spray.js +11 -11
  35. package/cli/tests/test-system.js +375 -0
  36. package/cli/tests/test-temp-unit.js +22 -2
  37. package/cli/tests/test-template.js +61 -73
  38. package/cli/tests/test-thermostat.js +126 -89
  39. package/cli/tests/test-timer.js +8 -51
  40. package/cli/tests/test-toggle.js +49 -173
  41. package/cli/tests/test-trigger.js +7 -50
  42. package/package.json +2 -2
@@ -87,22 +87,19 @@ async function runTests(context) {
87
87
 
88
88
  // Test 2: Get toggle state
89
89
  try {
90
- if (typeof testDevice.getToggleState === 'function') {
91
- const toggleState = await testDevice.getToggleState(0);
90
+ if (testDevice.toggle) {
91
+ const toggleState = await testDevice.toggle.get({ channel: 0 });
92
+ const isOn = testDevice.toggle.isOn({ channel: 0 });
92
93
 
93
94
  if (!toggleState) {
94
95
  results.push({
95
96
  name: 'should get toggle state',
96
97
  passed: false,
97
98
  skipped: false,
98
- error: 'getToggleState returned null or undefined',
99
+ error: 'toggle.get() returned null or undefined',
99
100
  device: deviceName
100
101
  });
101
102
  } else {
102
- // Check cached toggle state
103
- const cachedState = testDevice.getCachedToggleState(0);
104
- const isOn = testDevice.isOn(0);
105
-
106
103
  results.push({
107
104
  name: 'should get toggle state',
108
105
  passed: true,
@@ -111,7 +108,6 @@ async function runTests(context) {
111
108
  device: deviceName,
112
109
  details: {
113
110
  toggleState: toggleState,
114
- cachedState: cachedState,
115
111
  isOn: isOn
116
112
  }
117
113
  });
@@ -121,7 +117,7 @@ async function runTests(context) {
121
117
  name: 'should get toggle state',
122
118
  passed: false,
123
119
  skipped: true,
124
- error: 'Device does not support getToggleState',
120
+ error: 'Device does not support toggle feature',
125
121
  device: deviceName
126
122
  });
127
123
  }
@@ -137,141 +133,69 @@ async function runTests(context) {
137
133
 
138
134
  // Test 3: Control toggle state (turn on/off)
139
135
  try {
140
- // Get initial state
141
- let initialState = undefined;
142
- if (typeof testDevice.getToggleState === 'function') {
143
- const stateResponse = await testDevice.getToggleState(0);
144
- if (stateResponse && stateResponse.togglex) {
145
- initialState = stateResponse.togglex[0]?.onoff || stateResponse.togglex.onoff;
146
- }
147
- } else if (typeof testDevice.isOn === 'function') {
148
- initialState = testDevice.isOn(0);
149
- }
150
-
151
- // Test turnOn if available
152
- if (typeof testDevice.turnOn === 'function') {
153
- const turnOnResult = await testDevice.turnOn(0);
136
+ if (!testDevice.toggle) {
137
+ results.push({
138
+ name: 'should control toggle state',
139
+ passed: false,
140
+ skipped: true,
141
+ error: 'Device does not support toggle feature',
142
+ device: deviceName
143
+ });
144
+ } else {
145
+ // Get initial state
146
+ let initialState = testDevice.toggle.isOn({ channel: 0 });
154
147
 
155
- if (!turnOnResult) {
148
+ // Test turn on
149
+ await testDevice.toggle.set({ channel: 0, on: true });
150
+ await new Promise(resolve => setTimeout(resolve, 2000));
151
+
152
+ const isOnAfter = testDevice.toggle.isOn({ channel: 0 });
153
+ if (!isOnAfter) {
156
154
  results.push({
157
155
  name: 'should control toggle state (turn on)',
158
156
  passed: false,
159
157
  skipped: false,
160
- error: 'turnOn() returned null or undefined',
158
+ error: 'Device did not turn on after set({ on: true })',
161
159
  device: deviceName
162
160
  });
163
161
  } else {
164
- // Wait a bit for state to update
165
- await new Promise(resolve => setTimeout(resolve, 2000));
166
-
167
- // Verify state
168
- if (typeof testDevice.isOn === 'function') {
169
- const isOnAfter = testDevice.isOn(0);
170
- if (!isOnAfter) {
171
- results.push({
172
- name: 'should control toggle state (turn on)',
173
- passed: false,
174
- skipped: false,
175
- error: 'Device did not turn on after turnOn() call',
176
- device: deviceName
177
- });
178
- } else {
179
- results.push({
180
- name: 'should control toggle state (turn on)',
181
- passed: true,
182
- skipped: false,
183
- error: null,
184
- device: deviceName
185
- });
186
- }
187
- } else {
188
- // Can't verify, but command succeeded
189
- results.push({
190
- name: 'should control toggle state (turn on)',
191
- passed: true,
192
- skipped: false,
193
- error: null,
194
- device: deviceName,
195
- details: { note: 'turnOn succeeded but cannot verify state (isOn not available)' }
196
- });
197
- }
162
+ results.push({
163
+ name: 'should control toggle state (turn on)',
164
+ passed: true,
165
+ skipped: false,
166
+ error: null,
167
+ device: deviceName
168
+ });
198
169
  }
199
- } else {
200
- results.push({
201
- name: 'should control toggle state (turn on)',
202
- passed: false,
203
- skipped: true,
204
- error: 'Device does not support turnOn',
205
- device: deviceName
206
- });
207
- }
208
-
209
- // Test turnOff if available
210
- if (typeof testDevice.turnOff === 'function') {
211
- const turnOffResult = await testDevice.turnOff(0);
212
170
 
213
- if (!turnOffResult) {
171
+ // Test turn off
172
+ await testDevice.toggle.set({ channel: 0, on: false });
173
+ await new Promise(resolve => setTimeout(resolve, 2000));
174
+
175
+ const isOffAfter = testDevice.toggle.isOn({ channel: 0 });
176
+ if (isOffAfter) {
214
177
  results.push({
215
178
  name: 'should control toggle state (turn off)',
216
179
  passed: false,
217
180
  skipped: false,
218
- error: 'turnOff() returned null or undefined',
181
+ error: 'Device did not turn off after set({ on: false })',
219
182
  device: deviceName
220
183
  });
221
184
  } else {
222
- // Wait a bit for state to update
223
- await new Promise(resolve => setTimeout(resolve, 2000));
224
-
225
- // Verify state
226
- if (typeof testDevice.isOn === 'function') {
227
- const isOnAfter = testDevice.isOn(0);
228
- if (isOnAfter) {
229
- results.push({
230
- name: 'should control toggle state (turn off)',
231
- passed: false,
232
- skipped: false,
233
- error: 'Device did not turn off after turnOff() call',
234
- device: deviceName
235
- });
236
- } else {
237
- results.push({
238
- name: 'should control toggle state (turn off)',
239
- passed: true,
240
- skipped: false,
241
- error: null,
242
- device: deviceName
243
- });
244
- }
245
- } else {
246
- // Can't verify, but command succeeded
247
- results.push({
248
- name: 'should control toggle state (turn off)',
249
- passed: true,
250
- skipped: false,
251
- error: null,
252
- device: deviceName,
253
- details: { note: 'turnOff succeeded but cannot verify state (isOn not available)' }
254
- });
255
- }
185
+ results.push({
186
+ name: 'should control toggle state (turn off)',
187
+ passed: true,
188
+ skipped: false,
189
+ error: null,
190
+ device: deviceName
191
+ });
256
192
  }
257
- } else {
258
- results.push({
259
- name: 'should control toggle state (turn off)',
260
- passed: false,
261
- skipped: true,
262
- error: 'Device does not support turnOff',
263
- device: deviceName
264
- });
265
- }
266
-
267
- // Restore initial state if we changed it
268
- if (initialState !== undefined && typeof testDevice.turnOn === 'function' && typeof testDevice.turnOff === 'function') {
269
- if (initialState === 1 || initialState === true) {
270
- await testDevice.turnOn(0);
271
- } else {
272
- await testDevice.turnOff(0);
193
+
194
+ // Restore initial state if we changed it
195
+ if (initialState !== undefined) {
196
+ await testDevice.toggle.set({ channel: 0, on: initialState });
197
+ await new Promise(resolve => setTimeout(resolve, 2000));
273
198
  }
274
- await new Promise(resolve => setTimeout(resolve, 2000));
275
199
  }
276
200
 
277
201
  } catch (error) {
@@ -284,54 +208,6 @@ async function runTests(context) {
284
208
  });
285
209
  }
286
210
 
287
- // Test 4: Handle toggle push notifications
288
- try {
289
- const testDeviceForPush = toggleDevices[0];
290
-
291
- // Set up listener for toggle push notifications
292
- let receivedNotification = false;
293
- const notificationHandler = (notification) => {
294
- if (notification.namespace === 'Appliance.Control.ToggleX' ||
295
- notification.namespace === 'Appliance.Control.Toggle') {
296
- receivedNotification = true;
297
- }
298
- };
299
-
300
- testDeviceForPush.on('pushNotification', notificationHandler);
301
-
302
- // Get toggle state (may trigger a push notification)
303
- if (typeof testDeviceForPush.getToggleState === 'function') {
304
- await testDeviceForPush.getToggleState(0);
305
- }
306
-
307
- // Wait a bit for potential push notifications
308
- await new Promise(resolve => setTimeout(resolve, 5000));
309
-
310
- // Remove listener
311
- testDeviceForPush.removeListener('pushNotification', notificationHandler);
312
-
313
- // Note: We don't assert on receivedNotification since push notifications
314
- // are device-initiated and may not occur during testing
315
- // This test just verifies the listener mechanism works
316
- results.push({
317
- name: 'should handle toggle push notifications',
318
- passed: true,
319
- skipped: false,
320
- error: null,
321
- device: getDeviceName(testDeviceForPush),
322
- details: { notificationReceived: receivedNotification }
323
- });
324
-
325
- } catch (error) {
326
- results.push({
327
- name: 'should handle toggle push notifications',
328
- passed: false,
329
- skipped: false,
330
- error: error.message,
331
- device: toggleDevices.length > 0 ? getDeviceName(toggleDevices[0]) : null
332
- });
333
- }
334
-
335
211
  return results;
336
212
  }
337
213
 
@@ -81,7 +81,7 @@ async function runTests(context) {
81
81
  }
82
82
  }
83
83
  };
84
- testDevice.on('pushNotification', handler);
84
+ testDevice.on('pushNotificationReceived', handler);
85
85
 
86
86
  // Timeout after 5 seconds if no push notification arrives
87
87
  setTimeout(() => {
@@ -90,7 +90,7 @@ async function runTests(context) {
90
90
  }, 5000);
91
91
  });
92
92
 
93
- const createResult = await testDevice.setTriggerX(testTrigger);
93
+ const createResult = await testDevice.trigger.set({ triggerx: testTrigger });
94
94
 
95
95
  if (!createResult) {
96
96
  results.push({
@@ -114,7 +114,7 @@ async function runTests(context) {
114
114
  } else {
115
115
  // Wait a bit and query by alias to find it
116
116
  await new Promise(resolve => setTimeout(resolve, 2000));
117
- const triggers = await testDevice.getTriggerX(0);
117
+ const triggers = await testDevice.trigger.get({ channel: 0 });
118
118
  const foundTrigger = triggers?.triggerx?.find(t => t.alias === 'Test Trigger - CLI Test');
119
119
  if (foundTrigger && foundTrigger.id) {
120
120
  createdTriggerId = foundTrigger.id;
@@ -133,7 +133,7 @@ async function runTests(context) {
133
133
  }
134
134
 
135
135
  // Verify trigger exists by querying it
136
- const triggerInfo = await testDevice.getTriggerX(0);
136
+ const triggerInfo = await testDevice.trigger.get({ channel: 0 });
137
137
  const triggerExists = triggerInfo?.triggerx?.some(t => t.id === createdTriggerId);
138
138
 
139
139
  if (!triggerExists) {
@@ -148,7 +148,8 @@ async function runTests(context) {
148
148
  }
149
149
 
150
150
  // Verify cached trigger state
151
- const cachedTriggers = testDevice.getCachedTriggerX(0);
151
+ const triggerResponse = await testDevice.trigger.get({ channel: 0 });
152
+ const cachedTriggers = triggerResponse?.triggerx || [];
152
153
 
153
154
  results.push({
154
155
  name: 'should create trigger',
@@ -158,7 +159,7 @@ async function runTests(context) {
158
159
  device: deviceName,
159
160
  details: {
160
161
  triggerId: createdTriggerId,
161
- cachedTriggerCount: cachedTriggers ? cachedTriggers.length : 0
162
+ cachedTriggerCount: cachedTriggers.length
162
163
  }
163
164
  });
164
165
  } catch (error) {
@@ -226,50 +227,6 @@ async function runTests(context) {
226
227
  }
227
228
  }
228
229
 
229
- // Test 3: Handle trigger push notifications
230
- try {
231
- // Set up listener for trigger push notifications
232
- let receivedNotification = false;
233
- const notificationHandler = (notification) => {
234
- if (notification.namespace === 'Appliance.Control.TriggerX') {
235
- receivedNotification = true;
236
- }
237
- };
238
-
239
- testDevice.on('pushNotification', notificationHandler);
240
-
241
- // Get trigger info (may trigger a push notification)
242
- await testDevice.getTriggerX(0);
243
-
244
- // Wait a bit for potential push notifications
245
- await new Promise(resolve => setTimeout(resolve, 2000));
246
-
247
- // Remove listener
248
- testDevice.removeListener('pushNotification', notificationHandler);
249
-
250
- // Note: We don't assert on receivedNotification since push notifications
251
- // are device-initiated and may not occur during testing
252
- results.push({
253
- name: 'should handle trigger push notifications',
254
- passed: true,
255
- skipped: false,
256
- error: null,
257
- device: deviceName,
258
- details: {
259
- notificationReceived: receivedNotification,
260
- note: 'Push notifications are device-initiated and may not occur during testing'
261
- }
262
- });
263
- } catch (error) {
264
- results.push({
265
- name: 'should handle trigger push notifications',
266
- passed: false,
267
- skipped: false,
268
- error: error.message,
269
- device: deviceName
270
- });
271
- }
272
-
273
230
  return results;
274
231
  }
275
232
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meross-cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Command-line interface for controlling Meross smart home devices",
5
5
  "author": "Abe Haverkamp",
6
6
  "homepage": "https://github.com/Doekse/merossiot#readme",
@@ -24,7 +24,7 @@
24
24
  "chalk": "^4.1.2",
25
25
  "commander": "^12.1.0",
26
26
  "inquirer": "^8.2.6",
27
- "meross-iot": "^0.5.0",
27
+ "meross-iot": "^0.6.0",
28
28
  "ora": "^5.4.1"
29
29
  },
30
30
  "devDependencies": {