@switchbot/homebridge-switchbot 3.5.0-beta.7 → 3.5.0-beta.70

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 +425 -778
  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 +803 -837
  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 +241 -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 +283 -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 +254 -545
  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 +412 -806
  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 +711 -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 +540 -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 +261 -616
  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 +240 -594
  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 +196 -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 +281 -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 +252 -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 +191 -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 +180 -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 +188 -532
  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 +96 -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 +202 -521
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +10 -63
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +146 -475
  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 +10 -50
  88. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  89. package/dist/irdevice/airconditioner.js +324 -452
  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 +93 -307
  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 +39 -281
  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 +113 -341
  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 +118 -362
  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 +438 -570
  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 +87 -335
  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 +45 -285
  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 +47 -291
  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 -172
  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 +462 -817
  143. package/src/device/bot.ts +862 -931
  144. package/src/device/ceilinglight.ts +259 -633
  145. package/src/device/colorbulb.ts +300 -688
  146. package/src/device/contact.ts +288 -571
  147. package/src/device/curtain.ts +441 -838
  148. package/src/device/device.ts +734 -0
  149. package/src/device/fan.ts +596 -0
  150. package/src/device/hub.ts +299 -645
  151. package/src/device/humidifier.ts +274 -647
  152. package/src/device/iosensor.ts +233 -626
  153. package/src/device/lightstrip.ts +309 -620
  154. package/src/device/lock.ts +292 -601
  155. package/src/device/meter.ts +228 -619
  156. package/src/device/meterplus.ts +216 -619
  157. package/src/device/motion.ts +218 -559
  158. package/src/device/plug.ts +111 -490
  159. package/src/device/robotvacuumcleaner.ts +228 -550
  160. package/src/device/waterdetector.ts +169 -501
  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 +350 -477
  165. package/src/irdevice/airpurifier.ts +120 -330
  166. package/src/irdevice/camera.ts +53 -301
  167. package/src/irdevice/fan.ts +130 -360
  168. package/src/irdevice/irdevice.ts +346 -0
  169. package/src/irdevice/light.ts +157 -412
  170. package/src/irdevice/other.ts +507 -648
  171. package/src/irdevice/tv.ts +117 -367
  172. package/src/irdevice/vacuumcleaner.ts +59 -311
  173. package/src/irdevice/waterheater.ts +61 -320
  174. package/src/platform.ts +355 -219
  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,69 @@
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
+ accessory.context.LightBulb = accessory.context.LightBulb ?? {};
48
+ this.LightBulb = {
49
+ Name: accessory.context.LightBulb.Name ?? accessory.displayName,
50
+ Service: accessory.getService(this.hap.Service.Lightbulb) ?? accessory.addService(this.hap.Service.Lightbulb) as Service,
51
+ On: accessory.context.On ?? false,
52
+ Brightness: accessory.context.Brightness ?? 0,
53
+ };
54
+ accessory.context.LightBulb = this.LightBulb as object;
55
+
56
+ // Initialize LightBulb Characteristics
57
+ this.LightBulb.Service
58
+ .setCharacteristic(this.hap.Characteristic.Name, accessory.displayName)
59
+ .getCharacteristic(this.hap.Characteristic.On)
60
+ .onGet(() => {
61
+ return this.LightBulb.On;
62
+ })
63
+ .onSet(this.OnSet.bind(this));
98
64
 
99
- // handle Brightness events using the Brightness characteristic
100
- this.robotVacuumCleanerService
65
+ // Initialize LightBulb Brightness Characteristic
66
+ this.LightBulb.Service
101
67
  .getCharacteristic(this.hap.Characteristic.Brightness)
102
68
  .setProps({
103
69
  minStep: 25,
@@ -107,20 +73,43 @@ export class RobotVacuumCleaner {
107
73
  validValueRanges: [0, 100],
108
74
  })
109
75
  .onGet(() => {
110
- return this.Brightness;
76
+ return this.LightBulb.Brightness;
111
77
  })
112
78
  .onSet(this.BrightnessSet.bind(this));
113
79
 
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;
80
+ // Initialize Battery Service
81
+ accessory.context.Battery = accessory.context.Battery ?? {};
82
+ this.Battery = {
83
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
84
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
85
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
86
+ StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
87
+ ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGING,
88
+ };
89
+ accessory.context.Battery = this.Battery as object;
90
+
91
+ // Initialize Battery Characteristics
92
+ this.Battery.Service
93
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
94
+ .getCharacteristic(this.hap.Characteristic.BatteryLevel)
95
+ .onGet(() => {
96
+ return this.Battery.BatteryLevel;
97
+ });
118
98
 
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
- }
99
+ this.Battery.Service
100
+ .getCharacteristic(this.hap.Characteristic.StatusLowBattery)
101
+ .onGet(() => {
102
+ return this.Battery.StatusLowBattery;
103
+ });
104
+
105
+ this.Battery.Service
106
+ .getCharacteristic(this.hap.Characteristic.ChargingState)
107
+ .onGet(() => {
108
+ return this.Battery.ChargingState;
109
+ });
123
110
 
