@switchbot/homebridge-switchbot 3.5.0-beta.3 → 3.5.0-beta.30

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 (166) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/config.schema.json +147 -9
  3. package/dist/device/blindtilt.d.ts +21 -94
  4. package/dist/device/blindtilt.d.ts.map +1 -1
  5. package/dist/device/blindtilt.js +347 -756
  6. package/dist/device/blindtilt.js.map +1 -1
  7. package/dist/device/bot.d.ts +25 -71
  8. package/dist/device/bot.d.ts.map +1 -1
  9. package/dist/device/bot.js +582 -759
  10. package/dist/device/bot.js.map +1 -1
  11. package/dist/device/ceilinglight.d.ts +13 -67
  12. package/dist/device/ceilinglight.d.ts.map +1 -1
  13. package/dist/device/ceilinglight.js +209 -587
  14. package/dist/device/ceilinglight.js.map +1 -1
  15. package/dist/device/colorbulb.d.ts +13 -74
  16. package/dist/device/colorbulb.d.ts.map +1 -1
  17. package/dist/device/colorbulb.js +250 -632
  18. package/dist/device/colorbulb.js.map +1 -1
  19. package/dist/device/contact.d.ts +14 -65
  20. package/dist/device/contact.d.ts.map +1 -1
  21. package/dist/device/contact.js +204 -531
  22. package/dist/device/contact.js.map +1 -1
  23. package/dist/device/curtain.d.ts +17 -86
  24. package/dist/device/curtain.d.ts.map +1 -1
  25. package/dist/device/curtain.js +335 -786
  26. package/dist/device/curtain.js.map +1 -1
  27. package/dist/device/device.d.ts +59 -0
  28. package/dist/device/device.d.ts.map +1 -0
  29. package/dist/device/device.js +646 -0
  30. package/dist/device/device.js.map +1 -0
  31. package/dist/device/fan.d.ts +51 -0
  32. package/dist/device/fan.d.ts.map +1 -0
  33. package/dist/device/fan.js +499 -0
  34. package/dist/device/fan.js.map +1 -0
  35. package/dist/device/hub.d.ts +15 -59
  36. package/dist/device/hub.d.ts.map +1 -1
  37. package/dist/device/hub.js +242 -596
  38. package/dist/device/hub.js.map +1 -1
  39. package/dist/device/humidifier.d.ts +10 -65
  40. package/dist/device/humidifier.d.ts.map +1 -1
  41. package/dist/device/humidifier.js +207 -571
  42. package/dist/device/humidifier.js.map +1 -1
  43. package/dist/device/iosensor.d.ts +11 -64
  44. package/dist/device/iosensor.d.ts.map +1 -1
  45. package/dist/device/iosensor.js +174 -584
  46. package/dist/device/iosensor.js.map +1 -1
  47. package/dist/device/lightstrip.d.ts +10 -68
  48. package/dist/device/lightstrip.d.ts.map +1 -1
  49. package/dist/device/lightstrip.js +252 -568
  50. package/dist/device/lightstrip.js.map +1 -1
  51. package/dist/device/lock.d.ts +15 -62
  52. package/dist/device/lock.d.ts.map +1 -1
  53. package/dist/device/lock.js +210 -542
  54. package/dist/device/lock.js.map +1 -1
  55. package/dist/device/meter.d.ts +13 -63
  56. package/dist/device/meter.d.ts.map +1 -1
  57. package/dist/device/meter.js +170 -577
  58. package/dist/device/meter.js.map +1 -1
  59. package/dist/device/meterplus.d.ts +13 -64
  60. package/dist/device/meterplus.d.ts.map +1 -1
  61. package/dist/device/meterplus.js +159 -577
  62. package/dist/device/meterplus.js.map +1 -1
  63. package/dist/device/motion.d.ts +13 -69
  64. package/dist/device/motion.d.ts.map +1 -1
  65. package/dist/device/motion.js +136 -518
  66. package/dist/device/motion.js.map +1 -1
  67. package/dist/device/plug.d.ts +9 -57
  68. package/dist/device/plug.d.ts.map +1 -1
  69. package/dist/device/plug.js +82 -452
  70. package/dist/device/plug.js.map +1 -1
  71. package/dist/device/robotvacuumcleaner.d.ts +11 -62
  72. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  73. package/dist/device/robotvacuumcleaner.js +140 -451
  74. package/dist/device/robotvacuumcleaner.js.map +1 -1
  75. package/dist/device/waterdetector.d.ts +9 -70
  76. package/dist/device/waterdetector.d.ts.map +1 -1
  77. package/dist/device/waterdetector.js +121 -664
  78. package/dist/device/waterdetector.js.map +1 -1
  79. package/dist/index.js +1 -1
  80. package/dist/irdevice/airconditioner.d.ts +8 -48
  81. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  82. package/dist/irdevice/airconditioner.js +309 -419
  83. package/dist/irdevice/airconditioner.js.map +1 -1
  84. package/dist/irdevice/airpurifier.d.ts +7 -38
  85. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  86. package/dist/irdevice/airpurifier.js +72 -304
  87. package/dist/irdevice/airpurifier.js.map +1 -1
  88. package/dist/irdevice/camera.d.ts +6 -35
  89. package/dist/irdevice/camera.d.ts.map +1 -1
  90. package/dist/irdevice/camera.js +34 -278
  91. package/dist/irdevice/camera.js.map +1 -1
  92. package/dist/irdevice/fan.d.ts +6 -39
  93. package/dist/irdevice/fan.d.ts.map +1 -1
  94. package/dist/irdevice/fan.js +67 -311
  95. package/dist/irdevice/fan.js.map +1 -1
  96. package/dist/irdevice/irdevice.d.ts +40 -0
  97. package/dist/irdevice/irdevice.d.ts.map +1 -0
  98. package/dist/irdevice/irdevice.js +509 -0
  99. package/dist/irdevice/irdevice.js.map +1 -0
  100. package/dist/irdevice/light.d.ts +6 -34
  101. package/dist/irdevice/light.d.ts.map +1 -1
  102. package/dist/irdevice/light.js +23 -272
  103. package/dist/irdevice/light.js.map +1 -1
  104. package/dist/irdevice/other.d.ts +18 -47
  105. package/dist/irdevice/other.d.ts.map +1 -1
  106. package/dist/irdevice/other.js +352 -546
  107. package/dist/irdevice/other.js.map +1 -1
  108. package/dist/irdevice/tv.d.ts +7 -39
  109. package/dist/irdevice/tv.d.ts.map +1 -1
  110. package/dist/irdevice/tv.js +82 -321
  111. package/dist/irdevice/tv.js.map +1 -1
  112. package/dist/irdevice/vacuumcleaner.d.ts +6 -35
  113. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  114. package/dist/irdevice/vacuumcleaner.js +41 -284
  115. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  116. package/dist/irdevice/waterheater.d.ts +6 -35
  117. package/dist/irdevice/waterheater.d.ts.map +1 -1
  118. package/dist/irdevice/waterheater.js +42 -287
  119. package/dist/irdevice/waterheater.js.map +1 -1
  120. package/dist/platform.d.ts +14 -1
  121. package/dist/platform.d.ts.map +1 -1
  122. package/dist/platform.js +237 -94
  123. package/dist/platform.js.map +1 -1
  124. package/dist/settings.d.ts +40 -10
  125. package/dist/settings.d.ts.map +1 -1
  126. package/dist/settings.js +0 -552
  127. package/dist/settings.js.map +1 -1
  128. package/dist/utils.d.ts +77 -0
  129. package/dist/utils.d.ts.map +1 -1
  130. package/dist/utils.js +638 -1
  131. package/dist/utils.js.map +1 -1
  132. package/package.json +16 -15
  133. package/src/custom.d.ts +2 -1
  134. package/src/device/blindtilt.ts +373 -782
  135. package/src/device/bot.ts +616 -844
  136. package/src/device/ceilinglight.ts +222 -607
  137. package/src/device/colorbulb.ts +264 -656
  138. package/src/device/contact.ts +229 -553
  139. package/src/device/curtain.ts +355 -810
  140. package/src/device/device.ts +673 -0
  141. package/src/device/fan.ts +548 -0
  142. package/src/device/hub.ts +268 -623
  143. package/src/device/humidifier.ts +237 -618
  144. package/src/device/iosensor.ts +200 -610
  145. package/src/device/lightstrip.ts +273 -596
  146. package/src/device/lock.ts +247 -582
  147. package/src/device/meter.ts +196 -601
  148. package/src/device/meterplus.ts +184 -602
  149. package/src/device/motion.ts +156 -541
  150. package/src/device/plug.ts +92 -480
  151. package/src/device/robotvacuumcleaner.ts +161 -477
  152. package/src/device/waterdetector.ts +139 -689
  153. package/src/index.ts +1 -1
  154. package/src/irdevice/airconditioner.ts +330 -446
  155. package/src/irdevice/airpurifier.ts +89 -321
  156. package/src/irdevice/camera.ts +42 -293
  157. package/src/irdevice/fan.ts +78 -327
  158. package/src/irdevice/irdevice.ts +526 -0
  159. package/src/irdevice/light.ts +32 -287
  160. package/src/irdevice/other.ts +396 -615
  161. package/src/irdevice/tv.ts +100 -339
  162. package/src/irdevice/vacuumcleaner.ts +49 -305
  163. package/src/irdevice/waterheater.ts +50 -310
  164. package/src/platform.ts +247 -102
  165. package/src/settings.ts +56 -565
  166. package/src/utils.ts +642 -1
