tsvesync 1.5.1 → 1.6.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.
@@ -85,7 +85,8 @@ class VeSyncAir131 extends vesyncFan_1.VeSyncFan {
85
85
  speed: data.level || 0,
86
86
  filter_life: filterLife,
87
87
  screen_status: data.screenStatus || 'off',
88
- child_lock: data.childLock || false,
88
+ // The 131 API reports childLock as the string 'on'/'off'
89
+ child_lock: data.childLock === 'on' || data.childLock === true,
89
90
  air_quality: data.airQuality || 'unknown',
90
91
  air_quality_value: data.air_quality_value || 0,
91
92
  air_quality_level: normalizedAirQuality.level >= 1 ? normalizedAirQuality.level : undefined,
@@ -343,7 +344,7 @@ class VeSyncAir131 extends vesyncFan_1.VeSyncFan {
343
344
  });
344
345
  const success = this.checkResponse([response, status], 'setChildLock');
345
346
  if (success) {
346
- this.details.childLock = enabled;
347
+ this.details.child_lock = enabled;
347
348
  return true;
348
349
  }
349
350
  else {
@@ -54,6 +54,14 @@ export declare class VeSyncAirBaseV2 extends VeSyncAirBypass {
54
54
  * Override turn off to use the powerSwitch payload required by bypassV2 purifiers.
55
55
  */
56
56
  turnOff(): Promise<boolean>;
57
+ /**
58
+ * Override setChildLock to send the childLockSwitch payload required by
59
+ * bypassV2 purifiers (Vital 100S/200S, Everest Air). These devices report
60
+ * child lock as childLockSwitch 0|1 and reject the legacy child_lock
61
+ * boolean payload used by the Core series (matches pyvesync, which sends
62
+ * {'childLockSwitch': int} for this family).
63
+ */
64
+ setChildLock(enabled: boolean): Promise<boolean>;
57
65
  /**
58
66
  * Override setMode to send workMode payloads for bypassV2 purifiers.
59
67
  */
@@ -264,6 +264,47 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
264
264
  return super.turnOff();
265
265
  }
266
266
  }
267
+ /**
268
+ * Override setChildLock to send the childLockSwitch payload required by
269
+ * bypassV2 purifiers (Vital 100S/200S, Everest Air). These devices report
270
+ * child lock as childLockSwitch 0|1 and reject the legacy child_lock
271
+ * boolean payload used by the Core series (matches pyvesync, which sends
272
+ * {'childLockSwitch': int} for this family).
273
+ */
274
+ async setChildLock(enabled) {
275
+ var _a;
276
+ if (!this.requiresPowerSwitchPayload()) {
277
+ // Use parent implementation for non-bypassV2 models
278
+ return super.setChildLock(enabled);
279
+ }
280
+ if (!this.hasFeature('child_lock')) {
281
+ const error = 'Child lock not supported';
282
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
283
+ throw new Error(error);
284
+ }
285
+ logger_1.logger.debug(`Setting child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
286
+ const [head, body] = this.buildApiDict('setChildLock');
287
+ body.payload.data = {
288
+ childLockSwitch: enabled ? 1 : 0
289
+ };
290
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
291
+ const success = this.checkV2Response(response, status, 'setChildLock');
292
+ // Code 11000000 marks the feature unsupported even when the envelope
293
+ // succeeds, so it must override the lenient inner-code handling
294
+ if ((response === null || response === void 0 ? void 0 : response.code) === 11000000 || (((_a = response === null || response === void 0 ? void 0 : response.result) === null || _a === void 0 ? void 0 : _a.code) === 11000000)) {
295
+ logger_1.logger.warn(`Child lock control not supported via API for device: ${this.deviceName}`);
296
+ return false;
297
+ }
298
+ if (success) {
299
+ // No deferred details refresh here: pyvesync and the Core path
300
+ // both rely on the optimistic update plus the next regular poll
301
+ this.details.child_lock = enabled;
302
+ }
303
+ else {
304
+ logger_1.logger.error(`Failed to set child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
305
+ }
306
+ return success;
307
+ }
267
308
  /**
268
309
  * Override setMode to send workMode payloads for bypassV2 purifiers.
269
310
  */
@@ -198,7 +198,15 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
198
198
  }
199
199
  }, helpers_1.Helpers.reqHeaderBypass());
200
200
  const success = this.checkResponse([response, status], 'changeFanSpeed');