111
+ // Retrieve initial values and updateHomekit
112
+ this.refreshStatus();
124
113
  // Update Homekit
125
114
  this.updateHomeKitCharacteristics();
126
115
 
@@ -132,19 +121,22 @@ export class RobotVacuumCleaner {
132
121
  });
133
122
 
134
123
  //regisiter webhook event handler
135
- if (this.device.webhook) {
136
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
124
+ if (device.webhook) {
125
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
137
126
  this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
138
127
  try {
139
128
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
140
- const { onlineStatus, battery } = context;
141
- const { On, BatteryLevel } = this;
129
+ const { onlineStatus, battery, workingStatus } = context;
130
+ const { On } = this.LightBulb;
131
+ const { BatteryLevel, ChargingState } = this.Battery;
142
132
  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;
133
+ '(onlineStatus, battery, workingStatus) = ' +
134
+ `Webhook:(${onlineStatus}, ${battery}, ${workingStatus}), ` +
135
+ `current:(${On}, ${BatteryLevel}, ${ChargingState})`);
136
+ this.LightBulb.On = onlineStatus === 'online' ? true : false;
137
+ this.Battery.ChargingState = workingStatus === 'Charging'
138
+ ? this.hap.Characteristic.ChargingState.CHARGING : this.hap.Characteristic.ChargingState.NOT_CHARGING;
139
+ this.Battery.BatteryLevel = battery;
148
140
  this.updateHomeKitCharacteristics();
149
141
  } catch (e: any) {
150
142
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
@@ -164,10 +156,10 @@ export class RobotVacuumCleaner {
164
156
  )
165
157
  .subscribe(async () => {
166
158
  try {
167
- if (this.On !== this.accessory.context.On) {
159
+ if (this.LightBulb.On !== this.accessory.context.On) {
168
160
  await this.pushChanges();
169
161
  }
170
- if (this.On && this.Brightness !== this.accessory.context.Brightness) {
162
+ if (this.LightBulb.On && this.LightBulb.Brightness !== this.accessory.context.Brightness) {
171
163
  await this.openAPIpushBrightnessChanges();
172
164
  }
173
165
  } catch (e: any) {
@@ -181,60 +173,72 @@ export class RobotVacuumCleaner {
181
173
  });
182
174
  }
183
175
 
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();
176
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
177
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
178
+
179
+ // Battery
180
+ this.Battery.BatteryLevel = Number(serviceData.battery);
181
+ if (this.Battery.BatteryLevel < 10) {
182
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
194
183
  } 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
- );
184
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
199
185
  }
200
- }
186
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}, StatusLowBattery: ${this.Battery.StatusLowBattery}`);
201
187
 
202
- async BLEparseStatus(): Promise<void> {
203
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
204
188
  // State
205
- switch (this.BLE_On) {
189
+ switch (serviceData.state) {
206
190
  case 'on':
207
- this.On = true;
191
+ this.LightBulb.On = true;
208
192
  break;
209
193
  default:
210
- this.On = false;
194
+ this.LightBulb.On = false;
211
195
  }
212
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
196
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
213
197
  }
214
198
 
215
- async openAPIparseStatus() {
199
+ async openAPIparseStatus(deviceStatus: deviceStatus) {
216
200
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
217
- switch (this.OpenAPI_On) {
201
+ switch (deviceStatus.body.power) {
218
202
  case 'on':
219
- this.On = true;
203
+ this.LightBulb.On = true;
220
204
  break;
221
205
  default:
222
- this.On = false;
206
+ this.LightBulb.On = false;
223
207
  }
224
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
208
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
225
209
 
226
- // Battery
227
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
228
- if (this.BatteryLevel < 15) {
229
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
210
+ // BatteryLevel
211
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
212
+
213
+ // StatusLowBattery
214
+ if (this.Battery.BatteryLevel < 10) {
215
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
230
216
  } else {
231
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
217
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
218
+ }
219
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
220
+ this.Battery.BatteryLevel = 100;
232
221
  }
233
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
222
+ // ChargingState
223
+ this.Battery.ChargingState = deviceStatus.body.workingStatus === 'Charging'
224
+ ? this.hap.Characteristic.ChargingState.CHARGING : this.hap.Characteristic.ChargingState.NOT_CHARGING;
225
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
226
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}, ChargingState: ${this.Battery.ChargingState}`);
234
227
 
