@switchbot/homebridge-switchbot 3.5.0-beta.6 → 3.5.0-beta.60

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 (177) hide show
  1. package/.vscode/settings.json +4 -1
  2. package/CHANGELOG.md +4 -1
  3. package/config.schema.json +120 -17
  4. package/dist/device/blindtilt.d.ts +23 -96
  5. package/dist/device/blindtilt.d.ts.map +1 -1
  6. package/dist/device/blindtilt.js +408 -779
  7. package/dist/device/blindtilt.js.map +1 -1
  8. package/dist/device/bot.d.ts +26 -72
  9. package/dist/device/bot.d.ts.map +1 -1
  10. package/dist/device/bot.js +696 -822
  11. package/dist/device/bot.js.map +1 -1
  12. package/dist/device/ceilinglight.d.ts +14 -68
  13. package/dist/device/ceilinglight.d.ts.map +1 -1
  14. package/dist/device/ceilinglight.js +237 -606
  15. package/dist/device/ceilinglight.js.map +1 -1
  16. package/dist/device/colorbulb.d.ts +14 -75
  17. package/dist/device/colorbulb.d.ts.map +1 -1
  18. package/dist/device/colorbulb.js +279 -658
  19. package/dist/device/colorbulb.js.map +1 -1
  20. package/dist/device/contact.d.ts +15 -66
  21. package/dist/device/contact.d.ts.map +1 -1
  22. package/dist/device/contact.js +242 -544
  23. package/dist/device/contact.js.map +1 -1
  24. package/dist/device/curtain.d.ts +19 -88
  25. package/dist/device/curtain.d.ts.map +1 -1
  26. package/dist/device/curtain.js +402 -805
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/device.d.ts +59 -0
  29. package/dist/device/device.d.ts.map +1 -0
  30. package/dist/device/device.js +684 -0
  31. package/dist/device/device.js.map +1 -0
  32. package/dist/device/fan.d.ts +51 -0
  33. package/dist/device/fan.d.ts.map +1 -0
  34. package/dist/device/fan.js +535 -0
  35. package/dist/device/fan.js.map +1 -0
  36. package/dist/device/hub.d.ts +16 -60
  37. package/dist/device/hub.d.ts.map +1 -1
  38. package/dist/device/hub.js +246 -613
  39. package/dist/device/hub.js.map +1 -1
  40. package/dist/device/humidifier.d.ts +11 -66
  41. package/dist/device/humidifier.d.ts.map +1 -1
  42. package/dist/device/humidifier.js +232 -593
  43. package/dist/device/humidifier.js.map +1 -1
  44. package/dist/device/iosensor.d.ts +11 -64
  45. package/dist/device/iosensor.d.ts.map +1 -1
  46. package/dist/device/iosensor.js +185 -600
  47. package/dist/device/iosensor.js.map +1 -1
  48. package/dist/device/lightstrip.d.ts +11 -69
  49. package/dist/device/lightstrip.d.ts.map +1 -1
  50. package/dist/device/lightstrip.js +277 -586
  51. package/dist/device/lightstrip.js.map +1 -1
  52. package/dist/device/lock.d.ts +16 -63
  53. package/dist/device/lock.d.ts.map +1 -1
  54. package/dist/device/lock.js +241 -560
  55. package/dist/device/lock.js.map +1 -1
  56. package/dist/device/meter.d.ts +14 -64
  57. package/dist/device/meter.d.ts.map +1 -1
  58. package/dist/device/meter.js +181 -593
  59. package/dist/device/meter.js.map +1 -1
  60. package/dist/device/meterplus.d.ts +14 -65
  61. package/dist/device/meterplus.d.ts.map +1 -1
  62. package/dist/device/meterplus.js +170 -593
  63. package/dist/device/meterplus.js.map +1 -1
  64. package/dist/device/motion.d.ts +13 -69
  65. package/dist/device/motion.d.ts.map +1 -1
  66. package/dist/device/motion.js +178 -531
  67. package/dist/device/motion.js.map +1 -1
  68. package/dist/device/plug.d.ts +9 -57
  69. package/dist/device/plug.d.ts.map +1 -1
  70. package/dist/device/plug.js +92 -458
  71. package/dist/device/plug.js.map +1 -1
  72. package/dist/device/robotvacuumcleaner.d.ts +12 -63
  73. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  74. package/dist/device/robotvacuumcleaner.js +197 -521
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +10 -65
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +139 -495
  79. package/dist/device/waterdetector.js.map +1 -1
  80. package/dist/homebridge-ui/public/index.html +22 -16
  81. package/dist/homebridge-ui/server.js +1 -1
  82. package/dist/homebridge-ui/server.js.map +1 -1
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +2 -2
  86. package/dist/index.js.map +1 -1
  87. package/dist/irdevice/airconditioner.d.ts +9 -49
  88. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  89. package/dist/irdevice/airconditioner.js +309 -419
  90. package/dist/irdevice/airconditioner.js.map +1 -1
  91. package/dist/irdevice/airpurifier.d.ts +8 -39
  92. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  93. package/dist/irdevice/airpurifier.js +72 -304
  94. package/dist/irdevice/airpurifier.js.map +1 -1
  95. package/dist/irdevice/camera.d.ts +7 -36
  96. package/dist/irdevice/camera.d.ts.map +1 -1
  97. package/dist/irdevice/camera.js +34 -278
  98. package/dist/irdevice/camera.js.map +1 -1
  99. package/dist/irdevice/fan.d.ts +10 -43
  100. package/dist/irdevice/fan.d.ts.map +1 -1
  101. package/dist/irdevice/fan.js +100 -338
  102. package/dist/irdevice/fan.js.map +1 -1
  103. package/dist/irdevice/irdevice.d.ts +40 -0
  104. package/dist/irdevice/irdevice.d.ts.map +1 -0
  105. package/dist/irdevice/irdevice.js +330 -0
  106. package/dist/irdevice/irdevice.js.map +1 -0
  107. package/dist/irdevice/light.d.ts +12 -45
  108. package/dist/irdevice/light.d.ts.map +1 -1
  109. package/dist/irdevice/light.js +87 -357
  110. package/dist/irdevice/light.js.map +1 -1
  111. package/dist/irdevice/other.d.ts +19 -48
  112. package/dist/irdevice/other.d.ts.map +1 -1
  113. package/dist/irdevice/other.js +352 -546
  114. package/dist/irdevice/other.js.map +1 -1
  115. package/dist/irdevice/tv.d.ts +8 -40
  116. package/dist/irdevice/tv.d.ts.map +1 -1
  117. package/dist/irdevice/tv.js +82 -321
  118. package/dist/irdevice/tv.js.map +1 -1
  119. package/dist/irdevice/vacuumcleaner.d.ts +7 -36
  120. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  121. package/dist/irdevice/vacuumcleaner.js +41 -284
  122. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  123. package/dist/irdevice/waterheater.d.ts +7 -36
  124. package/dist/irdevice/waterheater.d.ts.map +1 -1
  125. package/dist/irdevice/waterheater.js +42 -287
  126. package/dist/irdevice/waterheater.js.map +1 -1
  127. package/dist/platform.d.ts +19 -6
  128. package/dist/platform.d.ts.map +1 -1
  129. package/dist/platform.js +310 -169
  130. package/dist/platform.js.map +1 -1
  131. package/dist/settings.d.ts +62 -19
  132. package/dist/settings.d.ts.map +1 -1
  133. package/dist/settings.js +16 -552
  134. package/dist/settings.js.map +1 -1
  135. package/dist/utils.d.ts +77 -0
  136. package/dist/utils.d.ts.map +1 -1
  137. package/dist/utils.js +638 -1
  138. package/dist/utils.js.map +1 -1
  139. package/eslint.config.js +96 -0
  140. package/package.json +19 -15
  141. package/src/custom.d.ts +2 -1
  142. package/src/device/blindtilt.ts +442 -814
  143. package/src/device/bot.ts +754 -915
  144. package/src/device/ceilinglight.ts +255 -633
  145. package/src/device/colorbulb.ts +294 -685
  146. package/src/device/contact.ts +277 -571
  147. package/src/device/curtain.ts +431 -835
  148. package/src/device/device.ts +709 -0
  149. package/src/device/fan.ts +591 -0
  150. package/src/device/hub.ts +286 -644
  151. package/src/device/humidifier.ts +266 -646
  152. package/src/device/iosensor.ts +220 -625
  153. package/src/device/lightstrip.ts +305 -620
  154. package/src/device/lock.ts +280 -600
  155. package/src/device/meter.ts +216 -617
  156. package/src/device/meterplus.ts +205 -619
  157. package/src/device/motion.ts +206 -556
  158. package/src/device/plug.ts +107 -490
  159. package/src/device/robotvacuumcleaner.ts +223 -550
  160. package/src/device/waterdetector.ts +160 -519
  161. package/src/homebridge-ui/public/index.html +22 -16
  162. package/src/homebridge-ui/server.ts +1 -1
  163. package/src/index.ts +4 -3
  164. package/src/irdevice/airconditioner.ts +333 -447
  165. package/src/irdevice/airpurifier.ts +92 -322
  166. package/src/irdevice/camera.ts +45 -294
  167. package/src/irdevice/fan.ts +115 -353
  168. package/src/irdevice/irdevice.ts +346 -0
  169. package/src/irdevice/light.ts +110 -385
  170. package/src/irdevice/other.ts +399 -616
  171. package/src/irdevice/tv.ts +103 -340
  172. package/src/irdevice/vacuumcleaner.ts +52 -306
  173. package/src/irdevice/waterheater.ts +53 -311
  174. package/src/platform.ts +355 -216
  175. package/src/settings.ts +116 -611
  176. package/src/utils.ts +642 -1
  177. package/src/device/waterdetector.json +0 -11