package/src/platform.ts CHANGED
@@ -1,4 +1,4 @@
1
- /* Copyright(C) 2017-2023, donavanbecker (https://github.com/donavanbecker). All rights reserved.
1
+ /* Copyright(C) 2017-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
2
  *
3
3
  * platform.ts: @switchbot/homebridge-switchbot platform class.
4
4
  */
@@ -20,8 +20,9 @@ import { CeilingLight } from './device/ceilinglight.js';
20
20
  import { StripLight } from './device/lightstrip.js';
21
21
  import { Humidifier } from './device/humidifier.js';
22
22
  import { RobotVacuumCleaner } from './device/robotvacuumcleaner.js';
23
+ import { Fan } from './device/fan.js';
23
24
  import { TV } from './irdevice/tv.js';
24
- import { Fan } from './irdevice/fan.js';
25
+ import { IRFan } from './irdevice/fan.js';
25
26
  import { Light } from './irdevice/light.js';
26
27
  import { Others } from './irdevice/other.js';
27
28
  import { Camera } from './irdevice/camera.js';
@@ -32,16 +33,16 @@ import { VacuumCleaner } from './irdevice/vacuumcleaner.js';
32
33
  import { AirConditioner } from './irdevice/airconditioner.js';
33
34
  import * as http from 'http';