235
- // FirmwareRevision
236
- this.FirmwareRevision = this.OpenAPI_FirmwareRevision!;
237
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
228
+ // Firmware Version
229
+ const version = deviceStatus.body.version?.toString();
230
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
231
+ if (deviceStatus.body.version) {
232
+ const deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
233
+ this.accessory
234
+ .getService(this.hap.Service.AccessoryInformation)!
235
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
236
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
237
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
238
+ .updateValue(deviceVersion);
239
+ this.accessory.context.deviceVersion = deviceVersion;
240
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
241
+ }
238
242
  }
239
243
 
240
244
  /**
@@ -243,8 +247,8 @@ export class RobotVacuumCleaner {
243
247
  async refreshStatus(): Promise<void> {
244
248
  if (!this.device.enableCloudService && this.OpenAPI) {
245
249
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus enableCloudService: ${this.device.enableCloudService}`);
246
- /*} else if (this.BLE) {
247
- await this.BLERefreshStatus();*/
250
+ } else if (this.BLE) {
251
+ await this.BLERefreshStatus();
248
252
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
249
253
  await this.openAPIRefreshStatus();
250
254
  } else {
@@ -268,96 +272,44 @@ export class RobotVacuumCleaner {
268
272
  this.getCustomBLEAddress(switchbot);
269
273
  // Start to monitor advertisement packets
270
274
  (async () => {
271
- await switchbot.startScan({
272
- model: '?',
273
- id: this.device.bleMac,
274
- });
275
+ // Start to monitor advertisement packets
276
+ await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
275
277
  // Set an event handler
276
278
  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 === '?') {
279
+ if (this.device.bleMac === ad.address && ad.model === this.device.bleModel) {
280
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
281
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
280
282
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
281
- this.BLE_On = ad.serviceData.state;
282
283
  } else {
283
284
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
284
285
  }
285
286
  };
286
- // Wait 1 seconds
287
+ // Wait 10 seconds
287
288
  await switchbot.wait(this.scanDuration * 1000);
288
289
  // Stop to monitor
289
290
  await switchbot.stopScan();
290
291
  // Update HomeKit
291
- await this.BLEparseStatus();
292
+ await this.BLEparseStatus(switchbot.onadvertisement.serviceData);
292
293
  await this.updateHomeKitCharacteristics();
293
294
  })();
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 {
295
+ if (switchbot === undefined) {
340
296
  await this.BLERefreshConnection(switchbot);
341
- }*/
297
+ }
342
298
  }
343
299
 