201
- if (!success) {
201
+ if (success) {
202
+ // Reflect the change locally so callers don't read a stale speed
203
+ // until the next getDetails(). setLevel also puts the device into
204
+ // manual mode and turns it on, mirroring pyvesync's set_fan_speed.
205
+ this.details.speed = speed;
206
+ this.details.mode = 'manual';
207
+ this.deviceStatus = 'on';
208
+ }
209
+ else {
202
210
  logger_1.logger.error(`Failed to change fan speed to ${speed} for device: ${this.deviceName}`);
203
211
  }
204
212
  return success;
@@ -308,7 +316,7 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
308
316
  configModule: this.configModule,
309
317
  payload: {
310
318
  data: {
311
- state: enabled
319
+ child_lock: enabled
312
320
  },
313
321
  method: 'setChildLock',
314
322
  source: 'APP'
@@ -321,7 +329,7 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
321
329
  return false;
322
330
  }
323
331
  if (success) {
324
- this.details.childLock = enabled;
332
+ this.details.child_lock = enabled;
325
333
  return true;
326
334
  }
327
335
  else {
@@ -13,13 +13,13 @@ exports.fanConfig = {
13
13
  'Core200S': {
14
14
  module: 'VeSyncAirBypass',
15
15
  features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'sleep_mode', 'filter_life'],
16
- levels: [1, 2, 3, 4], // 4 levels including sleep mode, matching reference plugin
16
+ levels: [1, 2, 3], // Low/Med/High; sleep is a mode, not a level
17
17
  modes: ['sleep', 'manual']
18
18
  },
19
19
  'Core300S': {
20
20
  module: 'VeSyncAirBypass',
21
21
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
22
- levels: [1, 2, 3, 4],
22
+ levels: [1, 2, 3],
23
23
  modes: ['sleep', 'manual', 'auto'],
24
24
  autoPreferences: ['default', 'efficient', 'quiet']
25
25
  },
@@ -53,21 +53,21 @@ exports.fanConfig = {
53
53
  'LAP-C301S-WJP': {
54
54
  module: 'VeSyncAirBypass',
55
55
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
56
- levels: [1, 2, 3, 4],
56
+ levels: [1, 2, 3],
57
57
  modes: ['sleep', 'manual', 'auto'],
58
58
  autoPreferences: ['default', 'efficient', 'quiet']
59
59
  },
60
60
  'LAP-C302S-WUSB': {
61
61
  module: 'VeSyncAirBypass',
62
62
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
63
- levels: [1, 2, 3, 4],
63
+ levels: [1, 2, 3],
64
64
  modes: ['sleep', 'manual', 'auto'],
65
65
  autoPreferences: ['default', 'efficient', 'quiet']
66
66
  },
67
67
  'LAP-C301S-WAAA': {
68
68
  module: 'VeSyncAirBypass',
69
69
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
70
- levels: [1, 2, 3, 4],
70
+ levels: [1, 2, 3],
71
71
  modes: ['sleep', 'manual', 'auto'],
72
72
  autoPreferences: ['default', 'efficient', 'quiet']
73
73
  },
@@ -228,22 +228,26 @@ exports.fanConfig = {
228
228
  // LTF Series
229
229
  'LTF-F422S-KEU': {
230
230
  module: 'VeSyncTowerFan',
231
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
231
+ // No child_lock: the LTF-F422S API neither reports nor accepts it (pyvesync parity)
232
+ features: ['display', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
232
233
  levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
233
234
  },
234
235
  'LTF-F422S-WUSR': {
235
236
  module: 'VeSyncTowerFan',
236
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
237
+ // No child_lock: the LTF-F422S API neither reports nor accepts it (pyvesync parity)
238
+ features: ['display', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
237
239
  levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
238
240
  },
239
241
  'LTF-F422_WJP': {
240
242
  module: 'VeSyncTowerFan',
241
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
243
+ // No child_lock: the LTF-F422S API neither reports nor accepts it (pyvesync parity)
244
+ features: ['display', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
242
245
  levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
243
246
  },
244
247
  'LTF-F422S-WUS': {
245
248
  module: 'VeSyncTowerFan',
246
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
249
+ // No child_lock: the LTF-F422S API neither reports nor accepts it (pyvesync parity)
250
+ features: ['display', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
247
251
  levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
248
252
  },
249
253
  // Classic Series
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsvesync",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "A TypeScript library for interacting with VeSync smart home devices",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,6 +8,7 @@
8
8
  "build": "tsc",
9
9
  "clean": "rm -rf dist",
10
10
  "test:everest": "ts-node test/everest-air-parity.test.ts",
11
+ "test:child-lock": "ts-node test/child-lock-parity.test.ts",
11
12
  "prepare": "npm run build",
12
13
  "version": "git add -A src",
13
14
  "postversion": "git push && git push --tags",
@@ -52,6 +53,9 @@
52
53
  "files": [
53
54
  "dist/**/*",
54
55
  "src/**/*",
55
- "api/**/*"
56
+ "api/**/*",
57
+ "!**/*.bak",
58
+ "!**/*.orig",
59
+ "!**/*.rej"
56
60
  ]
57
61
  }
@@ -95,7 +95,8 @@ export class VeSyncAir131 extends VeSyncFan {
95
95
  speed: data.level || 0,
96
96
  filter_life: filterLife,
97
97
  screen_status: data.screenStatus || 'off',
98
- child_lock: data.childLock || false,
98
+ // The 131 API reports childLock as the string 'on'/'off'
99
+ child_lock: data.childLock === 'on' || data.childLock === true,
99
100
  air_quality: data.airQuality || 'unknown',
100
101
  air_quality_value: data.air_quality_value || 0,
101
102
  air_quality_level: normalizedAirQuality.level >= 1 ? normalizedAirQuality.level : undefined,
@@ -413,7 +414,7 @@ export class VeSyncAir131 extends VeSyncFan {
413
414
 
414
415
  const success = this.checkResponse([response, status], 'setChildLock');
415
416
  if (success) {
416
- this.details.childLock = enabled;
417
+ this.details.child_lock = enabled;
417
418
  return true;
418
419
  } else {
419
420
  // Check for error code 11000000 (feature not supported)
@@ -311,6 +311,58 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
311
311
  }
312
312
  }
313
313
 
314
+ /**
315
+ * Override setChildLock to send the childLockSwitch payload required by
316
+ * bypassV2 purifiers (Vital 100S/200S, Everest Air). These devices report
317
+ * child lock as childLockSwitch 0|1 and reject the legacy child_lock
318
+ * boolean payload used by the Core series (matches pyvesync, which sends
319
+ * {'childLockSwitch': int} for this family).
320
+ */
321
+ override async setChildLock(enabled: boolean): Promise<boolean> {
322
+ if (!this.requiresPowerSwitchPayload()) {
323
+ // Use parent implementation for non-bypassV2 models
324
+ return super.setChildLock(enabled);
325
+ }
326
+
327
+ if (!this.hasFeature('child_lock')) {
328
+ const error = 'Child lock not supported';
329
+ logger.error(`${error} for device: ${this.deviceName}`);
330
+ throw new Error(error);
331
+ }
332
+
333
+ logger.debug(`Setting child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
334
+
335
+ const [head, body] = this.buildApiDict('setChildLock');
336
+ body.payload.data = {
337
+ childLockSwitch: enabled ? 1 : 0
338
+ };
339
+
340
+ const [response, status] = await this.callApi(
341
+ '/cloud/v2/deviceManaged/bypassV2',
342
+ 'post',
343
+ body,
344
+ head
345
+ );
346
+
347
+ const success = this.checkV2Response(response, status, 'setChildLock');
348
+
349
+ // Code 11000000 marks the feature unsupported even when the envelope
350
+ // succeeds, so it must override the lenient inner-code handling
351
+ if (response?.code === 11000000 || (response?.result?.code === 11000000)) {
352
+ logger.warn(`Child lock control not supported via API for device: ${this.deviceName}`);
353
+ return false;
354
+ }
355
+
356
+ if (success) {
357
+ // No deferred details refresh here: pyvesync and the Core path
358
+ // both rely on the optimistic update plus the next regular poll
359
+ this.details.child_lock = enabled;
360
+ } else {
361
+ logger.error(`Failed to set child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
362
+ }
363
+ return success;
364
+ }
365
+
314
366
  /**
315
367
  * Override setMode to send workMode payloads for bypassV2 purifiers.
316
368
  */
@@ -233,7 +233,14 @@ export class VeSyncAirBypass extends VeSyncFan {
233
233
  );
234
234
 
235
235
  const success = this.checkResponse([response, status], 'changeFanSpeed');
236
- if (!success) {
236
+ if (success) {
237
+ // Reflect the change locally so callers don't read a stale speed
238
+ // until the next getDetails(). setLevel also puts the device into
239
+ // manual mode and turns it on, mirroring pyvesync's set_fan_speed.
240
+ this.details.speed = speed;
241
+ this.details.mode = 'manual';
242
+ this.deviceStatus = 'on';
243
+ } else {
237
244
  logger.error(`Failed to change fan speed to ${speed} for device: ${this.deviceName}`);
238
245
  }
239
246
  return success;
@@ -369,7 +376,7 @@ export class VeSyncAirBypass extends VeSyncFan {
369
376
  configModule: this.configModule,
370
377
  payload: {
371
378
  data: {
372
- state: enabled
379
+ child_lock: enabled
373
380
  },
374
381
  method: 'setChildLock',
375
382
  source: 'APP'
@@ -387,7 +394,7 @@ export class VeSyncAirBypass extends VeSyncFan {
387
394
  }
388
395
 
389
396
  if (success) {
390
- this.details.childLock = enabled;
397
+ this.details.child_lock = enabled;
391
398
  return true;
392
399
  } else {
393
400
  logger.error(`Failed to set child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
@@ -25,13 +25,13 @@ export const fanConfig: FanConfig = {
25
25
  'Core200S': {
26
26
  module: 'VeSyncAirBypass',
27
27
  features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'sleep_mode', 'filter_life'],
28
- levels: [1, 2, 3, 4], // 4 levels including sleep mode, matching reference plugin
28
+ levels: [1, 2, 3], // Low/Med/High; sleep is a mode, not a level
29
29
  modes: ['sleep', 'manual']
30
30
  },
31
31
  'Core300S': {
32
32
  module: 'VeSyncAirBypass',
33
33
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
34
- levels: [1, 2, 3, 4],
34
+ levels: [1, 2, 3],
35
35
  modes: ['sleep', 'manual', 'auto'],
36
36
  autoPreferences: ['default', 'efficient', 'quiet']
37
37
  },
@@ -66,21 +66,21 @@ export const fanConfig: FanConfig = {
66
66
  'LAP-C301S-WJP': {
67
67
  module: 'VeSyncAirBypass',
68
68
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
69
- levels: [1, 2, 3, 4],
69
+ levels: [1, 2, 3],
70
70
  modes: ['sleep', 'manual', 'auto'],
71
71
  autoPreferences: ['default', 'efficient', 'quiet']
72
72
  },
73
73
  'LAP-C302S-WUSB': {
74
74
  module: 'VeSyncAirBypass',
75
75
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
76
- levels: [1, 2, 3, 4],
76
+ levels: [1, 2, 3],
77
77
  modes: ['sleep', 'manual', 'auto'],
78
78
  autoPreferences: ['default', 'efficient', 'quiet']
79
79
  },
80
80
  'LAP-C301S-WAAA': {
81
81
  module: 'VeSyncAirBypass',
82
82
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
83
- levels: [1, 2, 3, 4],
83
+ levels: [1, 2, 3],
84
84
  modes: ['sleep', 'manual', 'auto'],
85
85
  autoPreferences: ['default', 'efficient', 'quiet']
86
86
  },
@@ -242,22 +242,26 @@ export const fanConfig: FanConfig = {
242
242
  // LTF Series
243
243
  'LTF-F422S-KEU': {
244
244
  module: 'VeSyncTowerFan',
245
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
245
+ // No child_lock: the LTF-F422S API neither reports nor accepts it (pyvesync parity)
246
+ features: ['display', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
246
247
  levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
247
248
  },
248
249
  'LTF-F422S-WUSR': {
249
250
  module: 'VeSyncTowerFan',
250
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
251
+ // No child_lock: the LTF-F422S API neither reports nor accepts it (pyvesync parity)
252
+ features: ['display', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
251
253
  levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
252
254
  },
253
255
  'LTF-F422_WJP': {
254
256
  module: 'VeSyncTowerFan',
255
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
257
+ // No child_lock: the LTF-F422S API neither reports nor accepts it (pyvesync parity)
258
+ features: ['display', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
256
259
  levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
257
260
  },
258
261
  'LTF-F422S-WUS': {
259
262
  module: 'VeSyncTowerFan',
260
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
263
+ // No child_lock: the LTF-F422S API neither reports nor accepts it (pyvesync parity)
264
+ features: ['display', 'night_light', 'timer', 'fan_speeds', 'tower_modes'],
261
265
  levels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
262
266
  },
263
267
 
@@ -1,890 +0,0 @@
1
- import { VeSyncFan } from '../vesyncFan';
2
- import { VeSync } from '../vesync';
3
- import { Helpers } from '../helpers';
4
- import { logger } from '../logger';
5
-
6
- /**
7
- * VeSync Air Purifier with Bypass
8
- */
9
- export class VeSyncAirBypass extends VeSyncFan {
10
- protected readonly modes = ['auto', 'manual', 'sleep'] as const;
11
- protected readonly displayModes = ['on', 'off'] as const;
12
- protected readonly childLockModes = ['on', 'off'] as const;
13
-
14
- constructor(details: Record<string, any>, manager: VeSync) {
15
- super(details, manager);
16
- logger.debug(`Initialized VeSyncAirBypass device: ${this.deviceName}`);
17
- }
18
- }
19
- /**
20
- * Build API dictionary
21
- */
22
- protected buildApiDict(method: string): [Record<string, any>, Record<string, any>] {
23
- const head = Helpers.reqHeaderBypass();
24
- const body = {
25
- ...Helpers.reqBody(this.manager, 'bypassV2'),
26
- cid: this.cid,
27
- configModule: this.configModule,
28
- payload: {
29
- method,
30
- source: 'APP',
31
- data: {}
32
- }
33
- };
34
- return [head, body];
35
- }
36
-
37
- /**
38
- * Get device details
39
- */
40
- async getDetails(): Promise<Boolean> {
41
- logger.debug(`Getting details for device: ${this.deviceName}`);
42
-
43
- // Special handling for LV series
44
- if (this.deviceType.startsWith('LV-')) {
45
- const [response, status] = await this.callApi(
46
- '/131airPurifier/v1/device/devicedetail',
47
- 'post',
48
- {
49
- acceptLanguage: 'en',
50
- accountID: this.manager.accountId!,
51
- appVersion: '2.8.6',
52
- method: 'devicedetail',
53
- mobileId: '1234567890123456',
54
- phoneBrand: 'SM N9005',
55
- phoneOS: 'Android',
56
- timeZone: this.manager.timeZone!,
57
- token: this.manager.token!,
58
- uuid: this.uuid
59
- },
60
- {
61
- 'accept-language': 'en',
62
- 'accountId': this.manager.accountId!,
63
- 'appVersion': '2.8.6',
64
- 'content-type': 'application/json',
65
- 'tk': this.manager.token!,
66
- 'tz': this.manager.timeZone!
67
- }
68
- );
69
-
70
- const success = this.checkResponse([response, status], 'getDetails');
71
- if (success && response) {
72
- this.deviceStatus = response.result?.result?.deviceStatus === 'on' ? 'on' : 'off';
73
- this.details = {
74
- mode: response.result?.result?.mode || '',
75
- speed: response.result?.result?.level || 0,
76
- filterLife: response.result?.result?.filterLife || 0,
77
- screenStatus: response.result?.result?.display ? 'on' : 'off',
78
- childLock: response.result?.result?.childLock || false,
79
- airQuality: response.result?.result?.airQuality || 0
80
- };
81
- return true;
82
- }
83
- return false;
84
- }
85
-
86
- // Original implementation for other devices
87
- const [response, status] = await this.callApi(
88
- '/cloud/v2/deviceManaged/bypassV2',
89
- 'post',
90
- {
91
- ...Helpers.reqBody(this.manager, 'bypassV2'),
92
- cid: this.cid,
93
- configModule: this.configModule,
94
- payload: {
95
- data: {},
96
- method: 'getPurifierStatus',
97
- source: 'APP'
98
- }
99
- },
100
- Helpers.reqHeaderBypass()
101
- );
102
-
103
- const success = this.checkResponse([response, status], 'getDetails');
104
- if (success) {
105
- const result = response?.result?.result;
106
- if (result) {
107
- this.deviceStatus = result.enabled ? 'on' : 'off';
108
- this.details = {
109
- mode: result.mode || '',
110
- speed: result.level || 0,
111
- filterLife: result.filter_life || 0,
112
- screenStatus: result.display ? 'on' : 'off',
113
- childLock: result.child_lock || false,
114
- airQuality: result.air_quality || 0
115
- };
116
-
117
- // Don't overwrite config as it contains features array
118
- if (result.configuration) {
119
- this.details.configuration = result.configuration;
120
- }
121
- logger.debug(`Successfully got details for device: ${this.deviceName}`);
122
- }
123
- }
124
- return success;
125
- }
126
-
127
- /**
128
- * Turn device on
129
- */
130
- async turnOn(): Promise<boolean> {
131
- logger.info(`Turning on device: ${this.deviceName}`);
132
-
133
- // Special handling for LV series
134
- if (this.deviceType.startsWith('LV-')) {
135
- const [response, status] = await this.callApi(
136
- '/131airPurifier/v1/device/deviceStatus',
137
- 'put',
138
- {
139
- acceptLanguage: 'en',
140
- accountID: this.manager.accountId!,
141
- status: 'on',
142
- timeZone: this.manager.timeZone!,
143
- token: this.manager.token!,
144
- uuid: this.uuid
145
- },
146
- {
147
- 'accept-language': 'en',
148
- 'accountId': this.manager.accountId!,
149
- 'appVersion': '2.8.6',
150
- 'content-type': 'application/json',
151
- 'tk': this.manager.token!,
152
- 'tz': this.manager.timeZone!
153
- }
154
- );
155
-
156
- const success = this.checkResponse([response, status], 'turnOn');
157
- if (!success) {
158
- logger.error(`Failed to turn on device: ${this.deviceName}`);
159
- }
160
- return success;
161
- }
162
-
163
- // Original implementation for other devices
164
- const [response, status] = await this.callApi(
165
- '/cloud/v2/deviceManaged/bypassV2',
166
- 'post',
167
- {
168
- ...Helpers.reqBody(this.manager, 'bypassV2'),
169
- cid: this.cid,
170
- configModule: this.configModule,
171
- payload: {
172
- data: {
173
- enabled: true,
174
- id: 0
175
- },
176
- method: 'setSwitch',
177
- source: 'APP'
178
- }
179
- },
180
- Helpers.reqHeaderBypass()
181
- );
182
-
183
- const success = this.checkResponse([response, status], 'turnOn');
184
- if (!success) {
185
- logger.error(`Failed to turn on device: ${this.deviceName}`);
186
- }
187
- return success;
188
- }
189
-
190
- /**
191
- * Turn device off
192
- */
193
- async turnOff(): Promise<boolean> {
194
- logger.info(`Turning off device: ${this.deviceName}`);
195
-
196
- // Special handling for LV series
197
- if (this.deviceType.startsWith('LV-')) {
198
- const [response, status] = await this.callApi(
199
- '/131airPurifier/v1/device/deviceStatus',
200
- 'put',
201
- {
202
- acceptLanguage: 'en',
203
- accountID: this.manager.accountId!,
204
- status: 'off',
205
- timeZone: this.manager.timeZone!,
206
- token: this.manager.token!,
207
- uuid: this.uuid
208
- },
209
- {
210
- 'accept-language': 'en',
211
- 'accountId': this.manager.accountId!,
212
- 'appVersion': '2.8.6',
213
- 'content-type': 'application/json',
214
- 'tk': this.manager.token!,
215
- 'tz': this.manager.timeZone!
216
- }
217
- );
218
-
219
- const success = this.checkResponse([response, status], 'turnOff');
220
- if (!success) {
221
- logger.error(`Failed to turn off device: ${this.deviceName}`);
222
- }
223
- return success;
224
- }
225
-
226
- // Original implementation for other devices
227
- const [response, status] = await this.callApi(
228
- '/cloud/v2/deviceManaged/bypassV2',
229
- 'post',
230
- {
231
- ...Helpers.reqBody(this.manager, 'bypassV2'),
232
- cid: this.cid,
233
- configModule: this.configModule,
234
- payload: {
235
- data: {
236
- enabled: false,
237
- id: 0
238
- },
239
- method: 'setSwitch',
240
- source: 'APP'
241
- }
242
- },
243
- Helpers.reqHeaderBypass()
244
- );
245
-
246
- const success = this.checkResponse([response, status], 'turnOff');
247
- if (!success) {
248
- logger.error(`Failed to turn off device: ${this.deviceName}`);
249
- }
250
- return success;
251
- }
252
-
253
- /**
254
- * Change fan speed
255
- */
256
- async changeFanSpeed(speed: number): Promise<boolean> {
257
- // const speeds = this.config.levels ?? [];
258
- // if (!speeds.includes(speed)) {
259
- // logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
260
- // return false;
261
- // }
262
-
263
- logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
264
-
265
- // Special handling for LV series
266
- if (this.deviceType.startsWith('LV-')) {
267
- // Check if device is in manual mode
268
- if (this.details.mode !== 'manual') {
269
- logger.debug(`${this.deviceName} not in manual mode, cannot change speed`);
270
- return false;
271
- }
272
-
273
- // Validate speed for LV series (1-3)
274
- if (speed < 1 || speed > 3) {
275
- logger.error(`Invalid fan speed: ${speed}. Must be between 1 and 3 for device: ${this.deviceName}`);
276
- return false;
277
- }
278
-
279
- const [response, status] = await this.callApi(
280
- '/131airPurifier/v1/device/updateSpeed',
281
- 'put',
282
- {
283
- acceptLanguage: 'en',
284
- accountID: this.manager.accountId!,
285
- level: speed,
286
- timeZone: this.manager.timeZone!,
287
- token: this.manager.token!,
288
- uuid: this.uuid
289
- },
290
- {
291
- 'accept-language': 'en',
292
- 'accountId': this.manager.accountId!,
293
- 'appVersion': '2.8.6',
294
- 'content-type': 'application/json',
295
- 'tk': this.manager.token!,
296
- 'tz': this.manager.timeZone!
297
- }
298
- );
299
-
300
- const success = this.checkResponse([response, status], 'changeFanSpeed');
301
- if (success) {
302
- this.details.speed = speed;
303
- return true;
304
- } else {
305
- logger.error(`Failed to change fan speed to ${speed} for device: ${this.deviceName}`);
306
- return false;
307
- }
308
- }
309
-
310
- // Standard implementation for other devices
311
- const [response, status] = await this.callApi(
312
- '/cloud/v2/deviceManaged/bypassV2',
313
- 'post',
314
- {
315
- ...Helpers.reqBody(this.manager, 'bypassV2'),
316
- cid: this.cid,
317
- configModule: this.configModule,
318
- payload: {
319
- data: {
320
- id: 0,
321
- level: speed,
322
- mode: 'manual',
323
- type: 'wind'
324
- },
325
- method: 'setLevel',
326
- source: 'APP'
327
- }
328
- },
329
- Helpers.reqHeaderBypass()
330
- );
331
-
332
- const success = this.checkResponse([response, status], 'changeFanSpeed');
333
- if (!success) {
334
- logger.error(`Failed to change fan speed to ${speed} for device: ${this.deviceName}`);
335
- }
336
- return success;
337
- }
338
-
339
- /**
340
- * Set device mode
341
- */
342
- async setMode(mode: string): Promise<boolean> {
343
- if (!this.modes.includes(mode as any)) {
344
- const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
345
- logger.error(`${error} for device: ${this.deviceName}`);
346
- throw new Error(error);
347
- }
348
-
349
- logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
350
-
351
- // Special handling for LV series
352
- if (this.deviceType.startsWith('LV-')) {
353
- const payload: Record<string, any> = {
354
- acceptLanguage: 'en',
355
- accountID: this.manager.accountId!,
356
- mode: mode,
357
- timeZone: this.manager.timeZone!,
358
- token: this.manager.token!,
359
- uuid: this.uuid
360
- };
361
-
362
- // For manual mode, we need to set the level
363
- if (mode === 'manual') {
364
- payload.level = this.details.speed || 1;
365
- }
366
-
367
- const [response, status] = await this.callApi(
368
- '/131airPurifier/v1/device/updateMode',
369
- 'put',
370
- payload,
371
- {
372
- 'accept-language': 'en',
373
- 'accountId': this.manager.accountId!,
374
- 'appVersion': '2.8.6',
375
- 'content-type': 'application/json',
376
- 'tk': this.manager.token!,
377
- 'tz': this.manager.timeZone!
378
- }
379
- );
380
-
381
- const success = this.checkResponse([response, status], 'setMode');
382
- if (success) {
383
- this.details.mode = mode;
384
- return true;
385
- } else {
386
- logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
387
- return false;
388
- }
389
- }
390
-
391
- // Special handling for Core200S auto mode
392
- if (this.deviceType.includes('Core200S') && mode === 'auto') {
393
- // Core200S doesn't support auto mode, so we'll set it to manual mode
394
- logger.warn(`Auto mode not supported for ${this.deviceType}, using manual mode instead`);
395
- return this.setMode('manual');
396
- }
397
-
398
- // Standard implementation for other devices
399
- const [response, status] = await this.callApi(
400
- '/cloud/v2/deviceManaged/bypassV2',
401
- 'post',
402
- {
403
- ...Helpers.reqBody(this.manager, 'bypassV2'),
404
- cid: this.cid,
405
- configModule: this.configModule,
406
- payload: {
407
- data: {
408
- mode
409
- },
410
- method: 'setPurifierMode',
411
- source: 'APP'
412
- }
413
- },
414
- Helpers.reqHeaderBypass()
415
- );
416
-
417
- const success = this.checkResponse([response, status], 'setMode');
418
- if (success) {
419
- this.details.mode = mode;
420
- return true;
421
- } else {
422
- logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
423
- return false;
424
- }
425
- }
426
-
427
- /**
428
- * Set display status
429
- */
430
- async setDisplay(enabled: boolean): Promise<boolean> {
431
- if (!this.hasFeature('display')) {
432
- const error = 'Display control not supported';
433
- logger.error(`${error} for device: ${this.deviceName}`);
434
- throw new Error(error);
435
- }
436
-
437
- // Check if device is in sleep mode - display control may not work in sleep mode
438
- if (this.details.mode === 'sleep') {
439
- logger.warn(`Device ${this.deviceName} is in sleep mode, display control may not work`);
440
- }
441
-
442
- logger.debug(`Setting display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
443
-
444
- // Special handling for LV series
445
- if (this.deviceType.startsWith('LV-')) {
446
- const [response, status] = await this.callApi(
447
- '/131airPurifier/v1/device/updateScreen',
448
- 'put',
449
- {
450
- acceptLanguage: 'en',
451
- accountID: this.manager.accountId!,
452
- status: enabled ? 'on' : 'off',
453
- timeZone: this.manager.timeZone!,
454
- token: this.manager.token!,
455
- uuid: this.uuid
456
- },
457
- {
458
- 'accept-language': 'en',
459
- 'accountId': this.manager.accountId!,
460
- 'appVersion': '2.8.6',
461
- 'content-type': 'application/json',
462
- 'tk': this.manager.token!,
463
- 'tz': this.manager.timeZone!
464
- }
465
- );
466
-
467
- const success = this.checkResponse([response, status], 'setDisplay');
468
- if (success) {
469
- this.details.screenStatus = enabled ? 'on' : 'off';
470
- return true;
471
- } else {
472
- logger.error(`Failed to set display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
473
- return false;
474
- }
475
- }
476
-
477
- // Standard implementation for other devices
478
- const [response, status] = await this.callApi(
479
- '/cloud/v2/deviceManaged/bypassV2',
480
- 'post',
481
- {
482
- ...Helpers.reqBody(this.manager, 'bypassV2'),
483
- cid: this.cid,
484
- configModule: this.configModule,
485
- payload: {
486
- data: {
487
- state: enabled
488
- },
489
- method: 'setDisplay',
490
- source: 'APP'
491
- }
492
- },
493
- Helpers.reqHeaderBypass()
494
- );
495
-
496
- const success = this.checkResponse([response, status], 'setDisplay');
497
-
498
- // Check for error code 11018000 (operation not supported in current mode)
499
- if (response?.result?.code === 11018000) {
500
- logger.warn(`Display control not supported in current mode for device: ${this.deviceName}`);
501
- return false;
502
- }
503
-
504
- if (success) {
505
- this.details.screenStatus = enabled ? 'on' : 'off';
506
- return true;
507
- } else {
508
- logger.error(`Failed to set display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
509
- return false;
510
- }
511
- }
512
-
513
- /**
514
- * Set child lock
515
- */
516
- async setChildLock(enabled: boolean): Promise<boolean> {
517
- if (!this.hasFeature('child_lock')) {
518
- const error = 'Child lock not supported';
519
- logger.error(`${error} for device: ${this.deviceName}`);
520
- throw new Error(error);
521
- }
522
-
523
- // Check if device is in sleep mode - child lock may not work in sleep mode
524
- if (this.details.mode === 'sleep') {
525
- logger.warn(`Device ${this.deviceName} is in sleep mode, child lock control may not work`);
526
- }
527
-
528
- logger.debug(`Setting child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
529
-
530
- // Special handling for LV series
531
- if (this.deviceType.startsWith('LV-')) {
532
- const [response, status] = await this.callApi(
533
- '/131airPurifier/v1/device/updateChildLock',
534
- 'put',
535
- {
536
- acceptLanguage: 'en',
537
- accountID: this.manager.accountId!,
538
- status: enabled ? 'on' : 'off',
539
- timeZone: this.manager.timeZone!,
540
- token: this.manager.token!,
541
- uuid: this.uuid
542
- },
543
- {
544
- 'accept-language': 'en',
545
- 'accountId': this.manager.accountId!,
546
- 'appVersion': '2.8.6',
547
- 'content-type': 'application/json',
548
- 'tk': this.manager.token!,
549
- 'tz': this.manager.timeZone!
550
- }
551
- );
552
-
553
- const success = this.checkResponse([response, status], 'setChildLock');
554
- if (success) {
555
- this.details.childLock = enabled;
556
- return true;
557
- } else {
558
- // Check for error code 11000000 (feature not supported)
559
- if (response?.code === 11000000) {
560
- logger.warn(`Child lock control not supported via API for device: ${this.deviceName}`);
561
- return false;
562
- }
563
- logger.error(`Failed to set child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
564
- return false;
565
- }
566
- }
567
-
568
- // Standard implementation for other devices
569
- const [response, status] = await this.callApi(
570
- '/cloud/v2/deviceManaged/bypassV2',
571
- 'post',
572
- {
573
- ...Helpers.reqBody(this.manager, 'bypassV2'),
574
- cid: this.cid,
575
- configModule: this.configModule,
576
- payload: {
577
- data: {
578
- state: enabled
579
- },
580
- method: 'setChildLock',
581
- source: 'APP'
582
- }
583
- },
584
- Helpers.reqHeaderBypass()
585
- );
586
-
587
- const success = this.checkResponse([response, status], 'setChildLock');
588
-
589
- // Check for error code 11000000 (feature not supported)
590
- if (response?.code === 11000000 || (response?.result?.code === 11000000)) {
591
- logger.warn(`Child lock control not supported via API for device: ${this.deviceName}`);
592
- return false;
593
- }
594
-
595
- if (success) {
596
- this.details.childLock = enabled;
597
- return true;
598
- } else {
599
- logger.error(`Failed to set child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
600
- return false;
601
- }
602
- }
603
-
604
- /**
605
- * Set timer
606
- */
607
- async setTimer(hours: number): Promise<boolean> {
608
- if (!this.hasFeature('timer')) {
609
- const error = 'Timer not supported';
610
- logger.error(`${error} for device: ${this.deviceName}`);
611
- throw new Error(error);
612
- }
613
-
614
- logger.debug(`Setting timer to ${hours} hours for device: ${this.deviceName}`);
615
-
616
- // Special handling for LV series
617
- if (this.deviceType.startsWith('LV-')) {
618
- const [response, status] = await this.callApi(
619
- '/131airPurifier/v1/device/updateTimer',
620
- 'put',
621
- {
622
- acceptLanguage: 'en',
623
- accountID: this.manager.accountId!,
624
- action: 'off',
625
- duration: hours,
626
- timeZone: this.manager.timeZone!,
627
- token: this.manager.token!,
628
- uuid: this.uuid
629
- },
630
- {
631
- 'accept-language': 'en',
632
- 'accountId': this.manager.accountId!,
633
- 'appVersion': '2.8.6',
634
- 'content-type': 'application/json',
635
- 'tk': this.manager.token!,
636
- 'tz': this.manager.timeZone!
637
- }
638
- );
639
-
640
- const success = this.checkResponse([response, status], 'setTimer');
641
- if (success) {
642
- this.timer = { duration: hours * 3600, action: 'off' };
643
- return true;
644
- } else {
645
- logger.error(`Failed to set timer to ${hours} hours for device: ${this.deviceName}`);
646
- return false;
647
- }
648
- }
649
-
650
- // Standard implementation for other devices
651
- const [response, status] = await this.callApi(
652
- '/cloud/v2/deviceManaged/bypassV2',
653
- 'post',
654
- {
655
- ...Helpers.reqBody(this.manager, 'bypassV2'),
656
- cid: this.cid,
657
- configModule: this.configModule,
658
- payload: {
659
- data: {
660
- action: 'off',
661
- total: hours * 3600
662
- },
663
- method: 'addTimer',
664
- source: 'APP'
665
- }
666
- },
667
- Helpers.reqHeaderBypass()
668
- );
669
-
670
- const success = this.checkResponse([response, status], 'setTimer');
671
-
672
- // Check for successful response with timer ID
673
- if (success && response?.result?.result?.id) {
674
- this.timer = { duration: hours * 3600, action: 'off' };
675
- return true;
676
- } else if (success) {
677
- // API call succeeded but no timer ID returned
678
- logger.warn(`Timer API call succeeded but no timer ID returned for device: ${this.deviceName}`);
679
- this.timer = { duration: hours * 3600, action: 'off' };
680
- return true;
681
- } else {
682
- logger.error(`Failed to set timer to ${hours} hours for device: ${this.deviceName}`);
683
- return false;
684
- }
685
- }
686
-
687
- /**
688
- * Clear timer
689
- */
690
- async clearTimer(): Promise<boolean> {
691
- if (!this.hasFeature('timer')) {
692
- const error = 'Timer not supported';
693
- logger.error(`${error} for device: ${this.deviceName}`);
694
- throw new Error(error);
695
- }
696
-
697
- // If no timer is set, return success
698
- if (!this.timer) {
699
- logger.debug(`No timer to clear for device: ${this.deviceName}`);
700
- return true;
701
- }
702
-
703
- logger.debug(`Clearing timer for device: ${this.deviceName}`);
704
-
705
- // Special handling for LV series
706
- if (this.deviceType.startsWith('LV-')) {
707
- const [response, status] = await this.callApi(
708
- '/131airPurifier/v1/device/cancelTimer',
709
- 'put',
710
- {
711
- acceptLanguage: 'en',
712
- accountID: this.manager.accountId!,
713
- timeZone: this.manager.timeZone!,
714
- token: this.manager.token!,
715
- uuid: this.uuid
716
- },
717
- {
718
- 'accept-language': 'en',
719
- 'accountId': this.manager.accountId!,
720
- 'appVersion': '2.8.6',
721
- 'content-type': 'application/json',
722
- 'tk': this.manager.token!,
723
- 'tz': this.manager.timeZone!
724
- }
725
- );
726
-
727
- const success = this.checkResponse([response, status], 'clearTimer');
728
- if (success) {
729
- this.timer = null;
730
- return true;
731
- } else {
732
- logger.error(`Failed to clear timer for device: ${this.deviceName}`);
733
- return false;
734
- }
735
- }
736
-
737
- // Standard implementation for other devices
738
- const [response, status] = await this.callApi(
739
- '/cloud/v2/deviceManaged/bypassV2',
740
- 'post',
741
- {
742
- ...Helpers.reqBody(this.manager, 'bypassV2'),
743
- cid: this.cid,
744
- configModule: this.configModule,
745
- payload: {
746
- data: {},
747
- method: 'deleteTimer',
748
- source: 'APP'
749
- }
750
- },
751
- Helpers.reqHeaderBypass()
752
- );
753
-
754
- const success = this.checkResponse([response, status], 'clearTimer');
755
-
756
- // Check for error code 11000000 (feature not supported or no timer to clear)
757
- if (response?.code === 11000000 || (response?.result?.code === 11000000)) {
758
- logger.warn(`No timer to clear or timer control not supported via API for device: ${this.deviceName}`);
759
- this.timer = null;
760
- return true;
761
- }
762
-
763
- if (success) {
764
- this.timer = null;
765
- return true;
766
- } else {
767
- logger.error(`Failed to clear timer for device: ${this.deviceName}`);
768
- return false;
769
- }
770
- }
771
-
772
- /**
773
- * Turn automatic stop on
774
- */
775
- async automaticStopOn(): Promise<boolean> {
776
- logger.debug(`Setting automatic stop on for device: ${this.deviceName}`);
777
- const [response, status] = await this.callApi(
778
- '/cloud/v2/deviceManaged/bypassV2',
779
- 'post',
780
- {
781
- ...Helpers.reqBody(this.manager, 'bypassV2'),
782
- cid: this.cid,
783
- configModule: this.configModule,
784
- payload: {
785
- data: {
786
- enabled: true
787
- },
788
- method: 'setAutomaticStop',
789
- source: 'APP'
790
- }
791
- },
792
- Helpers.reqHeaderBypass()
793
- );
794
-
795
- const success = this.checkResponse([response, status], 'automaticStopOn');
796
- if (!success) {
797
- logger.error(`Failed to set automatic stop on for device: ${this.deviceName}`);
798
- }
799
- return success;
800
- }
801
-
802
- /**
803
- * Turn automatic stop off
804
- */
805
- async automaticStopOff(): Promise<boolean> {
806
- logger.debug(`Setting automatic stop off for device: ${this.deviceName}`);
807
- const [response, status] = await this.callApi(
808
- '/cloud/v2/deviceManaged/bypassV2',
809
- 'post',
810
- {
811
- ...Helpers.reqBody(this.manager, 'bypassV2'),
812
- cid: this.cid,
813
- configModule: this.configModule,
814
- payload: {
815
- data: {
816
- enabled: false
817
- },
818
- method: 'setAutomaticStop',
819
- source: 'APP'
820
- }
821
- },
822
- Helpers.reqHeaderBypass()
823
- );
824
-
825
- const success = this.checkResponse([response, status], 'automaticStopOff');
826
- if (!success) {
827
- logger.error(`Failed to set automatic stop off for device: ${this.deviceName}`);
828
- }
829
- return success;
830
- }
831
-
832
- /**
833
- * Set auto mode
834
- */
835
- async autoMode(): Promise<boolean> {
836
- logger.debug(`Setting auto mode for device: ${this.deviceName}`);
837
- const success = await this.setMode('auto');
838
- if (!success) {
839
- logger.error(`Failed to set auto mode for device: ${this.deviceName}`);
840
- }
841
- return success;
842
- }
843
-
844
- /**
845
- * Set manual mode
846
- */
847
- async manualMode(): Promise<boolean> {
848
- logger.debug(`Setting manual mode for device: ${this.deviceName}`);
849
- const success = await this.setMode('manual');
850
- if (!success) {
851
- logger.error(`Failed to set manual mode for device: ${this.deviceName}`);
852
- }
853
- return success;
854
- }
855
-
856
- /**
857
- * Set sleep mode
858
- */
859
- async sleepMode(): Promise<boolean> {
860
- logger.debug(`Setting sleep mode for device: ${this.deviceName}`);
861
- const success = await this.setMode('sleep');
862
- if (!success) {
863
- logger.error(`Failed to set sleep mode for device: ${this.deviceName}`);
864
- }
865
- return success;
866
- }
867
-
868
- /**
869
- * Turn off display
870
- */
871
- async turnOffDisplay(): Promise<boolean> {
872
- logger.debug(`Turning off display for device: ${this.deviceName}`);
873
- const success = await this.setDisplay(false);
874
- if (!success) {
875
- logger.error(`Failed to turn off display for device: ${this.deviceName}`);
876
- }
877
- return success;
878
- }
879
-
880
- /**
881
- * Turn on display
882
- */
883
- async turnOnDisplay(): Promise<boolean> {
884
- logger.debug(`Turning on display for device: ${this.deviceName}`);
885
- const success = await this.setDisplay(true);
886
- if (!success) {
887
- logger.error(`Failed to turn on display for device: ${this.deviceName}`);
888
- }
889
- return success;
890
- }