tsvesync 1.0.47 → 1.0.49

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.
@@ -82,10 +82,6 @@ export declare class VeSync {
82
82
  * Correct devices without cid or uuid
83
83
  */
84
84
  static setDevId(devices: any[]): any[];
85
- /**
86
- * Check if a device should be excluded based on configuration
87
- */
88
- private shouldExcludeDevice;
89
85
  /**
90
86
  * Process devices from API response
91
87
  */
@@ -102,6 +98,10 @@ export declare class VeSync {
102
98
  * Test if update interval has been exceeded
103
99
  */
104
100
  deviceTimeCheck(): boolean;
101
+ /**
102
+ * Check if a device should be excluded based on configuration
103
+ */
104
+ private shouldExcludeDevice;
105
105
  /**
106
106
  * Update device list and details
107
107
  */
@@ -285,52 +285,6 @@ class VeSync {
285
285
  }
286
286
  return devices;
287
287
  }
288
- /**
289
- * Check if a device should be excluded based on configuration
290
- */
291
- shouldExcludeDevice(device) {
292
- var _a, _b, _c, _d, _e;
293
- if (!this._excludeConfig) {
294
- return false;
295
- }
296
- const exclude = this._excludeConfig;
297
- // Check device type
298
- if ((_a = exclude.type) === null || _a === void 0 ? void 0 : _a.includes(device.deviceType.toLowerCase())) {
299
- logger_1.logger.debug(`Excluding device ${device.deviceName} by type: ${device.deviceType}`);
300
- return true;
301
- }
302
- // Check device model
303
- if ((_b = exclude.model) === null || _b === void 0 ? void 0 : _b.some(model => device.deviceType.toUpperCase().includes(model.toUpperCase()))) {
304
- logger_1.logger.debug(`Excluding device ${device.deviceName} by model: ${device.deviceType}`);
305
- return true;
306
- }
307
- // Check exact name match
308
- if ((_c = exclude.name) === null || _c === void 0 ? void 0 : _c.includes(device.deviceName.trim())) {
309
- logger_1.logger.debug(`Excluding device ${device.deviceName} by exact name match`);
310
- return true;
311
- }
312
- // Check name patterns
313
- if (exclude.namePattern) {
314
- for (const pattern of exclude.namePattern) {
315
- try {
316
- const regex = new RegExp(pattern);
317
- if (regex.test(device.deviceName.trim())) {
318
- logger_1.logger.debug(`Excluding device ${device.deviceName} by name pattern: ${pattern}`);
319
- return true;
320
- }
321
- }
322
- catch (error) {
323
- logger_1.logger.warn(`Invalid regex pattern in exclude config: ${pattern}`);
324
- }
325
- }
326
- }
327
- // Check device ID (cid or uuid)
328
- if (((_d = exclude.id) === null || _d === void 0 ? void 0 : _d.includes(device.cid)) || ((_e = exclude.id) === null || _e === void 0 ? void 0 : _e.includes(device.uuid))) {
329
- logger_1.logger.debug(`Excluding device ${device.deviceName} by ID: ${device.cid}/${device.uuid}`);
330
- return true;
331
- }
332
- return false;
333
- }
334
288
  /**
335
289
  * Process devices from API response
336
290
  */
@@ -346,10 +300,6 @@ class VeSync {
346
300
  }
347
301
  // Process each device
348
302
  deviceList.forEach(dev => {
349
- // Check if device should be excluded
350
- if (this.shouldExcludeDevice(dev)) {
351
- return;
352
- }
353
303
  const [category, device] = objectFactory(dev, this);
354
304
  // Handle outdoor plug sub-devices
355
305
  if (dev.deviceType === 'ESO15-TB' && dev.subDeviceNo) {
@@ -360,12 +310,9 @@ class VeSync {
360
310
  subDeviceNo: dev.subDeviceNo,
361
311
  isSubDevice: true,
362
312
  };
363
- // Check if sub-device should be excluded
364
- if (!this.shouldExcludeDevice(subDeviceDetails)) {
365
- const [subCategory, subDevice] = objectFactory(subDeviceDetails, this);
366
- if (subDevice && subCategory in this._devList) {
367
- this._devList[subCategory].push(subDevice);
368
- }
313
+ const [subCategory, subDevice] = objectFactory(subDeviceDetails, this);
314
+ if (subDevice && subCategory in this._devList) {
315
+ this._devList[subCategory].push(subDevice);
369
316
  }
370
317
  }
371
318
  else if (device && category in this._devList) {
@@ -501,6 +448,52 @@ class VeSync {
501
448
  return (this._lastUpdateTs === null ||
502
449
  (Date.now() - this._lastUpdateTs) / 1000 > this.updateInterval);
503
450
  }
451
+ /**
452
+ * Check if a device should be excluded based on configuration
453
+ */
454
+ shouldExcludeDevice(device) {
455
+ var _a, _b, _c, _d, _e;
456
+ if (!this._excludeConfig) {
457
+ return false;
458
+ }
459
+ const exclude = this._excludeConfig;
460
+ // Check device type
461
+ if ((_a = exclude.type) === null || _a === void 0 ? void 0 : _a.includes(device.deviceType.toLowerCase())) {
462
+ logger_1.logger.debug(`Excluding device ${device.deviceName} by type: ${device.deviceType}`);
463
+ return true;
464
+ }
465
+ // Check device model
466
+ if ((_b = exclude.model) === null || _b === void 0 ? void 0 : _b.some(model => device.deviceType.toUpperCase().includes(model.toUpperCase()))) {
467
+ logger_1.logger.debug(`Excluding device ${device.deviceName} by model: ${device.deviceType}`);
468
+ return true;
469
+ }
470
+ // Check exact name match
471
+ if ((_c = exclude.name) === null || _c === void 0 ? void 0 : _c.includes(device.deviceName.trim())) {
472
+ logger_1.logger.debug(`Excluding device ${device.deviceName} by exact name match`);
473
+ return true;
474
+ }
475
+ // Check name patterns
476
+ if (exclude.namePattern) {
477
+ for (const pattern of exclude.namePattern) {
478
+ try {
479
+ const regex = new RegExp(pattern);
480
+ if (regex.test(device.deviceName.trim())) {
481
+ logger_1.logger.debug(`Excluding device ${device.deviceName} by name pattern: ${pattern}`);
482
+ return true;
483
+ }
484
+ }
485
+ catch (error) {
486
+ logger_1.logger.warn(`Invalid regex pattern in exclude config: ${pattern}`);
487
+ }
488
+ }
489
+ }
490
+ // Check device ID (cid or uuid)
491
+ if (((_d = exclude.id) === null || _d === void 0 ? void 0 : _d.includes(device.cid)) || ((_e = exclude.id) === null || _e === void 0 ? void 0 : _e.includes(device.uuid))) {
492
+ logger_1.logger.debug(`Excluding device ${device.deviceName} by ID: ${device.cid}/${device.uuid}`);
493
+ return true;
494
+ }
495
+ return false;
496
+ }
504
497
  /**
505
498
  * Update device list and details
506
499
  */
@@ -515,7 +508,12 @@ class VeSync {
515
508
  for (const deviceList of Object.values(this._devList)) {
516
509
  for (const device of deviceList) {
517
510
  try {
518
- await device.getDetails();
511
+ if (!this.shouldExcludeDevice(device)) {
512
+ await device.getDetails();
513
+ }
514
+ else {
515
+ logger_1.logger.debug(`Skipping details update for excluded device: ${device.deviceName}`);
516
+ }
519
517
  }
520
518
  catch (error) {
521
519
  logger_1.logger.error(`Error updating ${device.deviceName}:`, error);
@@ -314,6 +314,10 @@ export declare class VeSyncAirBaseV2 extends VeSyncAirBypass {
314
314
  * Display JSON details
315
315
  */
316
316
  displayJSON(): string;
317
+ /**
318
+ * Set oscillation state
319
+ */
320
+ setOscillation(toggle: boolean): Promise<boolean>;
317
321
  }
318
322
  /**
319
323
  * VeSync Tower Fan Implementation
@@ -421,10 +425,6 @@ export declare class VeSyncTowerFan extends VeSyncAirBaseV2 {
421
425
  * Get error code
422
426
  */
423
427
  get errorCode(): number;
424
- /**
425
- * Set oscillation state
426
- */
427
- setOscillation(toggle: boolean): Promise<boolean>;
428
428
  /**
429
429
  * Turn oscillation on
430
430
  */
@@ -1449,6 +1449,24 @@ class VeSyncAirBaseV2 extends VeSyncAirBypass {
1449
1449
  }
1450
1450
  return JSON.stringify(details, null, 4);
1451
1451
  }
1452
+ /**
1453
+ * Set oscillation state
1454
+ */
1455
+ async setOscillation(toggle) {
1456
+ logger_1.logger.debug(`Setting oscillation to ${toggle ? 'on' : 'off'} for device: ${this.deviceName}`);
1457
+ const [head, body] = this.buildApiDict('setSwitch');
1458
+ body.payload.data = {
1459
+ oscillationSwitch: toggle ? 1 : 0,
1460
+ switchIdx: 0
1461
+ };
1462
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1463
+ const success = this.checkResponse([response, status], 'setOscillation');
1464
+ if (success) {
1465
+ this.details.oscillationState = toggle;
1466
+ this.details.oscillationSwitch = toggle ? 1 : 0;
1467
+ }
1468
+ return success;
1469
+ }
1452
1470
  }
1453
1471
  exports.VeSyncAirBaseV2 = VeSyncAirBaseV2;
1454
1472
  /**
@@ -1718,18 +1736,6 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
1718
1736
  get errorCode() {
1719
1737
  return this.details.errorCode || 0;
1720
1738
  }
1721
- /**
1722
- * Set oscillation state
1723
- */
1724
- async setOscillation(toggle) {
1725
- logger_1.logger.debug(`Setting oscillation to ${toggle ? 'on' : 'off'} for device: ${this.deviceName}`);
1726
- const [head, body] = this.buildApiDict('setSwitch');
1727
- body.payload.data = {
1728
- oscillationSwitch: toggle ? 1 : 0
1729
- };
1730
- const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1731
- return this.checkResponse([response, status], 'setOscillation');
1732
- }
1733
1739
  /**
1734
1740
  * Turn oscillation on
1735
1741
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsvesync",
3
- "version": "1.0.47",
3
+ "version": "1.0.49",
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",
package/src/lib/vesync.ts CHANGED
@@ -12,17 +12,6 @@ import { logger, setLogger, Logger } from './logger';
12
12
 
13
13
  const DEFAULT_ENERGY_UPDATE_INTERVAL = 21600;
14
14
 
15
- // Device constructor type for concrete device classes only
16
- type DeviceConstructor = new (config: Record<string, any>, manager: VeSync) => VeSyncBaseDevice;
17
-
18
- // Module dictionary type
19
- interface DeviceModules {
20
- [key: string]: DeviceConstructor;
21
- }
22
-
23
- // Device categories
24
- type DeviceCategory = 'fans' | 'outlets' | 'switches' | 'bulbs';
25
-
26
15
  /**
27
16
  * Device exclusion configuration
28
17
  */
@@ -34,6 +23,17 @@ export interface ExcludeConfig {
34
23
  id?: string[];
35
24
  }
36
25
 
26
+ // Device constructor type for concrete device classes only
27
+ type DeviceConstructor = new (config: Record<string, any>, manager: VeSync) => VeSyncBaseDevice;
28
+
29
+ // Module dictionary type
30
+ interface DeviceModules {
31
+ [key: string]: DeviceConstructor;
32
+ }
33
+
34
+ // Device categories
35
+ type DeviceCategory = 'fans' | 'outlets' | 'switches' | 'bulbs';
36
+
37
37
  /**
38
38
  * Create device instance based on type
39
39
  */
@@ -366,58 +366,6 @@ export class VeSync {
366
366
  return devices;
367
367
  }
368
368
 
369
- /**
370
- * Check if a device should be excluded based on configuration
371
- */
372
- private shouldExcludeDevice(device: Record<string, any>): boolean {
373
- if (!this._excludeConfig) {
374
- return false;
375
- }
376
-
377
- const exclude = this._excludeConfig;
378
-
379
- // Check device type
380
- if (exclude.type?.includes(device.deviceType.toLowerCase())) {
381
- logger.debug(`Excluding device ${device.deviceName} by type: ${device.deviceType}`);
382
- return true;
383
- }
384
-
385
- // Check device model
386
- if (exclude.model?.some(model => device.deviceType.toUpperCase().includes(model.toUpperCase()))) {
387
- logger.debug(`Excluding device ${device.deviceName} by model: ${device.deviceType}`);
388
- return true;
389
- }
390
-
391
- // Check exact name match
392
- if (exclude.name?.includes(device.deviceName.trim())) {
393
- logger.debug(`Excluding device ${device.deviceName} by exact name match`);
394
- return true;
395
- }
396
-
397
- // Check name patterns
398
- if (exclude.namePattern) {
399
- for (const pattern of exclude.namePattern) {
400
- try {
401
- const regex = new RegExp(pattern);
402
- if (regex.test(device.deviceName.trim())) {
403
- logger.debug(`Excluding device ${device.deviceName} by name pattern: ${pattern}`);
404
- return true;
405
- }
406
- } catch (error) {
407
- logger.warn(`Invalid regex pattern in exclude config: ${pattern}`);
408
- }
409
- }
410
- }
411
-
412
- // Check device ID (cid or uuid)
413
- if (exclude.id?.includes(device.cid) || exclude.id?.includes(device.uuid)) {
414
- logger.debug(`Excluding device ${device.deviceName} by ID: ${device.cid}/${device.uuid}`);
415
- return true;
416
- }
417
-
418
- return false;
419
- }
420
-
421
369
  /**
422
370
  * Process devices from API response
423
371
  */
@@ -435,11 +383,6 @@ export class VeSync {
435
383
 
436
384
  // Process each device
437
385
  deviceList.forEach(dev => {
438
- // Check if device should be excluded
439
- if (this.shouldExcludeDevice(dev)) {
440
- return;
441
- }
442
-
443
386
  const [category, device] = objectFactory(dev, this);
444
387
  // Handle outdoor plug sub-devices
445
388
  if (dev.deviceType === 'ESO15-TB' && dev.subDeviceNo) {
@@ -450,12 +393,9 @@ export class VeSync {
450
393
  subDeviceNo: dev.subDeviceNo,
451
394
  isSubDevice: true,
452
395
  };
453
- // Check if sub-device should be excluded
454
- if (!this.shouldExcludeDevice(subDeviceDetails)) {
455
- const [subCategory, subDevice] = objectFactory(subDeviceDetails, this);
456
- if (subDevice && subCategory in this._devList) {
457
- this._devList[subCategory].push(subDevice);
458
- }
396
+ const [subCategory, subDevice] = objectFactory(subDeviceDetails, this);
397
+ if (subDevice && subCategory in this._devList) {
398
+ this._devList[subCategory].push(subDevice);
459
399
  }
460
400
  } else if (device && category in this._devList) {
461
401
  this._devList[category].push(device);
@@ -622,6 +562,58 @@ export class VeSync {
622
562
  );
623
563
  }
624
564
 
565
+ /**
566
+ * Check if a device should be excluded based on configuration
567
+ */
568
+ private shouldExcludeDevice(device: VeSyncBaseDevice): boolean {
569
+ if (!this._excludeConfig) {
570
+ return false;
571
+ }
572
+
573
+ const exclude = this._excludeConfig;
574
+
575
+ // Check device type
576
+ if (exclude.type?.includes(device.deviceType.toLowerCase())) {
577
+ logger.debug(`Excluding device ${device.deviceName} by type: ${device.deviceType}`);
578
+ return true;
579
+ }
580
+
581
+ // Check device model
582
+ if (exclude.model?.some(model => device.deviceType.toUpperCase().includes(model.toUpperCase()))) {
583
+ logger.debug(`Excluding device ${device.deviceName} by model: ${device.deviceType}`);
584
+ return true;
585
+ }
586
+
587
+ // Check exact name match
588
+ if (exclude.name?.includes(device.deviceName.trim())) {
589
+ logger.debug(`Excluding device ${device.deviceName} by exact name match`);
590
+ return true;
591
+ }
592
+
593
+ // Check name patterns
594
+ if (exclude.namePattern) {
595
+ for (const pattern of exclude.namePattern) {
596
+ try {
597
+ const regex = new RegExp(pattern);
598
+ if (regex.test(device.deviceName.trim())) {
599
+ logger.debug(`Excluding device ${device.deviceName} by name pattern: ${pattern}`);
600
+ return true;
601
+ }
602
+ } catch (error) {
603
+ logger.warn(`Invalid regex pattern in exclude config: ${pattern}`);
604
+ }
605
+ }
606
+ }
607
+
608
+ // Check device ID (cid or uuid)
609
+ if (exclude.id?.includes(device.cid) || exclude.id?.includes(device.uuid)) {
610
+ logger.debug(`Excluding device ${device.deviceName} by ID: ${device.cid}/${device.uuid}`);
611
+ return true;
612
+ }
613
+
614
+ return false;
615
+ }
616
+
625
617
  /**
626
618
  * Update device list and details
627
619
  */
@@ -638,7 +630,11 @@ export class VeSync {
638
630
  for (const deviceList of Object.values(this._devList)) {
639
631
  for (const device of deviceList) {
640
632
  try {
641
- await device.getDetails();
633
+ if (!this.shouldExcludeDevice(device)) {
634
+ await device.getDetails();
635
+ } else {
636
+ logger.debug(`Skipping details update for excluded device: ${device.deviceName}`);
637
+ }
642
638
  } catch (error) {
643
639
  logger.error(`Error updating ${device.deviceName}:`, error);
644
640
  }
@@ -1786,6 +1786,33 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
1786
1786
 
1787
1787
  return JSON.stringify(details, null, 4);
1788
1788
  }
1789
+
1790
+ /**
1791
+ * Set oscillation state
1792
+ */
1793
+ async setOscillation(toggle: boolean): Promise<boolean> {
1794
+ logger.debug(`Setting oscillation to ${toggle ? 'on' : 'off'} for device: ${this.deviceName}`);
1795
+
1796
+ const [head, body] = this.buildApiDict('setSwitch');
1797
+ body.payload.data = {
1798
+ oscillationSwitch: toggle ? 1 : 0,
1799
+ switchIdx: 0
1800
+ };
1801
+
1802
+ const [response, status] = await this.callApi(
1803
+ '/cloud/v2/deviceManaged/bypassV2',
1804
+ 'post',
1805
+ body,
1806
+ head
1807
+ );
1808
+
1809
+ const success = this.checkResponse([response, status], 'setOscillation');
1810
+ if (success) {
1811
+ this.details.oscillationState = toggle;
1812
+ this.details.oscillationSwitch = toggle ? 1 : 0;
1813
+ }
1814
+ return success;
1815
+ }
1789
1816
  }
1790
1817
 
1791
1818
  /**
@@ -2112,27 +2139,6 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
2112
2139
  return this.details.errorCode || 0;
2113
2140
  }
2114
2141
 
2115
- /**
2116
- * Set oscillation state
2117
- */
2118
- async setOscillation(toggle: boolean): Promise<boolean> {
2119
- logger.debug(`Setting oscillation to ${toggle ? 'on' : 'off'} for device: ${this.deviceName}`);
2120
-
2121
- const [head, body] = this.buildApiDict('setSwitch');
2122
- body.payload.data = {
2123
- oscillationSwitch: toggle ? 1 : 0
2124
- };
2125
-
2126
- const [response, status] = await this.callApi(
2127
- '/cloud/v2/deviceManaged/bypassV2',
2128
- 'post',
2129
- body,
2130
- head
2131
- );
2132
-
2133
- return this.checkResponse([response, status], 'setOscillation');
2134
- }
2135
-
2136
2142
  /**
2137
2143
  * Turn oscillation on
2138
2144
  */