344
- async openAPIRefreshStatus() {
300
+ async openAPIRefreshStatus(): Promise<void> {
345
301
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
346
302
  try {
347
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
348
- headers: this.platform.generateHeaders(),
349
- });
303
+ const { body, statusCode } = await this.platform.retryRequest(this.deviceMaxRetries, this.deviceDelayBetweenRetries,
304
+ `${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders() });
350
305
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
351
306
  const deviceStatus: any = await body.json();
352
307
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
353
308
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
354
309
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
355
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
310
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
356
311
  + `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();
312
+ this.openAPIparseStatus(deviceStatus);
361
313
  this.updateHomeKitCharacteristics();
362
314
  } else {
363
315
  this.statusCode(statusCode);
@@ -405,8 +357,9 @@ export class RobotVacuumCleaner {
405
357
 
406
358
  async BLEpushChanges(): Promise<void> {
407
359
  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}`);
360
+ if (this.LightBulb.On !== this.accessory.context.On) {
361
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`
362
+ + ` On: ${this.LightBulb.On} OnCached: ${this.accessory.context.On}`);
410
363
  const switchbot = await this.platform.connectBLE();
411
364
  // Convert to BLE Address
412
365
  this.device.bleMac = this.device
@@ -420,11 +373,11 @@ export class RobotVacuumCleaner {
420
373
  id: this.device.bleMac,
421
374
  })
422
375
  .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(),
376
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
377
+ return await this.retryBLE({
378
+ max: await this.maxRetryBLE(),
426
379
  fn: async () => {
427
- if (this.On) {
380
+ if (this.LightBulb.On) {
428
381
  return await device_list[0].turnOn({ id: this.device.bleMac });
429
382
  } else {
430
383
  return await device_list[0].turnOff({ id: this.device.bleMac });
@@ -434,7 +387,9 @@ export class RobotVacuumCleaner {
434
387
  })
435
388
  .then(() => {
436
389
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
437
- this.On = false;
390
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
391
+ + `On: ${this.LightBulb.On} sent over BLE, sent successfully`);
392
+ this.LightBulb.On = false;
438
393
  })
439
394
  .catch(async (e: any) => {
440
395
  this.apiError(e);
@@ -445,26 +400,15 @@ export class RobotVacuumCleaner {
445
400
  await this.BLEPushConnection();
446
401
  });
447
402
  } else {
448
- this.debugLog(
449
- `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`,
450
- );
403
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges,`
404
+ + ` On: ${this.LightBulb.On}, OnCached: ${this.accessory.context.On}`);
451
405
  }
452
406
  }
453
407
 
454
408
  async openAPIpushChanges() {
455
409
  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
- });
410
+ if (this.LightBulb.On !== this.accessory.context.On) {
411
+ const bodyChange = await this.commands();
468
412
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
469
413
  try {
470
414
  const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
@@ -480,6 +424,8 @@ export class RobotVacuumCleaner {
480
424
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
481
425
  this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
482
426
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
427
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
428
+ + `request to SwitchBot API, body: ${JSON.stringify(JSON.parse(bodyChange))} sent successfully`);
483
429
  } else {
484
430
  this.statusCode(statusCode);
485
431
  this.statusCode(deviceStatus.statusCode);
@@ -494,7 +440,7 @@ export class RobotVacuumCleaner {
494
440
  } else {
495
441
  this.debugLog(
496
442
  `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` +
497
- `On: ${this.On}, ` +
443
+ `On: ${this.LightBulb.On}, ` +
498
444
  `OnCached: ${this.accessory.context.On}`,
499
445
  );
500
446
  }
@@ -502,10 +448,11 @@ export class RobotVacuumCleaner {
502
448
 
503
449
  async openAPIpushBrightnessChanges() {
504
450
  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},`);
451
+ const bodyChange = await this.brightnessCommands();
452
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
507
453
  try {
508
454
  const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
455
+ body: bodyChange,
509
456
  method: 'POST',
510
457
  headers: this.platform.generateHeaders(),
511
458
  });
@@ -514,8 +461,10 @@ export class RobotVacuumCleaner {
514
461
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
515
462
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
516
463
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
517
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
464
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
518
465
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
466
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
467
+ + `request to SwitchBot API, body: ${JSON.stringify(JSON.parse(bodyChange))} sent successfully`);
519
468
  } else {
520
469
  this.statusCode(statusCode);
521
470
  this.statusCode(deviceStatus.statusCode);
@@ -529,10 +478,10 @@ export class RobotVacuumCleaner {
529
478
  }
530
479
  }
531
480
 
532
- private commands() {
481
+ async commands() {
533
482
  let command: string;
534
483
  let parameter: string;
535
- if (this.On) {
484
+ if (this.LightBulb.On) {
536
485
  command = 'start';
537
486
  parameter = 'default';
538
487
  } else {
@@ -547,44 +496,44 @@ export class RobotVacuumCleaner {
547
496
  return body;
548
497
  }
549
498
 
550
- private brightnessCommands() {
499
+ async brightnessCommands(): Promise<string> {
551
500
  let command: string;
552
501
  let parameter: string;
553
- if (this.Brightness === 25) {
502
+ if (this.LightBulb.Brightness === 25) {
554
503
  command = 'PowLevel';
555
504
  parameter = '0';
556
- } else if (this.Brightness === 50) {
505
+ } else if (this.LightBulb.Brightness === 50) {
557
506
  command = 'PowLevel';
558
507
  parameter = '1';
559
- } else if (this.Brightness === 75) {
508
+ } else if (this.LightBulb.Brightness === 75) {
560
509
  command = 'PowLevel';
561
510
  parameter = '2';
562
- } else if (this.Brightness === 100) {
511
+ } else if (this.LightBulb.Brightness === 100) {
563
512
  command = 'PowLevel';
564
513
  parameter = '3';
565
514
  } else {
566
515
  command = 'dock';
567
516
  parameter = 'default';
568
517
  }
569
- const body = JSON.stringify({
518
+ const bodyChange = JSON.stringify({
570
519
  command: `${command}`,
571
520
  parameter: `${parameter}`,
572
521
  commandType: 'command',
573
522
  });
574
- return body;
523
+ return bodyChange;
575
524
  }
576
525
 
577
526
  /**
578
527
  * Handle requests to set the value of the "On" characteristic
579
528
  */
580
529
  async OnSet(value: CharacteristicValue): Promise<void> {
581
- if (this.On === this.accessory.context.On) {
530
+ if (this.LightBulb.On === this.accessory.context.On) {
582
531
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set On: ${value}`);
583
532
  } else {
584
533
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
585
534
  }
586
535
 
587
- this.On = value;
536
+ this.LightBulb.On = value;
588
537
  this.doRobotVacuumCleanerUpdate.next();
589
538
  }
590
539
 
@@ -592,78 +541,60 @@ export class RobotVacuumCleaner {
592
541
  * Handle requests to set the value of the "Brightness" characteristic
593
542
  */
594
543
  async BrightnessSet(value: CharacteristicValue): Promise<void> {
595
- if (this.Brightness === this.accessory.context.Brightness) {
544
+ if (this.LightBulb.Brightness === this.accessory.context.Brightness) {
596
545
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set Brightness: ${value}`);
597
- } else if (this.On) {
546
+ } else if (this.LightBulb.On) {
598
547
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Brightness: ${value}`);
599
548
  } else {
600
549
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Brightness: ${value}`);
601
550
  }
602
551
 
603
- this.Brightness = value;
552
+ this.LightBulb.Brightness = value;
604
553
  this.doRobotVacuumCleanerUpdate.next();
605
554
  }
606
555
 
607
556
  async updateHomeKitCharacteristics(): Promise<void> {
608
557
  // On
609
- if (this.On === undefined) {
610
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
558
+ if (this.LightBulb.On === undefined) {
559
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
611
560
  } 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}`);
561
+ this.accessory.context.On = this.LightBulb.On;
562
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.On, this.LightBulb.On);
563
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.LightBulb.On}`);
615
564
  }
616
565
  // Brightness
617
- if (this.Brightness === undefined) {
618
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
566
+ if (this.LightBulb.Brightness === undefined) {
567
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.LightBulb.Brightness}`);
619
568
  } 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}`);
569
+ this.accessory.context.Brightness = this.LightBulb.Brightness;
570
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.Brightness, this.LightBulb.Brightness);
571
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Brightness: ${this.LightBulb.Brightness}`);
623
572
  }
624
573
  // BatteryLevel
625
- if (this.BatteryLevel === undefined) {
626
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
574
+ if (this.Battery.BatteryLevel === undefined) {
575
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
627
576
  } 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}`);
577
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
578
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
579
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
631
580
  }
632
581
  // StatusLowBattery
633
- if (this.StatusLowBattery === undefined) {
634
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
582
+ if (this.Battery.StatusLowBattery === undefined) {
583
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
635
584
  } 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();
585
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
586
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
587
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
588
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
589
+ }
590
+ // ChargingState
591
+ if (this.Battery.ChargingState === undefined) {
592
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ChargingState: ${this.Battery.ChargingState}`);
647
593
  } 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
- })();
594
+ this.accessory.context.ChargingState = this.Battery.ChargingState;
595
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, this.Battery.ChargingState);
596
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
597
+ + ` ChargingState: ${this.Battery.ChargingState}`);
667
598
  }
668
599
  }
669
600
 
@@ -683,266 +614,13 @@ export class RobotVacuumCleaner {
683
614
  }
684
615
  }
685
616
 
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
617
  async offlineOff(): Promise<void> {
811
618
  if (this.device.offline) {
812
- await this.deviceContext();
813
- await this.updateHomeKitCharacteristics();
619
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.On, false);
814
620
  }
815
621
  }
816
622
 
817
623
  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';
624
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.On, e);
947
625
  }
948
626
  }