@@ -1,103 +1,67 @@
1
+ /* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
+ *
3
+ * robotvacuumcleaner.ts: @switchbot/homebridge-switchbot.
4
+ */
1
5
  import { request } from 'undici';
2
- import { sleep } from '../utils.js';
3
- import { interval, Subject } from 'rxjs';
4
- import { SwitchBotPlatform } from '../platform.js';
5
- import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
6
- import { Service, PlatformAccessory, CharacteristicValue, API, Logging, HAP } from 'homebridge';
7
- import { device, devicesConfig, deviceStatus, serviceData, Devices, SwitchBotPlatformConfig } from '../settings.js';
8
-
9
- export class RobotVacuumCleaner {
10
- public readonly api: API;
11
- public readonly log: Logging;
12
- public readonly config!: SwitchBotPlatformConfig;
13
- protected readonly hap: HAP;
14
- // Services
15
- batteryService: Service;
16
- robotVacuumCleanerService: Service;
17
-
18
- // Characteristic Values
19
- On!: CharacteristicValue;
20
- Brightness!: CharacteristicValue;
21
- BatteryLevel!: CharacteristicValue;
22
- StatusLowBattery!: CharacteristicValue;
23
- FirmwareRevision!: CharacteristicValue;
24
-
25
- // OpenAPI Status
26
- OpenAPI_On: deviceStatus['power'];
27
- OpenAPI_BatteryLevel: deviceStatus['battery'];
28
- OpenAPI_FirmwareRevision: deviceStatus['version'];
6
+ import { Devices } from '../settings.js';
7
+ import { deviceBase } from './device.js';
8
+ import { Subject, interval, skipWhile } from 'rxjs';
9
+ import { debounceTime, take, tap } from 'rxjs/operators';
29
10
 
30
- // BLE Status
31
- BLE_On: serviceData['state'];
11
+ import type { SwitchBotPlatform } from '../platform.js';
12
+ import type { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
13
+ import type { device, devicesConfig, deviceStatus, serviceData } from '../settings.js';
32
14
 
33
- // BLE Others
34
- BLE_IsConnected?: boolean;
35
-
36
- // Config
37
- scanDuration!: number;
38
- deviceLogging!: string;
39
- deviceRefreshRate!: number;
15
+ export class RobotVacuumCleaner extends deviceBase {
16
+ // Services
17
+ private LightBulb: {
18
+ Name: CharacteristicValue;
19
+ Service: Service;
20
+ On: CharacteristicValue;
21
+ Brightness: CharacteristicValue;
22
+ };
23
+
24
+ private Battery: {
25
+ Name: CharacteristicValue;
26
+ Service: Service;
27
+ BatteryLevel: CharacteristicValue;
28
+ StatusLowBattery: CharacteristicValue;
29
+ ChargingState: CharacteristicValue;
30
+ };
40
31
 
41
32
  // Updates
42
33
  robotVacuumCleanerUpdateInProgress!: boolean;
43
34
  doRobotVacuumCleanerUpdate!: Subject<void>;
44
35
 
45
- // Connection
46
- private readonly OpenAPI: boolean;
47
- private readonly BLE: boolean;
48
-
49
36
  constructor(
50
- private readonly platform: SwitchBotPlatform,
51
- private accessory: PlatformAccessory,
52
- public device: device & devicesConfig,
37
+ readonly platform: SwitchBotPlatform,
38
+ accessory: PlatformAccessory,
39
+ device: device & devicesConfig,
53
40
  ) {
54
- this.api = this.platform.api;
55
- this.log = this.platform.log;
56
- this.config = this.platform.config;
57
- this.hap = this.api.hap;
58
- // Connection
59
- this.BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI';
60
- this.OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI';
61
- // default placeholders
62
- this.deviceLogs(device);
63
- this.scan(device);
64
- this.refreshRate(device);
65
- this.deviceContext();
66
- this.deviceConfig(device);
67
-
41
+ super(platform, accessory, device);
68
42
  // this is subject we use to track when we need to POST changes to the SwitchBot API
69
43
  this.doRobotVacuumCleanerUpdate = new Subject();
70
44
  this.robotVacuumCleanerUpdateInProgress = false;
71
45
 
72
- // Retrieve initial values and updateHomekit
73
- this.refreshStatus();
74
-
75
- // set accessory information
76
- accessory
77
- .getService(this.hap.Service.AccessoryInformation)!
78
- .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
79
- .setCharacteristic(this.hap.Characteristic.Model, this.model(device))
80
- .setCharacteristic(this.hap.Characteristic.SerialNumber, device.deviceId)
81
- .setCharacteristic(this.hap.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision);
82
-
83
- // get the Lightbulb service if it exists, otherwise create a new Lightbulb service
84
- // you can create multiple services for each accessory
85
- const robotVacuumCleanerService = `${accessory.displayName} ${device.deviceType}`;
86
- (this.robotVacuumCleanerService = accessory.getService(this.hap.Service.Lightbulb)
87
- || accessory.addService(this.hap.Service.Lightbulb)), robotVacuumCleanerService;
88
-
89
- this.robotVacuumCleanerService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
90
- if (!this.robotVacuumCleanerService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
91
- this.robotVacuumCleanerService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
92
- }
93
- // each service must implement at-minimum the "required characteristics" for the given service type
94
- // see https://developers.homebridge.io/#/service/Lightbulb
95
-
96
- // create handlers for required characteristics
97
- this.robotVacuumCleanerService.getCharacteristic(this.hap.Characteristic.On).onSet(this.OnSet.bind(this));
46
+ // Initialize Lightbulb Service
47
+ this.LightBulb = {
48
+ Name: accessory.context.LightBulbName ?? accessory.displayName,
49
+ Service: accessory.getService(this.hap.Service.Lightbulb) ?? accessory.addService(this.hap.Service.Lightbulb) as Service,
50
+ On: accessory.context.On ?? false,
51
+ Brightness: accessory.context.Brightness ?? 0,
52
+ };
53
+
54
+ // Initialize LightBulb Characteristics
55
+ this.LightBulb.Service
56
+ .setCharacteristic(this.hap.Characteristic.Name, accessory.displayName)
57
+ .getCharacteristic(this.hap.Characteristic.On)
58
+ .onGet(() => {
59
+ return this.LightBulb.On;
60
+ })
61
+ .onSet(this.OnSet.bind(this));
98
62
 
99
- // handle Brightness events using the Brightness characteristic
100
- this.robotVacuumCleanerService
63
+ // Initialize LightBulb Brightness Characteristic
64
+ this.LightBulb.Service
101
65
  .getCharacteristic(this.hap.Characteristic.Brightness)
102
66
  .setProps({
103
67
  minStep: 25,
@@ -107,20 +71,43 @@ export class RobotVacuumCleaner {
107
71
  validValueRanges: [0, 100],
108
72
  })
109
73
  .onGet(() => {
110
- return this.Brightness;
74
+ return this.LightBulb.Brightness;
111
75
  })
112
76
  .onSet(this.BrightnessSet.bind(this));
77
+ accessory.context.LightBulbName = this.LightBulb.Name;
78
+
79
+ // Initialize Battery Service
80
+ this.Battery = {
81
+ Name: accessory.context.BatteryName ?? `${accessory.displayName} Battery`,
82
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
83
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
84
+ StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
85
+ ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGING,
86
+ };
87
+
88
+ // Initialize Battery Characteristics
89
+ this.Battery.Service
90
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
91
+ .getCharacteristic(this.hap.Characteristic.BatteryLevel)
92
+ .onGet(() => {
93
+ return this.Battery.BatteryLevel;
94
+ });
113
95
 
114
- // Battery Service
115
- const batteryService = `${accessory.displayName} Battery`;
116
- (this.batteryService = this.accessory.getService(this.hap.Service.Battery)
117
- || accessory.addService(this.hap.Service.Battery)), batteryService;
96
+ this.Battery.Service
97
+ .getCharacteristic(this.hap.Characteristic.StatusLowBattery)
98
+ .onGet(() => {
99
+ return this.Battery.StatusLowBattery;
100
+ });
118
101
 
119
- this.batteryService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Battery`);
120
- if (!this.batteryService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
121
- this.batteryService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Battery`);
122
- }
102
+ this.Battery.Service
103
+ .getCharacteristic(this.hap.Characteristic.ChargingState)
104
+ .onGet(() => {
105
+ return this.Battery.ChargingState;
106
+ });
107
+ accessory.context.BatteryName = this.Battery.Name;
123
108
 
109
+ // Retrieve initial values and updateHomekit
110
+ this.refreshStatus();
124
111
  // Update Homekit
125
112
  this.updateHomeKitCharacteristics();
126
113
 
@@ -132,19 +119,22 @@ export class RobotVacuumCleaner {
132
119
  });
133
120
 
134
121
  //regisiter webhook event handler
135
- if (this.device.webhook) {
136
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
122
+ if (device.webhook) {
123
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
137
124
  this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
138
125
  try {
139
126
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
140
- const { onlineStatus, battery } = context;
141
- const { On, BatteryLevel } = this;
127
+ const { onlineStatus, battery, workingStatus } = context;
128
+ const { On } = this.LightBulb;
129
+ const { BatteryLevel, ChargingState } = this.Battery;
142
130
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
143
- '(onlineStatus, battery) = ' +
144
- `Webhook:(${onlineStatus}, ${battery}), ` +
145
- `current:(${On}, ${BatteryLevel})`);
146
- this.On = onlineStatus === 'online' ? true : false;
147
- this.BatteryLevel = battery;
131
+ '(onlineStatus, battery, workingStatus) = ' +
132
+ `Webhook:(${onlineStatus}, ${battery}, ${workingStatus}), ` +
133
+ `current:(${On}, ${BatteryLevel}, ${ChargingState})`);
134
+ this.LightBulb.On = onlineStatus === 'online' ? true : false;
135
+ this.Battery.ChargingState = workingStatus === 'Charging'
136
+ ? this.hap.Characteristic.ChargingState.CHARGING : this.hap.Characteristic.ChargingState.NOT_CHARGING;
137
+ this.Battery.BatteryLevel = battery;
148
138
  this.updateHomeKitCharacteristics();
149
139
  } catch (e: any) {
150
140
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
@@ -164,10 +154,10 @@ export class RobotVacuumCleaner {
164
154
  )
165
155
  .subscribe(async () => {
166
156
  try {
167
- if (this.On !== this.accessory.context.On) {
157
+ if (this.LightBulb.On !== this.accessory.context.On) {
168
158
  await this.pushChanges();
169
159
  }
170
- if (this.On && this.Brightness !== this.accessory.context.Brightness) {
160
+ if (this.LightBulb.On && this.LightBulb.Brightness !== this.accessory.context.Brightness) {
171
161
  await this.openAPIpushBrightnessChanges();
172
162
  }
173
163
  } catch (e: any) {
@@ -181,60 +171,69 @@ export class RobotVacuumCleaner {
181
171
  });
182
172
  }
183
173
 
184
- /**
185
- * Parse the device status from the SwitchBot api
186
- */
187
- async parseStatus(): Promise<void> {
188
- if (!this.device.enableCloudService && this.OpenAPI) {
189
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`);
190
- /*} else if (this.BLE) {
191
- await this.BLEparseStatus();*/
192
- } else if (this.OpenAPI && this.platform.config.credentials?.token) {
193
- await this.openAPIparseStatus();
174
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
175
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
176
+
177
+ // Battery
178
+ this.Battery.BatteryLevel = Number(serviceData.battery);
179
+ if (this.Battery.BatteryLevel < 10) {
180
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
194
181
  } else {
195
- await this.offlineOff();
196
- this.debugWarnLog(
197
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`,
198
- );
182
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
199
183
  }
200
- }
184
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}, StatusLowBattery: ${this.Battery.StatusLowBattery}`);
201
185
 
202
- async BLEparseStatus(): Promise<void> {
203
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
204
186
  // State
205
- switch (this.BLE_On) {
187
+ switch (serviceData.state) {
206
188
  case 'on':
207
- this.On = true;
189
+ this.LightBulb.On = true;
208
190
  break;
209
191
  default:
210
- this.On = false;
192
+ this.LightBulb.On = false;
211
193
  }
212
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
194
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
213
195
  }
214
196
 
215
- async openAPIparseStatus() {
197
+ async openAPIparseStatus(deviceStatus: deviceStatus) {
216
198
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
217
- switch (this.OpenAPI_On) {
199
+ switch (deviceStatus.body.power) {
218
200
  case 'on':
219
- this.On = true;
201
+ this.LightBulb.On = true;
220
202
  break;
221
203
  default:
222
- this.On = false;
204
+ this.LightBulb.On = false;
223
205
  }
224
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
206
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
225
207
 
226
- // Battery
227
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
228
- if (this.BatteryLevel < 15) {
229
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
208
+ // BatteryLevel
209
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
210
+
211
+ // StatusLowBattery
212
+ if (this.Battery.BatteryLevel < 10) {
213
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
230
214
  } else {
231
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
215
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
216
+ }
217
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
218
+ this.Battery.BatteryLevel = 100;
232
219
  }
233
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
220
+ // ChargingState
221
+ this.Battery.ChargingState = deviceStatus.body.workingStatus === 'Charging'
222
+ ? this.hap.Characteristic.ChargingState.CHARGING : this.hap.Characteristic.ChargingState.NOT_CHARGING;
223
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
224
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}, ChargingState: ${this.Battery.ChargingState}`);
234
225
 
235
- // FirmwareRevision
236
- this.FirmwareRevision = this.OpenAPI_FirmwareRevision!;
237
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
226
+ // Firmware Version
227
+ const version = deviceStatus.body.version?.toString();
228
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
229
+ if (deviceStatus.body.version) {
230
+ this.accessory.context.version = version?.replace(/^V|-.*$/g, '');
231
+ this.accessory
232
+ .getService(this.hap.Service.AccessoryInformation)!
233
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, this.accessory.context.version)
234
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
235
+ .updateValue(this.accessory.context.version);
236
+ }
238
237
  }
239
238
 
240
239
  /**
@@ -243,8 +242,8 @@ export class RobotVacuumCleaner {
243
242
  async refreshStatus(): Promise<void> {
244
243
  if (!this.device.enableCloudService && this.OpenAPI) {
245
244
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus enableCloudService: ${this.device.enableCloudService}`);
246
- /*} else if (this.BLE) {
247
- await this.BLERefreshStatus();*/
245
+ } else if (this.BLE) {
246
+ await this.BLERefreshStatus();
248
247
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
249
248
  await this.openAPIRefreshStatus();
250
249
  } else {
@@ -268,96 +267,44 @@ export class RobotVacuumCleaner {
268
267
  this.getCustomBLEAddress(switchbot);
269
268
  // Start to monitor advertisement packets
270
269
  (async () => {
271
- await switchbot.startScan({
272
- model: '?',
273
- id: this.device.bleMac,
274
- });
270
+ // Start to monitor advertisement packets
271
+ await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
275
272
  // Set an event handler
276
273
  switchbot.onadvertisement = (ad: any) => {
277
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
278
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.serviceData.model}`);
279
- if (this.device.bleMac === ad.address && ad.serviceData.model === '?') {
274
+ if (this.device.bleMac === ad.address && ad.model === this.device.bleModel) {
275
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
276
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
280
277
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
281
- this.BLE_On = ad.serviceData.state;
282
278
  } else {
283
279
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
284
280
  }
285
281
  };
286
- // Wait 1 seconds
282
+ // Wait 10 seconds
287
283
  await switchbot.wait(this.scanDuration * 1000);
288
284
  // Stop to monitor
289
285
  await switchbot.stopScan();
290
286
  // Update HomeKit
291
- await this.BLEparseStatus();
287
+ await this.BLEparseStatus(switchbot.onadvertisement.serviceData);
292
288
  await this.updateHomeKitCharacteristics();
293
289
  })();
294
- /*if (switchbot !== false) {
295
- switchbot
296
- .startScan({
297
- model: this.BLEmodel(),
298
- id: this.device.bleMac,
299
- })
300
- .then(async () => {
301
- // Set an event handler
302
- switchbot.onadvertisement = async (ad: ad) => {
303
- this.debugLog(
304
- `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` +
305
- ` BLE Address Found: ${ad.address}`,
306
- );
307
- this.BLE_On = ad.serviceData.state;
308
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
309
- this.debugLog(
310
- `${this.device.deviceType}: ${this.accessory.displayName} state: ${ad.serviceData.state}, ` +
311
- `delay: ${ad.serviceData.delay}, timer: ${ad.serviceData.timer}, syncUtcTime: ${ad.serviceData.syncUtcTime} ` +
312
- `wifiRssi: ${ad.serviceData.wifiRssi}, overload: ${ad.serviceData.overload}, currentPower: ${ad.serviceData.currentPower}`,
313
- );
314
-
315
- if (ad.serviceData) {
316
- this.BLE_IsConnected = true;
317
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
318
- await this.stopScanning(switchbot);
319
- } else {
320
- this.BLE_IsConnected = false;
321
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
322
- }
323
- };
324
- // Wait
325
- return await sleep(this.scanDuration * 1000);
326
- })
327
- .then(async () => {
328
- // Stop to monitor
329
- await this.stopScanning(switchbot);
330
- })
331
- .catch(async (e: any) => {
332
- this.apiError(e);
333
- this.errorLog(
334
- `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` +
335
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
336
- );
337
- await this.BLERefreshConnection(switchbot);
338
- });
339
- } else {
290
+ if (switchbot === undefined) {
340
291
  await this.BLERefreshConnection(switchbot);
341
- }*/
292
+ }
342
293
  }
343
294
 
344
- async openAPIRefreshStatus() {
295
+ async openAPIRefreshStatus(): Promise<void> {
345
296
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
346
297
  try {
347
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
348
- headers: this.platform.generateHeaders(),
349
- });
298
+ const { body, statusCode } = await this.platform.retryRequest(this.deviceMaxRetries, this.deviceDelayBetweenRetries,
299
+ `${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders() });
350
300
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
351
301
  const deviceStatus: any = await body.json();
352
302
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
353
303
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
354
304
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
355
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
305
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
356
306
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
357
- this.OpenAPI_On = deviceStatus.body.power;
358
- this.OpenAPI_BatteryLevel = deviceStatus.body.battery;
359
- this.OpenAPI_FirmwareRevision = deviceStatus.body.version;
360
- this.openAPIparseStatus();
307
+ this.openAPIparseStatus(deviceStatus);
361
308
  this.updateHomeKitCharacteristics();
362
309
  } else {
363
310
  this.statusCode(statusCode);
@@ -405,8 +352,9 @@ export class RobotVacuumCleaner {
405
352
 
406
353
  async BLEpushChanges(): Promise<void> {
407
354
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
408
- if (this.On !== this.accessory.context.On) {
409
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
355
+ if (this.LightBulb.On !== this.accessory.context.On) {
356
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`
357
+ + ` On: ${this.LightBulb.On} OnCached: ${this.accessory.context.On}`);
410
358
  const switchbot = await this.platform.connectBLE();
411
359
  // Convert to BLE Address
412
360
  this.device.bleMac = this.device
@@ -420,11 +368,11 @@ export class RobotVacuumCleaner {
420
368
  id: this.device.bleMac,
421
369
  })
422
370
  .then(async (device_list: any) => {
423
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
424
- return await this.retry({
425
- max: this.maxRetry(),
371
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
372
+ return await this.retryBLE({
373
+ max: await this.maxRetryBLE(),
426
374
  fn: async () => {
427
- if (this.On) {
375
+ if (this.LightBulb.On) {
428
376
  return await device_list[0].turnOn({ id: this.device.bleMac });
429
377
  } else {
430
378
  return await device_list[0].turnOff({ id: this.device.bleMac });
@@ -434,7 +382,9 @@ export class RobotVacuumCleaner {
434
382
  })
435
383
  .then(() => {
436
384
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
437
- this.On = false;
385
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
386
+ + `On: ${this.LightBulb.On} sent over BLE, sent successfully`);
387
+ this.LightBulb.On = false;
438
388
  })
439
389
  .catch(async (e: any) => {
440
390
  this.apiError(e);
@@ -445,26 +395,15 @@ export class RobotVacuumCleaner {
445
395
  await this.BLEPushConnection();
446
396
  });
447
397
  } else {
448
- this.debugLog(
449
- `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`,
450
- );
398
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges,`
399
+ + ` On: ${this.LightBulb.On}, OnCached: ${this.accessory.context.On}`);
451
400
  }
452
401
  }
453
402
 
454
403
  async openAPIpushChanges() {
455
404
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
456
- if (this.On !== this.accessory.context.On) {
457
- let command = '';
458
- if (this.On) {
459
- command = 'turnOn';
460
- } else {
461
- command = 'turnOff';
462
- }
463
- const bodyChange = JSON.stringify({
464
- command: `${command}`,
465
- parameter: 'default',
466
- commandType: 'command',
467
- });
405
+ if (this.LightBulb.On !== this.accessory.context.On) {
406
+ const bodyChange = await this.commands();
468
407
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
469
408
  try {
470
409
  const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
@@ -480,6 +419,8 @@ export class RobotVacuumCleaner {
480
419
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
481
420
  this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
482
421
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
422
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
423
+ + `request to SwitchBot API, body: ${JSON.stringify(bodyChange)} sent successfully`);
483
424
  } else {
484
425
  this.statusCode(statusCode);
485
426
  this.statusCode(deviceStatus.statusCode);
@@ -494,7 +435,7 @@ export class RobotVacuumCleaner {
494
435
  } else {
495
436
  this.debugLog(
496
437
  `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` +
497
- `On: ${this.On}, ` +
438
+ `On: ${this.LightBulb.On}, ` +
498
439
  `OnCached: ${this.accessory.context.On}`,
499
440
  );
500
441
  }
@@ -502,10 +443,11 @@ export class RobotVacuumCleaner {
502
443
 
503
444
  async openAPIpushBrightnessChanges() {
504
445
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushBrightnessChanges`);
505
- const body = await this.brightnessCommands();
506
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
446
+ const bodyChange = await this.brightnessCommands();
447
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
507
448
  try {
508
449
  const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
450
+ body: bodyChange,
509
451
  method: 'POST',
510
452
  headers: this.platform.generateHeaders(),
511
453
  });
@@ -514,8 +456,10 @@ export class RobotVacuumCleaner {
514
456
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
515
457
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
516
458
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
517
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
459
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
518
460
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
461
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
462
+ + `request to SwitchBot API, body: ${JSON.stringify(deviceStatus)} sent successfully`);
519
463
  } else {
520
464
  this.statusCode(statusCode);
521
465
  this.statusCode(deviceStatus.statusCode);
@@ -529,10 +473,10 @@ export class RobotVacuumCleaner {
529
473
  }
530
474
  }
531
475
 
532
- private commands() {
476
+ async commands() {
533
477
  let command: string;
534
478
  let parameter: string;
535
- if (this.On) {
479
+ if (this.LightBulb.On) {
536
480
  command = 'start';
537
481
  parameter = 'default';
538
482
  } else {
@@ -547,44 +491,44 @@ export class RobotVacuumCleaner {
547
491
  return body;
548
492
  }
549
493
 
550
- private brightnessCommands() {
494
+ async brightnessCommands(): Promise<string> {
551
495
  let command: string;
552
496
  let parameter: string;
553
- if (this.Brightness === 25) {
497
+ if (this.LightBulb.Brightness === 25) {
554
498
  command = 'PowLevel';
555
499
  parameter = '0';
556
- } else if (this.Brightness === 50) {
500
+ } else if (this.LightBulb.Brightness === 50) {
557
501
  command = 'PowLevel';
558
502
  parameter = '1';
559
- } else if (this.Brightness === 75) {
503
+ } else if (this.LightBulb.Brightness === 75) {
560
504
  command = 'PowLevel';
561
505
  parameter = '2';
562
- } else if (this.Brightness === 100) {
506
+ } else if (this.LightBulb.Brightness === 100) {
563
507
  command = 'PowLevel';
564
508
  parameter = '3';
565
509
  } else {
566
510
  command = 'dock';
567
511
  parameter = 'default';
568
512
  }
569
- const body = JSON.stringify({
513
+ const bodyChange = JSON.stringify({
570
514
  command: `${command}`,
571
515
  parameter: `${parameter}`,
572
516
  commandType: 'command',
573
517
  });
574
- return body;
518
+ return bodyChange;
575
519
  }
576
520
 
577
521
  /**
578
522
  * Handle requests to set the value of the "On" characteristic
579
523
  */
580
524
  async OnSet(value: CharacteristicValue): Promise<void> {
581
- if (this.On === this.accessory.context.On) {
525
+ if (this.LightBulb.On === this.accessory.context.On) {
582
526
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set On: ${value}`);
583
527
  } else {
584
528
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
585
529
  }
586
530
 
587
- this.On = value;
531
+ this.LightBulb.On = value;
588
532
  this.doRobotVacuumCleanerUpdate.next();
589
533
  }
590
534
 
@@ -592,78 +536,60 @@ export class RobotVacuumCleaner {
592
536
  * Handle requests to set the value of the "Brightness" characteristic
593
537
  */
594
538
  async BrightnessSet(value: CharacteristicValue): Promise<void> {
595
- if (this.Brightness === this.accessory.context.Brightness) {
539
+ if (this.LightBulb.Brightness === this.accessory.context.Brightness) {
596
540
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set Brightness: ${value}`);
597
- } else if (this.On) {
541
+ } else if (this.LightBulb.On) {
598
542
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Brightness: ${value}`);
599
543
  } else {
600
544
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Brightness: ${value}`);
601
545
  }
602
546
 
603
- this.Brightness = value;
547
+ this.LightBulb.Brightness = value;
604
548
  this.doRobotVacuumCleanerUpdate.next();
605
549
  }
606
550
 
607
551
  async updateHomeKitCharacteristics(): Promise<void> {
608
552
  // On
609
- if (this.On === undefined) {
610
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
553
+ if (this.LightBulb.On === undefined) {
554
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
611
555
  } else {
612
- this.accessory.context.On = this.On;
613
- this.robotVacuumCleanerService.updateCharacteristic(this.hap.Characteristic.On, this.On);
614
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
556
+ this.accessory.context.On = this.LightBulb.On;
557
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.On, this.LightBulb.On);
558
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.LightBulb.On}`);
615
559
  }
616
560
  // Brightness
617
- if (this.Brightness === undefined) {
618
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
561
+ if (this.LightBulb.Brightness === undefined) {
562
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.LightBulb.Brightness}`);
619
563
  } else {
620
- this.accessory.context.Brightness = this.Brightness;
621
- this.robotVacuumCleanerService.updateCharacteristic(this.hap.Characteristic.Brightness, this.Brightness);
622
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Brightness: ${this.Brightness}`);
564
+ this.accessory.context.Brightness = this.LightBulb.Brightness;
565
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.Brightness, this.LightBulb.Brightness);
566
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Brightness: ${this.LightBulb.Brightness}`);
623
567
  }
624
568
  // BatteryLevel
625
- if (this.BatteryLevel === undefined) {
626
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
569
+ if (this.Battery.BatteryLevel === undefined) {
570
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
627
571
  } else {
628
- this.accessory.context.BatteryLevel = this.BatteryLevel;
629
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.BatteryLevel);
630
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
572
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
573
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
574
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
631
575
  }
632
576
  // StatusLowBattery
633
- if (this.StatusLowBattery === undefined) {
634
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
577
+ if (this.Battery.StatusLowBattery === undefined) {
578
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
635
579
  } else {
636
- this.accessory.context.StatusLowBattery = this.StatusLowBattery;
637
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.StatusLowBattery);
638
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
639
- }
640
- }
641
-
642
- async stopScanning(switchbot: any) {
643
- switchbot.stopScan();
644
- if (this.BLE_IsConnected) {
645
- await this.BLEparseStatus();
646
- await this.updateHomeKitCharacteristics();
580
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
581
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
582
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
583
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
584
+ }
585
+ // ChargingState
586
+ if (this.Battery.ChargingState === undefined) {
587
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ChargingState: ${this.Battery.ChargingState}`);
647
588
  } else {
648
- await this.BLERefreshConnection(switchbot);
649
- }
650
- }
651
-
652
- async getCustomBLEAddress(switchbot: any) {
653
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
654
- (async () => {
655
- // Start to monitor advertisement packets
656
- await switchbot.startScan({
657
- model: '?',
658
- });
659
- // Set an event handler
660
- switchbot.onadvertisement = (ad: any) => {
661
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
662
- };
663
- await sleep(10000);
664
- // Stop to monitor
665
- switchbot.stopScan();
666
- })();
589
+ this.accessory.context.ChargingState = this.Battery.ChargingState;
590
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, this.Battery.ChargingState);
591
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
592
+ + ` ChargingState: ${this.Battery.ChargingState}`);
667
593
  }
668
594
  }
669
595
 
@@ -683,266 +609,13 @@ export class RobotVacuumCleaner {
683
609
  }
684
610
  }