34
35
  import { Buffer } from 'buffer';
35
- import { request } from 'undici';
36
+ import { Dispatcher, request } from 'undici';
36
37
  import { MqttClient } from 'mqtt';
37
38
  import { queueScheduler } from 'rxjs';
38
39
  import fakegato from 'fakegato-history';
39
40
  import asyncmqtt from 'async-mqtt';
40
41
  import crypto, { randomUUID } from 'crypto';
41
42
  import { readFileSync, writeFileSync } from 'fs';
42
- import hbLib from 'homebridge-lib';
43
-
44
-
43
+ import { EveHomeKitTypes } from 'homebridge-lib/EveHomeKitTypes';
44
+ import { UrlObject } from 'url';
45
+ import { sleep } from './utils.js';
45
46
 
46
47
  /**
47
48
  * HomebridgePlatform
@@ -56,6 +57,8 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
56
57
  version!: string;
57
58
  Logging?: string;
58
59
  debugMode!: boolean;
60
+ maxRetries!: number;
61
+ delayBetweenRetries!: number;
59
62
  platformConfig!: SwitchBotPlatformConfig['options'];
60
63
  platformLogging!: SwitchBotPlatformConfig['logging'];
61
64
  config!: SwitchBotPlatformConfig;
@@ -104,7 +107,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
104
107
  }
105
108
 
106
109
  // import fakegato-history module and EVE characteristics
107
- const { EveHomeKitTypes } = hbLib;
108
110
  this.fakegatoAPI = fakegato(api);
109
111
  this.eve = new EveHomeKitTypes(api);
110
112
 
@@ -383,6 +385,21 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
383
385
  this.debugWarnLog('Using Default Push Rate.');
384
386
  }
385
387
 
388
+ if (!this.config.options.maxRetries) {
389
+ this.config.options.maxRetries = 5;
390
+ this.debugWarnLog('Using Default Max Retries.');
391
+ } else {
392
+ this.maxRetries = this.config.options.maxRetries;
393
+ }
394
+
395
+ if (!this.config.options.delayBetweenRetries) {
396
+ // default 3 seconds
397
+ this.config.options!.delayBetweenRetries! = 3000;
398
+ this.debugWarnLog('Using Default Delay Between Retries.');
399
+ } else {
400
+ this.delayBetweenRetries = this.config.options.delayBetweenRetries * 1000;
401
+ }
402
+
386
403
  if (!this.config.credentials && !this.config.options) {
387
404
  this.debugWarnLog('Missing Credentials');
388
405
  } else if (this.config.credentials && !this.config.credentials.notice) {
@@ -492,44 +509,98 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
492
509
  */
