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,281 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Encryption Device Tests
|
|
5
|
+
* Tests encryption support, key management, and message encryption/decryption
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { findDevicesByAbility, waitForDeviceConnection, getDeviceName, OnlineStatus } = require('./test-helper');
|
|
9
|
+
|
|
10
|
+
const metadata = {
|
|
11
|
+
name: 'encryption',
|
|
12
|
+
description: 'Tests encryption support, key management, and message encryption/decryption',
|
|
13
|
+
requiredAbilities: ['Appliance.Encrypt.ECDHE', 'Appliance.Encrypt.Suite'],
|
|
14
|
+
minDevices: 1
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
async function runTests(context) {
|
|
18
|
+
const { manager, devices, options = {} } = context;
|
|
19
|
+
const timeout = options.timeout || 30000;
|
|
20
|
+
const results = [];
|
|
21
|
+
|
|
22
|
+
// If no devices provided, discover them
|
|
23
|
+
let testDevices = devices || [];
|
|
24
|
+
if (testDevices.length === 0) {
|
|
25
|
+
// Find devices with encryption support
|
|
26
|
+
const encryptionDevices = await findDevicesByAbility(manager, 'Appliance.Encrypt.ECDHE', OnlineStatus.ONLINE);
|
|
27
|
+
|
|
28
|
+
// Also check for Appliance.Encrypt.Suite
|
|
29
|
+
const suiteDevices = await findDevicesByAbility(manager, 'Appliance.Encrypt.Suite', OnlineStatus.ONLINE);
|
|
30
|
+
|
|
31
|
+
// Combine and deduplicate
|
|
32
|
+
const allDevices = [...encryptionDevices];
|
|
33
|
+
for (const device of suiteDevices) {
|
|
34
|
+
if (!allDevices.find(d => d.dev.uuid === device.dev.uuid)) {
|
|
35
|
+
allDevices.push(device);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
testDevices = allDevices.slice(0, 3); // Test up to 3 devices
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Wait for devices to be connected
|
|
43
|
+
for (const device of testDevices) {
|
|
44
|
+
await waitForDeviceConnection(device, timeout);
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (testDevices.length === 0) {
|
|
49
|
+
results.push({
|
|
50
|
+
name: 'should detect encryption support',
|
|
51
|
+
passed: false,
|
|
52
|
+
skipped: true,
|
|
53
|
+
error: 'No device with encryption support has been found to run this test',
|
|
54
|
+
device: null
|
|
55
|
+
});
|
|
56
|
+
return results;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const testDevice = testDevices[0];
|
|
60
|
+
const deviceName = getDeviceName(testDevice);
|
|
61
|
+
|
|
62
|
+
// Test 1: Detect encryption support
|
|
63
|
+
try {
|
|
64
|
+
if (typeof testDevice.supportEncryption !== 'function') {
|
|
65
|
+
results.push({
|
|
66
|
+
name: 'should detect encryption support',
|
|
67
|
+
passed: false,
|
|
68
|
+
skipped: true,
|
|
69
|
+
error: 'Device does not have encryption feature methods',
|
|
70
|
+
device: deviceName
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
const supportsEncryption = testDevice.supportEncryption();
|
|
74
|
+
|
|
75
|
+
// Check if encryption key is set
|
|
76
|
+
let isKeySet = false;
|
|
77
|
+
if (supportsEncryption) {
|
|
78
|
+
isKeySet = testDevice.isEncryptionKeySet();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
results.push({
|
|
82
|
+
name: 'should detect encryption support',
|
|
83
|
+
passed: true,
|
|
84
|
+
skipped: false,
|
|
85
|
+
error: null,
|
|
86
|
+
device: deviceName,
|
|
87
|
+
details: {
|
|
88
|
+
supportsEncryption: supportsEncryption,
|
|
89
|
+
isKeySet: isKeySet
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
results.push({
|
|
95
|
+
name: 'should detect encryption support',
|
|
96
|
+
passed: false,
|
|
97
|
+
skipped: false,
|
|
98
|
+
error: error.message,
|
|
99
|
+
device: deviceName
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Test 2: Set encryption key if supported
|
|
104
|
+
try {
|
|
105
|
+
if (typeof testDevice.supportEncryption !== 'function' || !testDevice.supportEncryption()) {
|
|
106
|
+
results.push({
|
|
107
|
+
name: 'should set encryption key if supported',
|
|
108
|
+
passed: false,
|
|
109
|
+
skipped: true,
|
|
110
|
+
error: 'Device does not support encryption',
|
|
111
|
+
device: deviceName
|
|
112
|
+
});
|
|
113
|
+
} else {
|
|
114
|
+
// Check if key is already set
|
|
115
|
+
const isKeySet = testDevice.isEncryptionKeySet();
|
|
116
|
+
|
|
117
|
+
// If key is not set and we have the required info, set it
|
|
118
|
+
if (!isKeySet && testDevice.dev && testDevice.dev.uuid && manager.key && testDevice._macAddress) {
|
|
119
|
+
testDevice.setEncryptionKey(testDevice.dev.uuid, manager.key, testDevice._macAddress);
|
|
120
|
+
|
|
121
|
+
const keySetAfter = testDevice.isEncryptionKeySet();
|
|
122
|
+
|
|
123
|
+
if (!keySetAfter) {
|
|
124
|
+
results.push({
|
|
125
|
+
name: 'should set encryption key if supported',
|
|
126
|
+
passed: false,
|
|
127
|
+
skipped: false,
|
|
128
|
+
error: 'Encryption key was not set successfully',
|
|
129
|
+
device: deviceName
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
results.push({
|
|
133
|
+
name: 'should set encryption key if supported',
|
|
134
|
+
passed: true,
|
|
135
|
+
skipped: false,
|
|
136
|
+
error: null,
|
|
137
|
+
device: deviceName,
|
|
138
|
+
details: { keySet: true }
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
} else if (!isKeySet) {
|
|
142
|
+
results.push({
|
|
143
|
+
name: 'should set encryption key if supported',
|
|
144
|
+
passed: false,
|
|
145
|
+
skipped: true,
|
|
146
|
+
error: 'Cannot set encryption key - missing required information (UUID, key, or MAC address)',
|
|
147
|
+
device: deviceName
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
results.push({
|
|
151
|
+
name: 'should set encryption key if supported',
|
|
152
|
+
passed: true,
|
|
153
|
+
skipped: false,
|
|
154
|
+
error: null,
|
|
155
|
+
device: deviceName,
|
|
156
|
+
details: { keySet: true, note: 'Key was already set' }
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
results.push({
|
|
162
|
+
name: 'should set encryption key if supported',
|
|
163
|
+
passed: false,
|
|
164
|
+
skipped: false,
|
|
165
|
+
error: error.message,
|
|
166
|
+
device: deviceName
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Test 3: Encrypt and decrypt messages if encryption key is set
|
|
171
|
+
try {
|
|
172
|
+
if (typeof testDevice.supportEncryption !== 'function' || !testDevice.supportEncryption()) {
|
|
173
|
+
results.push({
|
|
174
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
175
|
+
passed: false,
|
|
176
|
+
skipped: true,
|
|
177
|
+
error: 'Device does not support encryption',
|
|
178
|
+
device: deviceName
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
// Ensure encryption key is set
|
|
182
|
+
if (!testDevice.isEncryptionKeySet()) {
|
|
183
|
+
if (testDevice.dev && testDevice.dev.uuid && manager.key && testDevice._macAddress) {
|
|
184
|
+
testDevice.setEncryptionKey(testDevice.dev.uuid, manager.key, testDevice._macAddress);
|
|
185
|
+
} else {
|
|
186
|
+
results.push({
|
|
187
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
188
|
+
passed: false,
|
|
189
|
+
skipped: true,
|
|
190
|
+
error: 'Cannot set encryption key - missing required information',
|
|
191
|
+
device: deviceName
|
|
192
|
+
});
|
|
193
|
+
return results;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Test encryption/decryption
|
|
198
|
+
const testMessage = { test: 'data', value: 123 };
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const encrypted = testDevice.encryptMessage(testMessage);
|
|
202
|
+
|
|
203
|
+
if (!encrypted) {
|
|
204
|
+
results.push({
|
|
205
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
206
|
+
passed: false,
|
|
207
|
+
skipped: false,
|
|
208
|
+
error: 'encryptMessage returned null or undefined',
|
|
209
|
+
device: deviceName
|
|
210
|
+
});
|
|
211
|
+
return results;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Encrypted message should be different from original
|
|
215
|
+
if (JSON.stringify(encrypted) === JSON.stringify(testMessage)) {
|
|
216
|
+
results.push({
|
|
217
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
218
|
+
passed: false,
|
|
219
|
+
skipped: false,
|
|
220
|
+
error: 'Encrypted message is identical to original message',
|
|
221
|
+
device: deviceName
|
|
222
|
+
});
|
|
223
|
+
return results;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const decrypted = testDevice.decryptMessage(encrypted);
|
|
227
|
+
|
|
228
|
+
if (!decrypted) {
|
|
229
|
+
results.push({
|
|
230
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
231
|
+
passed: false,
|
|
232
|
+
skipped: false,
|
|
233
|
+
error: 'decryptMessage returned null or undefined',
|
|
234
|
+
device: deviceName
|
|
235
|
+
});
|
|
236
|
+
} else if (JSON.stringify(decrypted) !== JSON.stringify(testMessage)) {
|
|
237
|
+
results.push({
|
|
238
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
239
|
+
passed: false,
|
|
240
|
+
skipped: false,
|
|
241
|
+
error: 'Decrypted message does not match original',
|
|
242
|
+
device: deviceName
|
|
243
|
+
});
|
|
244
|
+
} else {
|
|
245
|
+
results.push({
|
|
246
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
247
|
+
passed: true,
|
|
248
|
+
skipped: false,
|
|
249
|
+
error: null,
|
|
250
|
+
device: deviceName
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
} catch (error) {
|
|
254
|
+
// This is okay - encryption might not be fully implemented or might require specific conditions
|
|
255
|
+
results.push({
|
|
256
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
257
|
+
passed: false,
|
|
258
|
+
skipped: false,
|
|
259
|
+
error: `Encryption/decryption test failed: ${error.message}`,
|
|
260
|
+
device: deviceName,
|
|
261
|
+
details: { note: 'Encryption might not be fully implemented or might require specific conditions' }
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
} catch (error) {
|
|
266
|
+
results.push({
|
|
267
|
+
name: 'should encrypt and decrypt messages if encryption key is set',
|
|
268
|
+
passed: false,
|
|
269
|
+
skipped: false,
|
|
270
|
+
error: error.message,
|
|
271
|
+
device: deviceName
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return results;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
module.exports = {
|
|
279
|
+
metadata,
|
|
280
|
+
runTests
|
|
281
|
+
};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Garage Door Opener Tests
|
|
5
|
+
* Tests open/close control for garage door openers
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { findDevicesByAbility, findDevicesByType, waitForDeviceConnection, getDeviceName, OnlineStatus } = require('./test-helper');
|
|
9
|
+
|
|
10
|
+
const metadata = {
|
|
11
|
+
name: 'garage',
|
|
12
|
+
description: 'Tests open/close control for garage door openers',
|
|
13
|
+
requiredAbilities: ['Appliance.GarageDoor.State'],
|
|
14
|
+
minDevices: 1
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
async function runTests(context) {
|
|
18
|
+
const { manager, devices, options = {} } = context;
|
|
19
|
+
const timeout = options.timeout || 120000; // Garage doors take time
|
|
20
|
+
const results = [];
|
|
21
|
+
|
|
22
|
+
// If no devices provided, discover them
|
|
23
|
+
let garageDevices = devices || [];
|
|
24
|
+
if (garageDevices.length === 0) {
|
|
25
|
+
// Find garage door devices (try by ability first, then by type)
|
|
26
|
+
garageDevices = await findDevicesByAbility(manager, 'Appliance.GarageDoor.State', OnlineStatus.ONLINE);
|
|
27
|
+
|
|
28
|
+
if (garageDevices.length === 0) {
|
|
29
|
+
garageDevices = await findDevicesByType(manager, 'msg100', OnlineStatus.ONLINE);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Wait for devices to be connected
|
|
34
|
+
for (const device of garageDevices) {
|
|
35
|
+
await waitForDeviceConnection(device, timeout);
|
|
36
|
+
await device.getGarageDoorState();
|
|
37
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (garageDevices.length === 0) {
|
|
41
|
+
results.push({
|
|
42
|
+
name: 'should open and close garage door',
|
|
43
|
+
passed: false,
|
|
44
|
+
skipped: true,
|
|
45
|
+
error: 'Could not find any Garage Opener within the given set of devices',
|
|
46
|
+
device: null
|
|
47
|
+
});
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const garage = garageDevices[0];
|
|
52
|
+
const deviceName = getDeviceName(garage);
|
|
53
|
+
|
|
54
|
+
// Test 1: Open and close garage door
|
|
55
|
+
try {
|
|
56
|
+
// Without a full update, the status will be undefined
|
|
57
|
+
let currentStatus = garage.getCachedGarageDoorState(0);
|
|
58
|
+
|
|
59
|
+
// Trigger the full update
|
|
60
|
+
await garage.getGarageDoorState();
|
|
61
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
62
|
+
currentStatus = garage.getCachedGarageDoorState(0);
|
|
63
|
+
|
|
64
|
+
if (!currentStatus) {
|
|
65
|
+
results.push({
|
|
66
|
+
name: 'should open and close garage door',
|
|
67
|
+
passed: false,
|
|
68
|
+
skipped: false,
|
|
69
|
+
error: 'Could not get garage door state',
|
|
70
|
+
device: deviceName
|
|
71
|
+
});
|
|
72
|
+
return results;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Get current state
|
|
76
|
+
let isOpen = garage.isGarageDoorOpened(0);
|
|
77
|
+
if (isOpen === undefined) {
|
|
78
|
+
results.push({
|
|
79
|
+
name: 'should open and close garage door',
|
|
80
|
+
passed: false,
|
|
81
|
+
skipped: false,
|
|
82
|
+
error: 'isGarageDoorOpened returned undefined',
|
|
83
|
+
device: deviceName
|
|
84
|
+
});
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Toggle
|
|
89
|
+
if (isOpen) {
|
|
90
|
+
await garage.closeGarageDoor({ channel: 0 });
|
|
91
|
+
} else {
|
|
92
|
+
await garage.openGarageDoor({ channel: 0 });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Wait for door operation (garage doors take time)
|
|
96
|
+
await new Promise(resolve => setTimeout(resolve, 40000));
|
|
97
|
+
|
|
98
|
+
await garage.getGarageDoorState();
|
|
99
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
100
|
+
|
|
101
|
+
const newIsOpen = garage.isGarageDoorOpened(0);
|
|
102
|
+
|
|
103
|
+
if (newIsOpen === undefined) {
|
|
104
|
+
results.push({
|
|
105
|
+
name: 'should open and close garage door',
|
|
106
|
+
passed: false,
|
|
107
|
+
skipped: false,
|
|
108
|
+
error: 'Could not verify door state after toggle',
|
|
109
|
+
device: deviceName
|
|
110
|
+
});
|
|
111
|
+
return results;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (newIsOpen === isOpen) {
|
|
115
|
+
results.push({
|
|
116
|
+
name: 'should open and close garage door',
|
|
117
|
+
passed: false,
|
|
118
|
+
skipped: false,
|
|
119
|
+
error: `Door state did not change. Expected ${!isOpen}, got ${newIsOpen}`,
|
|
120
|
+
device: deviceName
|
|
121
|
+
});
|
|
122
|
+
return results;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Toggle back
|
|
126
|
+
isOpen = newIsOpen;
|
|
127
|
+
if (isOpen) {
|
|
128
|
+
await garage.closeGarageDoor({ channel: 0 });
|
|
129
|
+
} else {
|
|
130
|
+
await garage.openGarageDoor({ channel: 0 });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
await new Promise(resolve => setTimeout(resolve, 40000));
|
|
134
|
+
|
|
135
|
+
await garage.getGarageDoorState();
|
|
136
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
137
|
+
|
|
138
|
+
const finalIsOpen = garage.isGarageDoorOpened(0);
|
|
139
|
+
|
|
140
|
+
if (finalIsOpen === undefined || finalIsOpen === isOpen) {
|
|
141
|
+
results.push({
|
|
142
|
+
name: 'should open and close garage door',
|
|
143
|
+
passed: false,
|
|
144
|
+
skipped: false,
|
|
145
|
+
error: `Failed to toggle back. Expected ${!isOpen}, got ${finalIsOpen}`,
|
|
146
|
+
device: deviceName
|
|
147
|
+
});
|
|
148
|
+
} else {
|
|
149
|
+
results.push({
|
|
150
|
+
name: 'should open and close garage door',
|
|
151
|
+
passed: true,
|
|
152
|
+
skipped: false,
|
|
153
|
+
error: null,
|
|
154
|
+
device: deviceName
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
} catch (error) {
|
|
158
|
+
results.push({
|
|
159
|
+
name: 'should open and close garage door',
|
|
160
|
+
passed: false,
|
|
161
|
+
skipped: false,
|
|
162
|
+
error: error.message,
|
|
163
|
+
device: deviceName
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Test 2: Get garage door multiple config
|
|
168
|
+
try {
|
|
169
|
+
if (typeof garage.getGarageDoorMultipleState !== 'function') {
|
|
170
|
+
results.push({
|
|
171
|
+
name: 'should get garage door multiple config',
|
|
172
|
+
passed: false,
|
|
173
|
+
skipped: true,
|
|
174
|
+
error: 'Device does not support getGarageDoorMultipleState',
|
|
175
|
+
device: deviceName
|
|
176
|
+
});
|
|
177
|
+
} else {
|
|
178
|
+
const config = await garage.getGarageDoorMultipleState();
|
|
179
|
+
|
|
180
|
+
if (!config) {
|
|
181
|
+
results.push({
|
|
182
|
+
name: 'should get garage door multiple config',
|
|
183
|
+
passed: false,
|
|
184
|
+
skipped: false,
|
|
185
|
+
error: 'getGarageDoorMultipleState returned null or undefined',
|
|
186
|
+
device: deviceName
|
|
187
|
+
});
|
|
188
|
+
} else {
|
|
189
|
+
results.push({
|
|
190
|
+
name: 'should get garage door multiple config',
|
|
191
|
+
passed: true,
|
|
192
|
+
skipped: false,
|
|
193
|
+
error: null,
|
|
194
|
+
device: deviceName,
|
|
195
|
+
details: { config: config.config || config }
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
results.push({
|
|
201
|
+
name: 'should get garage door multiple config',
|
|
202
|
+
passed: false,
|
|
203
|
+
skipped: false,
|
|
204
|
+
error: error.message,
|
|
205
|
+
device: deviceName
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Test 3: Get garage door config
|
|
210
|
+
try {
|
|
211
|
+
if (typeof garage.getGarageDoorConfig !== 'function') {
|
|
212
|
+
results.push({
|
|
213
|
+
name: 'should get garage door config',
|
|
214
|
+
passed: false,
|
|
215
|
+
skipped: true,
|
|
216
|
+
error: 'Device does not support getGarageDoorConfig',
|
|
217
|
+
device: deviceName
|
|
218
|
+
});
|
|
219
|
+
} else {
|
|
220
|
+
const config = await garage.getGarageDoorConfig();
|
|
221
|
+
|
|
222
|
+
if (!config) {
|
|
223
|
+
results.push({
|
|
224
|
+
name: 'should get garage door config',
|
|
225
|
+
passed: false,
|
|
226
|
+
skipped: false,
|
|
227
|
+
error: 'getGarageDoorConfig returned null or undefined',
|
|
228
|
+
device: deviceName
|
|
229
|
+
});
|
|
230
|
+
} else {
|
|
231
|
+
// Note: We don't test controlGarageDoorConfig as it modifies device settings
|
|
232
|
+
// that may affect operation. Only read operations are tested.
|
|
233
|
+
results.push({
|
|
234
|
+
name: 'should get garage door config',
|
|
235
|
+
passed: true,
|
|
236
|
+
skipped: false,
|
|
237
|
+
error: null,
|
|
238
|
+
device: deviceName,
|
|
239
|
+
details: { config: config }
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} catch (error) {
|
|
244
|
+
results.push({
|
|
245
|
+
name: 'should get garage door config',
|
|
246
|
+
passed: false,
|
|
247
|
+
skipped: false,
|
|
248
|
+
error: error.message,
|
|
249
|
+
device: deviceName
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return results;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = {
|
|
257
|
+
metadata,
|
|
258
|
+
runTests
|
|
259
|
+
};
|