685
611
 
686
- async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
687
- return fn().catch(async (e: any) => {
688
- if (max === 0) {
689
- throw e;
690
- }
691
- this.infoLog(e);
692
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Retrying`);
693
- await sleep(1000);
694
- return this.retry({ max: max - 1, fn });
695
- });
696
- }
697
-
698
- maxRetry(): number {
699
- if (this.device.maxRetry) {
700
- return this.device.maxRetry;
701
- } else {
702
- return 5;
703
- }
704
- }
705
-
706
- model(device: device & devicesConfig): string {
707
- let model: string;
708
- if (device.deviceType === 'Robot Vacuum Cleaner S1 Plus') {
709
- model = 'W3011010';
710
- } else if (device.deviceType === 'Robot Vacuum Cleaner S1') {
711
- model = 'W3011000';
712
- } else {
713
- model = 'N/A';
714
- }
715
- return model;
716
- }
717
-
718
- async scan(device: device & devicesConfig): Promise<void> {
719
- if (device.scanDuration) {
720
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
721
- if (this.BLE) {
722
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
723
- }
724
- } else {
725
- this.scanDuration = this.accessory.context.scanDuration = 1;
726
- if (this.BLE) {
727
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
728
- }
729
- }
730
- }
731
-
732
- async statusCode(statusCode: number): Promise<void> {
733
- switch (statusCode) {
734
- case 151:
735
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
736
- break;
737
- case 152:
738
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
739
- break;
740
- case 160:
741
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
742
- break;
743
- case 161:
744
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
745
- this.offlineOff();
746
- break;
747
- case 171:
748
- this.errorLog(
749
- `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` +
750
- `Hub: ${this.device.hubDeviceId}`,
751
- );
752
- this.offlineOff();
753
- break;
754
- case 190:
755
- this.errorLog(
756
- `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
757
- ` Or command format is invalid, statusCode: ${statusCode}`,
758
- );
759
- break;
760
- case 100:
761
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
762
- break;
763
- case 200:
764
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
765
- break;
766
- case 400:
767
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bad Request, The client has issued an invalid request. `
768
- + `This is commonly used to specify validation errors in a request payload, statusCode: ${statusCode}`);
769
- break;
770
- case 401:
771
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unauthorized, Authorization for the API is required, `
772
- + `but the request has not been authenticated, statusCode: ${statusCode}`);
773
- break;
774
- case 403:
775
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Forbidden, The request has been authenticated but does not `
776
- + `have appropriate permissions, or a requested resource is not found, statusCode: ${statusCode}`);
777
- break;
778
- case 404:
779
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Found, Specifies the requested path does not exist, `
780
- + `statusCode: ${statusCode}`);
781
- break;
782
- case 406:
783
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Acceptable, The client has requested a MIME type via `
784
- + `the Accept header for a value not supported by the server, statusCode: ${statusCode}`);
785
- break;
786
- case 415:
787
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unsupported Media Type, The client has defined a contentType `
788
- + `header that is not supported by the server, statusCode: ${statusCode}`);
789
- break;
790
- case 422:
791
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unprocessable Entity, The client has made a valid request, `
792
- + `but the server cannot process it. This is often used for APIs for which certain limits have been exceeded, statusCode: ${statusCode}`);
793
- break;
794
- case 429:
795
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Too Many Requests, The client has exceeded the number of `
796
- + `requests allowed for a given time window, statusCode: ${statusCode}`);
797
- break;
798
- case 500:
799
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Internal Server Error, An unexpected error on the SmartThings `
800
- + `servers has occurred. These errors should be rare, statusCode: ${statusCode}`);
801
- break;
802
- default:
803
- this.infoLog(
804
- `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` +
805
- `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`,
806
- );
807
- }
808
- }
809
-
810
612
  async offlineOff(): Promise<void> {
811
613
  if (this.device.offline) {
812
- await this.deviceContext();
813
- await this.updateHomeKitCharacteristics();
614
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.On, false);
814
615
  }
815
616
  }
816
617
 
817
618
  async apiError(e: any): Promise<void> {
818
- this.robotVacuumCleanerService.updateCharacteristic(this.hap.Characteristic.On, e);
819
- }
820
-
821
- async deviceContext() {
822
- if (this.On === undefined) {
823
- this.On = false;
824
- } else {
825
- this.On = this.accessory.context.On;
826
- }
827
- if (this.Brightness === undefined) {
828
- this.Brightness = 0;
829
- } else {
830
- this.Brightness = this.accessory.context.Brightness;
831
- }
832
- if (this.FirmwareRevision === undefined) {
833
- this.FirmwareRevision = this.platform.version;
834
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
835
- }
836
- }
837
-
838
- async refreshRate(device: device & devicesConfig): Promise<void> {
839
- if (device.refreshRate) {
840
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
841
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
842
- } else if (this.platform.config.options!.refreshRate) {
843
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
844
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
845
- }
846
- }
847
-
848
- async deviceConfig(device: device & devicesConfig): Promise<void> {
849
- let config = {};
850
- if (device.plug) {
851
- config = device.plug;
852
- }
853
- if (device.connectionType !== undefined) {
854
- config['connectionType'] = device.connectionType;
855
- }
856
- if (device.external !== undefined) {
857
- config['external'] = device.external;
858
- }
859
- if (device.logging !== undefined) {
860
- config['logging'] = device.logging;
861
- }
862
- if (device.refreshRate !== undefined) {
863
- config['refreshRate'] = device.refreshRate;
864
- }
865
- if (device.scanDuration !== undefined) {
866
- config['scanDuration'] = device.scanDuration;
867
- }
868
- if (device.offline !== undefined) {
869
- config['offline'] = device.offline;
870
- }
871
- if (device.maxRetry !== undefined) {
872
- config['maxRetry'] = device.maxRetry;
873
- }
874
- if (device.webhook !== undefined) {
875
- config['webhook'] = device.webhook;
876
- }
877
- if (Object.entries(config).length !== 0) {
878
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
879
- }
880
- }
881
-
882
- async deviceLogs(device: device & devicesConfig): Promise<void> {
883
- if (this.platform.debugMode) {
884
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
885
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
886
- } else if (device.logging) {
887
- this.deviceLogging = this.accessory.context.logging = device.logging;
888
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
889
- } else if (this.platform.config.options?.logging) {
890
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
891
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
892
- } else {
893
- this.deviceLogging = this.accessory.context.logging = 'standard';
894
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
895
- }
896
- }
897
-
898
- /**
899
- * Logging for Device
900
- */
901
- infoLog(...log: any[]): void {
902
- if (this.enablingDeviceLogging()) {
903
- this.platform.log.info(String(...log));
904
- }
905
- }
906
-
907
- warnLog(...log: any[]): void {
908
- if (this.enablingDeviceLogging()) {
909
- this.platform.log.warn(String(...log));
910
- }
911
- }
912
-
913
- debugWarnLog(...log: any[]): void {
914
- if (this.enablingDeviceLogging()) {
915
- if (this.deviceLogging?.includes('debug')) {
916
- this.platform.log.warn('[DEBUG]', String(...log));
917
- }
918
- }
919
- }
920
-
921
- errorLog(...log: any[]): void {
922
- if (this.enablingDeviceLogging()) {
923
- this.platform.log.error(String(...log));
924
- }
925
- }
926
-
927
- debugErrorLog(...log: any[]): void {
928
- if (this.enablingDeviceLogging()) {
929
- if (this.deviceLogging?.includes('debug')) {
930
- this.platform.log.error('[DEBUG]', String(...log));
931
- }
932
- }
933
- }
934
-
935
- debugLog(...log: any[]): void {
936
- if (this.enablingDeviceLogging()) {
937
- if (this.deviceLogging === 'debug') {
938
- this.platform.log.info('[DEBUG]', String(...log));
939
- } else {
940
- this.platform.log.debug(String(...log));
941
- }
942
- }
943
- }
944
-
945
- enablingDeviceLogging(): boolean {
946
- return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
619
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.On, e);
947
620
  }
948
621
  }