493
510
  async discoverDevices() {
494
511
  if (this.config.credentials?.token) {
495
- try {
496
- const { body, statusCode } = await request(Devices, {
497
- headers: this.generateHeaders(),
498
- });
499
- this.debugWarnLog(`statusCode: ${statusCode}`);
500
- const devicesAPI: any = await body.json();
501
- this.debugWarnLog(`devicesAPI: ${JSON.stringify(devicesAPI)}`);
502
- this.debugWarnLog(`devicesAPI Body: ${JSON.stringify(devicesAPI.body)}`);
503
- this.debugWarnLog(`devicesAPI StatusCode: ${devicesAPI.statusCode}`);
504
- if ((statusCode === 200 || statusCode === 100) && (devicesAPI.statusCode === 200 || devicesAPI.statusCode === 100)) {
505
- this.debugErrorLog(`statusCode: ${statusCode} & devicesAPI StatusCode: ${devicesAPI.statusCode}`);
506
- // SwitchBot Devices
507
- const deviceLists = devicesAPI.body.deviceList;
508
- this.debugWarnLog(`DeviceLists: ${JSON.stringify(deviceLists)}`);
509
- this.debugWarnLog(`DeviceLists Length: ${deviceLists.length}`);
510
- if (!this.config.options?.devices) {
511
- this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`);
512
- if (deviceLists.length === 0) {
513
- this.debugLog(`SwitchBot API Currently Doesn't Have Any Devices With Cloud Services Enabled: ${JSON.stringify(devicesAPI.body)}`);
514
- } else {
515
- const devices = deviceLists.map((v: any) => v);
516
- for (const device of devices) {
517
- if (device.deviceType) {
518
- if (device.configDeviceName) {
519
- device.deviceName = device.configDeviceName;
512
+ let retryCount = 0;
513
+ const maxRetries = this.maxRetries; // Maximum number of retries
514
+ const delayBetweenRetries = this.delayBetweenRetries; // Delay between retries in milliseconds
515
+ this.debugWarnLog(`Retry Count: ${retryCount}`);
516
+ this.debugWarnLog(`Max Retries: ${maxRetries}`);
517
+ this.debugWarnLog(`Delay Between Retries: ${delayBetweenRetries}`);
518
+ while (retryCount < maxRetries) {
519
+ try {
520
+ const { body, statusCode } = await request(Devices, {
521
+ headers: this.generateHeaders(),
522
+ });
523
+ this.debugWarnLog(`statusCode: ${statusCode}`);
524
+ const devicesAPI: any = await body.json();
525
+ this.debugWarnLog(`devicesAPI: ${JSON.stringify(devicesAPI)}`);
526
+ this.debugWarnLog(`devicesAPI Body: ${JSON.stringify(devicesAPI.body)}`);
527
+ this.debugWarnLog(`devicesAPI StatusCode: ${devicesAPI.statusCode}`);
528
+ if ((statusCode === 200 || statusCode === 100) && (devicesAPI.statusCode === 200 || devicesAPI.statusCode === 100)) {
529
+ this.debugErrorLog(`statusCode: ${statusCode} & devicesAPI StatusCode: ${devicesAPI.statusCode}`);
530
+ // SwitchBot Devices
531
+ const deviceLists = devicesAPI.body.deviceList;
532
+ this.debugWarnLog(`DeviceLists: ${JSON.stringify(deviceLists)}`);
533
+ this.debugWarnLog(`DeviceLists Length: ${deviceLists.length}`);
534
+ if (!this.config.options?.devices) {
535
+ this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`);
536
+ if (deviceLists.length === 0) {
537
+ this.debugLog(`SwitchBot API Currently Doesn't Have Any Devices With Cloud Services Enabled: ${JSON.stringify(devicesAPI.body)}`);
538
+ } else {
539
+ const devices = deviceLists.map((v: any) => v);
540
+ for (const device of devices) {
541
+ if (device.deviceType) {
542
+ if (device.configDeviceName) {
543
+ device.deviceName = device.configDeviceName;
544
+ }
545
+ this.createDevice(device);
520
546
  }
521
- this.createDevice(device);
522
547
  }
523
548
  }
549
+ } else if (this.config.credentials?.token && this.config.options.devices) {
550
+ this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`);
551
+ if (deviceLists.length === 0) {
552
+ this.debugLog(`SwitchBot API Currently Doesn't Have Any Devices With Cloud Services Enabled: ${JSON.stringify(devicesAPI.body)}`);
553
+ } else {
554
+ const deviceConfigs = this.config.options?.devices;
555
+
556
+ const mergeBydeviceId = (a1: { deviceId: string }[], a2: any[]) =>
557
+ a1.map((itm: { deviceId: string }) => ({
558
+ ...a2.find(
559
+ (item: { deviceId: string }) =>
560
+ item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item,
561
+ ),
562
+ ...itm,
563
+ }));
564
+
565
+ const devices = mergeBydeviceId(deviceLists, deviceConfigs);
566
+ this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`);
567
+ for (const device of devices) {
568
+ if (!device.deviceType) {
569
+ device.deviceType = device.configDeviceType;
570
+ this.errorLog(`API has displaying no deviceType: ${device.deviceType}, So using configDeviceType: ${device.configDeviceType}`);
571
+ }
572
+ if (device.deviceType) {
573
+ if (device.configDeviceName) {
574
+ device.deviceName = device.configDeviceName;
575
+ }
576
+ this.createDevice(device);
577
+ }
578
+ }
579
+ }
580
+ } else {
581
+ this.errorLog('SwitchBot Token Supplied, Issue with Auth.');
524
582
  }
525
- } else if (this.config.credentials?.token && this.config.options.devices) {
526
- this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`);
527
- if (deviceLists.length === 0) {
528
- this.debugLog(`SwitchBot API Currently Doesn't Have Any Devices With Cloud Services Enabled: ${JSON.stringify(devicesAPI.body)}`);
583
+ if (devicesAPI.body.deviceList.length !== 0) {
584
+ this.infoLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
529
585
  } else {
530
- const deviceConfigs = this.config.options?.devices;
586
+ this.debugLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
587
+ }
531
588
 
532
- const mergeBydeviceId = (a1: { deviceId: string }[], a2: any[]) =>
589
+ // IR Devices
590
+ const irDeviceLists = devicesAPI.body.infraredRemoteList;
591
+ if (!this.config.options?.irdevices) {
592
+ this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`);
593
+ const devices = irDeviceLists.map((v: any) => v);
594
+ for (const device of devices) {
595
+ if (device.remoteType) {
596
+ this.createIRDevice(device);
597
+ }
598
+ }
599
+ } else {
600
+ this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`);
601
+ const irDeviceConfig = this.config.options?.irdevices;
602
+
603
+ const mergeIRBydeviceId = (a1: { deviceId: string }[], a2: any[]) =>
533
604
  a1.map((itm: { deviceId: string }) => ({
534
605
  ...a2.find(
535
606
  (item: { deviceId: string }) =>
@@ -538,73 +609,34 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
538
609
  ...itm,
539
610
  }));
540
611
 
541
- const devices = mergeBydeviceId(deviceLists, deviceConfigs);
542
- this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`);
612
+ const devices = mergeIRBydeviceId(irDeviceLists, irDeviceConfig);
613
+ this.debugLog(`IR Devices: ${JSON.stringify(devices)}`);
543
614
  for (const device of devices) {
544
- if (!device.deviceType) {
545
- device.deviceType = device.configDeviceType;
546
- this.errorLog(`API has displaying no deviceType: ${device.deviceType}, So using configDeviceType: ${device.configDeviceType}`);
547
- }
548
- if (device.deviceType) {
549
- if (device.configDeviceName) {
550
- device.deviceName = device.configDeviceName;
551
- }
552
- this.createDevice(device);
553
- }
554
- }
555
- }
556
- } else {
557
- this.errorLog('SwitchBot Token Supplied, Issue with Auth.');
558
- }
559
- if (devicesAPI.body.deviceList.length !== 0) {
560
- this.infoLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
561
- } else {
562
- this.debugLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
563
- }
564
-
565
- // IR Devices
566
- const irDeviceLists = devicesAPI.body.infraredRemoteList;
567
- if (!this.config.options?.irdevices) {
568
- this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`);
569
- const devices = irDeviceLists.map((v: any) => v);
570
- for (const device of devices) {
571
- if (device.remoteType) {
572
615
  this.createIRDevice(device);
573
616
  }
574
617
  }
575
- } else {
576
- this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`);
577
- const irDeviceConfig = this.config.options?.irdevices;
578
-
579
- const mergeIRBydeviceId = (a1: { deviceId: string }[], a2: any[]) =>
580
- a1.map((itm: { deviceId: string }) => ({
581
- ...a2.find(
582
- (item: { deviceId: string }) =>
583
- item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item,
584
- ),
585
- ...itm,
586
- }));
587
-
588
- const devices = mergeIRBydeviceId(irDeviceLists, irDeviceConfig);
589
- this.debugLog(`IR Devices: ${JSON.stringify(devices)}`);
590
- for (const device of devices) {
591
- this.createIRDevice(device);
618
+ if (devicesAPI.body.infraredRemoteList.length !== 0) {
619
+ this.infoLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
620
+ } else {
621
+ this.debugLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
592
622
  }
593
- }
594
- if (devicesAPI.body.infraredRemoteList.length !== 0) {
595
- this.infoLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
623
+ break;
596
624
  } else {
597
- this.debugLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
625
+ this.statusCode(statusCode);
626
+ this.statusCode(devicesAPI.statusCode);
627
+ if (statusCode === 500) {
628
+ retryCount++;
629
+ this.infoLog(`statusCode: ${statusCode} Attempt ${retryCount} of ${maxRetries}`);
630
+ await sleep(delayBetweenRetries);
631
+ }
598
632
  }
599
- } else {
600
- this.statusCode(statusCode);
601
- this.statusCode(devicesAPI.statusCode);
633
+ } catch (e: any) {
634
+ retryCount++;
635
+ this.debugErrorLog(
636
+ `Failed to Discover Devices, Error Message: ${JSON.stringify(e.message)}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug',
637
+ );
638
+ this.debugErrorLog(`Failed to Discover Devices, Error: ${e}`);
602
639
  }
603
- } catch (e: any) {
604
- this.debugErrorLog(
605
- `Failed to Discover Devices, Error Message: ${JSON.stringify(e.message)}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug',
606
- );
607
- this.debugErrorLog(`Failed to Discover Devices, Error: ${e}`);
608
640
  }
609
641
  } else if (!this.config.credentials?.token && this.config.options?.devices) {
610
642
  this.debugLog(`SwitchBot Device Manual Config Set: ${JSON.stringify(this.config.options?.devices)}`);
@@ -691,10 +723,12 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
691
723
  this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
692
724
  this.createColorBulb(device);
693
725
  break;
726
+ case 'K10+':
694
727
  case 'WoSweeper':
695
728
  case 'WoSweeperMini':
696
729
  case 'Robot Vacuum Cleaner S1':
697
730
  case 'Robot Vacuum Cleaner S1 Plus':
731
+ case 'Robot Vacuum Cleaner S10':
698
732
  this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
699
733
  this.createRobotVacuumCleaner(device);
700
734
  break;
@@ -712,8 +746,13 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
712
746
  this.warnLog(`Device: ${device.deviceName} with Device Type: ${device.deviceType}, is currently not supported.`);
713
747
  break;
714
748
  case 'Remote':
749
+ case 'remote with screen+':
715
750
  this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId} is Not Supported.`);
716
751
  break;
752
+ case 'Battery Circulator Fan':
753
+ this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
754
+ this.createFan(device);
755
+ break;
717
756
  default:
718
757
  this.warnLog(`Device: ${device.deviceName} with Device Type: ${device.deviceType}, is currently not supported.`);
719
758
  // eslint-disable-next-line max-len
@@ -749,7 +788,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
749
788
  case 'Fan':
750
789
  case 'DIY Fan':
751
790
  this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
752
- this.createFan(device);
791
+ this.createIRFan(device);
753
792
  break;
754
793
  case 'Air Conditioner':
755
794
  case 'DIY Air Conditioner':
@@ -1781,6 +1820,66 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
1781
1820
  }
1782
1821
  }
1783
1822
 
1823
+ private async createFan(device: device & devicesConfig) {
1824
+ const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1825
+
1826
+ // see if an accessory with the same uuid has already been registered and restored from
1827
+ // the cached devices we stored in the `configureAccessory` method above
1828
+ const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1829
+
1830
+ if (existingAccessory) {
1831
+ // the accessory already exists
1832
+ if (await this.registerDevice(device)) {
1833
+ // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
1834
+ existingAccessory.context.model = device.deviceType;
1835
+ existingAccessory.context.deviceID = device.deviceId;
1836
+ existingAccessory.displayName = device.configDeviceName || device.deviceName;
1837
+ if (device.firmware) {
1838
+ existingAccessory.context.FirmwareRevision = device.firmware;
1839
+ }
1840
+ existingAccessory.context.deviceType = `SwitchBot: ${device.deviceType}`;
1841
+ this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName} DeviceID: ${device.deviceId}`);
1842
+ existingAccessory.context.connectionType = await this.connectionType(device);
1843
+ this.api.updatePlatformAccessories([existingAccessory]);
1844
+ // create the accessory handler for the restored accessory
1845
+ // this is imported from `platformAccessory.ts`
1846
+ new Fan(this, existingAccessory, device);
1847
+ this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${existingAccessory.UUID})`);
1848
+ } else {
1849
+ this.unregisterPlatformAccessories(existingAccessory);
1850
+ }
1851
+ } else if (await this.registerDevice(device)) {
1852
+ // the accessory does not yet exist, so we need to create it
1853
+ if (!device.external) {
1854
+ this.infoLog(`Adding new accessory: ${device.deviceName} ${device.deviceType} DeviceID: ${device.deviceId}`);
1855
+ }
1856
+
1857
+ // create a new accessory
1858
+ const accessory = new this.api.platformAccessory(device.deviceName, uuid);
1859
+
1860
+ // store a copy of the device object in the `accessory.context`
1861
+ // the `context` property can be used to store any data about the accessory you may need
1862
+ accessory.context.device = device;
1863
+ accessory.context.model = device.deviceType;
1864
+ accessory.context.deviceID = device.deviceId;
1865
+ if (device.firmware) {
1866
+ accessory.context.FirmwareRevision = device.firmware;
1867
+ }
1868
+ accessory.context.deviceType = `SwitchBot: ${device.deviceType}`;
1869
+ accessory.context.connectionType = await this.connectionType(device);
1870
+ // create the accessory handler for the newly create accessory
1871
+ // this is imported from `platformAccessory.ts`
1872
+ new Fan(this, accessory, device);
1873
+ this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${accessory.UUID})`);
1874
+
1875
+ // publish device externally or link the accessory to your platform
1876
+ this.externalOrPlatform(device, accessory);
1877
+ this.accessories.push(accessory);
1878
+ } else {
1879
+ this.debugLog(`Device not registered: ${device.deviceName} ${device.deviceType} DeviceID: ${device.deviceId}`);
1880
+ }
1881
+ }
1882
+
1784
1883
  private async createRobotVacuumCleaner(device: device & devicesConfig) {
1785
1884
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1786
1885
 
@@ -1893,7 +1992,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
1893
1992
  }
1894
1993
  }
1895
1994
 
1896
- private async createFan(device: irdevice & devicesConfig) {
1995
+ private async createIRFan(device: irdevice & devicesConfig) {
1897
1996
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
1898
1997
 
1899
1998
  // see if an accessory with the same uuid has already been registered and restored from
@@ -1916,7 +2015,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
1916
2015
  this.api.updatePlatformAccessories([existingAccessory]);
1917
2016
  // create the accessory handler for the restored accessory
1918
2017
  // this is imported from `platformAccessory.ts`
1919
- new Fan(this, existingAccessory, device);
2018
+ new IRFan(this, existingAccessory, device);
1920
2019
  this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${existingAccessory.UUID})`);
1921
2020
  } else {
1922
2021
  this.unregisterPlatformAccessories(existingAccessory);
@@ -1942,7 +2041,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
1942
2041
  accessory.context.connectionType = device.connectionType;
1943
2042
  // create the accessory handler for the newly create accessory
1944
2043
  // this is imported from `platformAccessory.ts`
1945
- new Fan(this, accessory, device);
2044
+ new IRFan(this, accessory, device);
1946
2045
  this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
1947
2046
 
1948
2047
  // publish device externally or link the accessory to your platform
@@ -2626,6 +2725,30 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2626
2725
  }
2627
2726
  }
2628
2727
 
2728
+ async retryRequest(deviceMaxRetries: number, deviceDelayBetweenRetries: number, url: string | URL | UrlObject,
2729
+ options?: { dispatcher?: Dispatcher } & Omit<Dispatcher.RequestOptions,
2730
+ 'origin' | 'path' | 'method'> & Partial<Pick<Dispatcher.RequestOptions, 'method'>>): Promise<{ body: any; statusCode: number }> {
2731
+ let retryCount = 0;
2732
+ const maxRetries = deviceMaxRetries;
2733
+ const delayBetweenRetries = deviceDelayBetweenRetries;
2734
+ while (retryCount < maxRetries) {
2735
+ try {
2736
+ const { body, statusCode } = await request(url, options);
2737
+ if (statusCode === 200 || statusCode === 100) {
2738
+ return { body, statusCode };
2739
+ } else {
2740
+ this.debugLog(`Received status code: ${statusCode}`);
2741
+ }
2742
+ } catch (error: any) {
2743
+ this.errorLog(`Error making request: ${error.message}`);
2744
+ }
2745
+ retryCount++;
2746
+ this.debugLog(`Retry attempt ${retryCount} of ${maxRetries}`);
2747
+ await sleep(delayBetweenRetries);
2748
+ }
2749
+ return { body: null, statusCode: -1 };
2750
+ }
2751
+
2629
2752
  // BLE Connection
2630
2753
  async connectBLE() {
2631
2754
  let switchbot: any;
@@ -2662,6 +2785,22 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2662
2785
  if (this.config.options.pushRate) {
2663
2786
  platformConfig.pushRate = this.config.options.pushRate;
2664
2787
  }
2788
+ if (this.config.options.maxRetries) {
2789
+ this.maxRetries = this.config.options.maxRetries;
2790
+ platformConfig.maxRetries = this.config.options.maxRetries;
2791
+ } else {
2792
+ this.maxRetries = 3;
2793
+ this.debugWarnLog('Using Default Max Retries');
2794
+ platformConfig.maxRetries = this.maxRetries;
2795
+ }
2796
+ if (this.config.options.delayBetweenRetries) {
2797
+ this.delayBetweenRetries = this.config.options.delayBetweenRetries * 1000;
2798
+ platformConfig.delayBetweenRetries = this.config.options.delayBetweenRetries;
2799
+ } else {
2800
+ this.delayBetweenRetries = 3000;
2801
+ this.debugWarnLog('Using Default Delay Between Retries');
2802
+ platformConfig.delayBetweenRetries = this.delayBetweenRetries / 1000;
2803
+ }
2665
2804
  if (Object.entries(platformConfig).length !== 0) {
2666
2805
  this.debugLog(`Platform Config: ${JSON.stringify(platformConfig)}`);
2667
2806
  }
@@ -2687,6 +2826,12 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2687
2826
  * If device level logging is turned on, log to log.warn
2688
2827
  * Otherwise send debug logs to log.debug
2689
2828
  */
2829
+ successLog(...log: any[]): void {
2830
+ if (this.enablingPlatformLogging()) {
2831
+ this.log.success(String(...log));
2832
+ }
2833
+ }
2834
+
2690
2835
  infoLog(...log: any[]): void {
2691
2836
  if (this.enablingPlatformLogging()) {
2692
2837
  this.log.info(String(...log));