@switchbot/homebridge-switchbot 3.5.0-beta.9 → 3.5.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/.vscode/settings.json +4 -1
  2. package/CHANGELOG.md +4 -1
  3. package/config.schema.json +164 -22
  4. package/dist/device/blindtilt.d.ts +21 -96
  5. package/dist/device/blindtilt.d.ts.map +1 -1
  6. package/dist/device/blindtilt.js +457 -866
  7. package/dist/device/blindtilt.js.map +1 -1
  8. package/dist/device/bot.d.ts +27 -72
  9. package/dist/device/bot.d.ts.map +1 -1
  10. package/dist/device/bot.js +851 -913
  11. package/dist/device/bot.js.map +1 -1
  12. package/dist/device/ceilinglight.d.ts +15 -69
  13. package/dist/device/ceilinglight.d.ts.map +1 -1
  14. package/dist/device/ceilinglight.js +316 -742
  15. package/dist/device/ceilinglight.js.map +1 -1
  16. package/dist/device/colorbulb.d.ts +15 -76
  17. package/dist/device/colorbulb.d.ts.map +1 -1
  18. package/dist/device/colorbulb.js +380 -833
  19. package/dist/device/colorbulb.js.map +1 -1
  20. package/dist/device/contact.d.ts +14 -66
  21. package/dist/device/contact.d.ts.map +1 -1
  22. package/dist/device/contact.js +267 -602
  23. package/dist/device/contact.js.map +1 -1
  24. package/dist/device/curtain.d.ts +18 -89
  25. package/dist/device/curtain.d.ts.map +1 -1
  26. package/dist/device/curtain.js +469 -897
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/device.d.ts +76 -0
  29. package/dist/device/device.d.ts.map +1 -0
  30. package/dist/device/device.js +846 -0
  31. package/dist/device/device.js.map +1 -0
  32. package/dist/device/fan.d.ts +63 -0
  33. package/dist/device/fan.d.ts.map +1 -0
  34. package/dist/device/fan.js +645 -0
  35. package/dist/device/fan.js.map +1 -0
  36. package/dist/device/hub.d.ts +19 -58
  37. package/dist/device/hub.d.ts.map +1 -1
  38. package/dist/device/hub.js +304 -640
  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 +300 -710
  43. package/dist/device/humidifier.js.map +1 -1
  44. package/dist/device/iosensor.d.ts +12 -64
  45. package/dist/device/iosensor.d.ts.map +1 -1
  46. package/dist/device/iosensor.js +225 -643
  47. package/dist/device/iosensor.js.map +1 -1
  48. package/dist/device/lightstrip.d.ts +12 -70
  49. package/dist/device/lightstrip.d.ts.map +1 -1
  50. package/dist/device/lightstrip.js +371 -742
  51. package/dist/device/lightstrip.js.map +1 -1
  52. package/dist/device/lock.d.ts +17 -63
  53. package/dist/device/lock.d.ts.map +1 -1
  54. package/dist/device/lock.js +309 -642
  55. package/dist/device/lock.js.map +1 -1
  56. package/dist/device/meter.d.ts +15 -64
  57. package/dist/device/meter.d.ts.map +1 -1
  58. package/dist/device/meter.js +223 -638
  59. package/dist/device/meter.js.map +1 -1
  60. package/dist/device/meterplus.d.ts +15 -65
  61. package/dist/device/meterplus.d.ts.map +1 -1
  62. package/dist/device/meterplus.js +216 -644
  63. package/dist/device/meterplus.js.map +1 -1
  64. package/dist/device/motion.d.ts +12 -69
  65. package/dist/device/motion.d.ts.map +1 -1
  66. package/dist/device/motion.js +209 -588
  67. package/dist/device/motion.js.map +1 -1
  68. package/dist/device/plug.d.ts +10 -57
  69. package/dist/device/plug.d.ts.map +1 -1
  70. package/dist/device/plug.js +141 -532
  71. package/dist/device/plug.js.map +1 -1
  72. package/dist/device/robotvacuumcleaner.d.ts +13 -63
  73. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  74. package/dist/device/robotvacuumcleaner.js +252 -609
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +11 -63
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +179 -521
  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 +337 -482
  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 +108 -333
  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 +47 -299
  98. package/dist/irdevice/camera.js.map +1 -1
  99. package/dist/irdevice/fan.d.ts +7 -43
  100. package/dist/irdevice/fan.d.ts.map +1 -1
  101. package/dist/irdevice/fan.js +95 -364
  102. package/dist/irdevice/fan.js.map +1 -1
  103. package/dist/irdevice/irdevice.d.ts +46 -0
  104. package/dist/irdevice/irdevice.d.ts.map +1 -0
  105. package/dist/irdevice/irdevice.js +393 -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 +121 -376
  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 +441 -584
  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 +94 -353
  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 +48 -299
  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 +50 -305
  126. package/dist/irdevice/waterheater.js.map +1 -1
  127. package/dist/platform.d.ts +22 -8
  128. package/dist/platform.d.ts.map +1 -1
  129. package/dist/platform.js +342 -191
  130. package/dist/platform.js.map +1 -1
  131. package/dist/settings.d.ts +66 -18
  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 +95 -0
  136. package/dist/utils.d.ts.map +1 -1
  137. package/dist/utils.js +657 -1
  138. package/dist/utils.js.map +1 -1
  139. package/eslint.config.js +96 -0
  140. package/package.json +20 -16
  141. package/src/custom.d.ts +2 -1
  142. package/src/device/blindtilt.ts +488 -937
  143. package/src/device/bot.ts +907 -1016
  144. package/src/device/ceilinglight.ts +330 -798
  145. package/src/device/colorbulb.ts +394 -904
  146. package/src/device/contact.ts +298 -637
  147. package/src/device/curtain.ts +496 -954
  148. package/src/device/device.ts +872 -0
  149. package/src/device/fan.ts +692 -0
  150. package/src/device/hub.ts +338 -671
  151. package/src/device/humidifier.ts +330 -777
  152. package/src/device/iosensor.ts +258 -671
  153. package/src/device/lightstrip.ts +394 -809
  154. package/src/device/lock.ts +345 -700
  155. package/src/device/meter.ts +256 -666
  156. package/src/device/meterplus.ts +248 -672
  157. package/src/device/motion.ts +234 -622
  158. package/src/device/plug.ts +152 -572
  159. package/src/device/robotvacuumcleaner.ts +273 -653
  160. package/src/device/waterdetector.ts +198 -549
  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 +368 -540
  165. package/src/irdevice/airpurifier.ts +134 -369
  166. package/src/irdevice/camera.ts +60 -324
  167. package/src/irdevice/fan.ts +111 -392
  168. package/src/irdevice/irdevice.ts +406 -0
  169. package/src/irdevice/light.ts +159 -425
  170. package/src/irdevice/other.ts +509 -661
  171. package/src/irdevice/tv.ts +123 -388
  172. package/src/irdevice/vacuumcleaner.ts +61 -324
  173. package/src/irdevice/waterheater.ts +63 -333
  174. package/src/platform.ts +395 -259
  175. package/src/settings.ts +120 -610
  176. package/src/utils.ts +661 -1
  177. package/src/device/waterdetector.json +0 -11
@@ -1,143 +1,110 @@
1
- import { request } from 'undici';
2
- import { sleep } from '../utils.js';
1
+ /* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
+ *
3
+ * ceilinglight.ts: @switchbot/homebridge-switchbot.
4
+ */
5
+ import { deviceBase } from './device.js';
3
6
  import { interval, Subject } from 'rxjs';
4
- import { SwitchBotPlatform } from '../platform.js';
7
+ import { hs2rgb, rgb2hs, m2hs } from '../utils.js';
5
8
  import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
6
- import { device, devicesConfig, deviceStatus, hs2rgb, rgb2hs, m2hs, serviceData, Devices, SwitchBotPlatformConfig } from '../settings.js';
7
- import {
8
- Service, PlatformAccessory, CharacteristicValue, ControllerConstructor, Controller, ControllerServiceMap, API, Logging, HAP,
9
- } from 'homebridge';
9
+
10
+ import type { SwitchBotPlatform } from '../platform.js';
11
+ import type { device, devicesConfig, serviceData, deviceStatus } from '../settings.js';
12
+ import type { Service, PlatformAccessory, CharacteristicValue, ControllerConstructor, Controller, ControllerServiceMap } from 'homebridge';
10
13
 
11
14
  /**
12
15
  * Platform Accessory
13
16
  * An instance of this class is created for each accessory your platform registers
14
17
  * Each accessory may expose multiple services of different service types.
15
18
  */
16
- export class CeilingLight {
17
- public readonly api: API;
18
- public readonly log: Logging;
19
- public readonly config!: SwitchBotPlatformConfig;
20
- protected readonly hap: HAP;
19
+ export class CeilingLight extends deviceBase {
21
20
  // Services
22
- lightBulbService!: Service;
23
-
24
- // Characteristic Values
25
- On!: CharacteristicValue;
26
- Hue!: CharacteristicValue;
27
- Saturation!: CharacteristicValue;
28
- Brightness!: CharacteristicValue;
29
- ColorTemperature?: CharacteristicValue;
30
- FirmwareRevision!: CharacteristicValue;
31
-
32
- // OpenAPI Status
33
- OpenAPI_On: deviceStatus['power'];
34
- OpenAPI_RGB: deviceStatus['color'];
35
- OpenAPI_Brightness: deviceStatus['brightness'];
36
- OpenAPI_FirmwareRevision: deviceStatus['version'];
37
- OpenAPI_ColorTemperature?: deviceStatus['colorTemperature'];
38
-
39
- // BLE Status
40
- BLE_Delay: serviceData['delay'];
41
- BLE_On: serviceData['state'];
42
- BLE_WifiRssi: serviceData['wifiRssi'];
43
-
44
- // BLE Others
45
- BLE_IsConnected?: boolean;
46
-
47
- // Config
48
- set_minStep?: number;
49
- scanDuration!: number;
50
- deviceLogging!: string;
51
- deviceRefreshRate!: number;
52
- adaptiveLightingShift?: number;
21
+ private LightBulb: {
22
+ Name: CharacteristicValue;
23
+ Service: Service;
24
+ On: CharacteristicValue;
25
+ Hue: CharacteristicValue;
26
+ Saturation: CharacteristicValue;
27
+ Brightness: CharacteristicValue;
28
+ ColorTemperature?: CharacteristicValue;
29
+ };
53
30
 
54
31
  // Adaptive Lighting
55
32
  AdaptiveLightingController?: ControllerConstructor | Controller<ControllerServiceMap>;
56
- minKelvin!: number;
57
- maxKelvin!: number;
58
-
59
- // Others
60
- cacheKelvin!: number;
33
+ adaptiveLightingShift?: number;
61
34
 
62
35
  // Updates
63
36
  ceilingLightUpdateInProgress!: boolean;
64
37
  doCeilingLightUpdate!: Subject<void>;
65
38
 
66
- // Connection
67
- private readonly OpenAPI: boolean;
68
- private readonly BLE: boolean;
69
-
70
39
  constructor(
71
- private readonly platform: SwitchBotPlatform,
72
- private accessory: PlatformAccessory,
73
- public device: device & devicesConfig,
40
+ readonly platform: SwitchBotPlatform,
41
+ accessory: PlatformAccessory,
42
+ device: device & devicesConfig,
74
43
  ) {
75
- this.api = this.platform.api;
76
- this.log = this.platform.log;
77
- this.config = this.platform.config;
78
- this.hap = this.api.hap;
79
- // Connection
80
- this.BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI';
81
- this.OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI';
44
+ super(platform, accessory, device);
82
45
  // default placeholders
83
- this.deviceLogs(device);
84
- this.scan(device);
85
- this.refreshRate(device);
86
46
  this.adaptiveLighting(device);
87
- this.deviceContext();
88
- this.deviceConfig(device);
89
47
 
90
48
  // this is subject we use to track when we need to POST changes to the SwitchBot API
91
49
  this.doCeilingLightUpdate = new Subject();
92
50
  this.ceilingLightUpdateInProgress = false;
93
51
 
94
- // Retrieve initial values and updateHomekit
95
- this.refreshStatus();
96
-
97
- // set accessory information
98
- accessory
99
- .getService(this.hap.Service.AccessoryInformation)!
100
- .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
101
- .setCharacteristic(this.hap.Characteristic.Model, this.model(device))
102
- .setCharacteristic(this.hap.Characteristic.SerialNumber, device.deviceId)
103
- .setCharacteristic(this.hap.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision);
104
-
105
- // get the Lightbulb service if it exists, otherwise create a new Lightbulb service
106
- // you can create multiple services for each accessory
107
- const lightBulbService = `${accessory.displayName} ${device.deviceType}`;
108
- (this.lightBulbService = accessory.getService(this.hap.Service.Lightbulb)
109
- || accessory.addService(this.hap.Service.Lightbulb)), lightBulbService;
110
-
111
- if (this.adaptiveLightingShift === -1 && this.accessory.context.adaptiveLighting) {
112
- this.accessory.removeService(this.lightBulbService);
113
- this.lightBulbService = this.accessory.addService(this.hap.Service.Lightbulb);
114
- this.accessory.context.adaptiveLighting = false;
115
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} adaptiveLighting: ${this.accessory.context.adaptiveLighting}`);
52
+ // Initialize LightBulb Service
53
+ accessory.context.LightBulb = accessory.context.LightBulb ?? {};
54
+ this.LightBulb = {
55
+ Name: accessory.context.LightBul.bName ?? accessory.displayName,
56
+ Service: accessory.getService(this.hap.Service.Lightbulb) ?? accessory.addService(this.hap.Service.Lightbulb) as Service,
57
+ On: accessory.context.On ?? false,
58
+ Hue: accessory.context.Hue ?? 0,
59
+ Saturation: accessory.context.Saturation ?? 0,
60
+ Brightness: accessory.context.Brightness ?? 0,
61
+ ColorTemperature: accessory.context.ColorTemperature ?? 140,
62
+ };
63
+ accessory.context.LightBulb = this.LightBulb as object;
64
+
65
+ // Adaptive Lighting
66
+ if (this.adaptiveLightingShift === -1 && accessory.context.adaptiveLighting) {
67
+ accessory.removeService(this.LightBulb.Service);
68
+ this.LightBulb.Service = accessory.addService(this.hap.Service.Lightbulb);
69
+ accessory.context.adaptiveLighting = false;
70
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} adaptiveLighting: ${accessory.context.adaptiveLighting}`);
116
71
  }
117
-
118
- this.lightBulbService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
119
- if (!this.lightBulbService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
120
- this.lightBulbService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
72
+ if (this.adaptiveLightingShift !== -1) {
73
+ this.AdaptiveLightingController = new platform.api.hap.AdaptiveLightingController(this.LightBulb.Service, {
74
+ customTemperatureAdjustment: this.adaptiveLightingShift,
75
+ });
76
+ this.accessory.configureController(this.AdaptiveLightingController);
77
+ this.accessory.context.adaptiveLighting = true;
78
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} adaptiveLighting: ${this.accessory.context.adaptiveLighting},`
79
+ + ` adaptiveLightingShift: ${this.adaptiveLightingShift}`);
121
80
  }
122
- // handle on / off events using the On characteristic
123
- this.lightBulbService.getCharacteristic(this.hap.Characteristic.On).onSet(this.OnSet.bind(this));
81
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} adaptiveLightingShift: ${this.adaptiveLightingShift}`);
82
+
83
+ // Initialize LightBulb Characteristics
84
+ this.LightBulb.Service
85
+ .setCharacteristic(this.hap.Characteristic.Name, this.LightBulb.Name)
86
+ .getCharacteristic(this.hap.Characteristic.On)
87
+ .onGet(() => {
88
+ return this.LightBulb.On;
89
+ })
90
+ .onSet(this.OnSet.bind(this));
124
91
 
125
- // handle Brightness events using the Brightness characteristic
126
- this.lightBulbService
92
+ // Initialize LightBulb Brightness
93
+ this.LightBulb.Service
127
94
  .getCharacteristic(this.hap.Characteristic.Brightness)
128
95
  .setProps({
129
- minStep: this.minStep(device),
96
+ minStep: device.ceilinglight?.set_minStep ?? 1,
130
97
  minValue: 0,
131
98
  maxValue: 100,
132
99
  validValueRanges: [0, 100],
133
100
  })
134
101
  .onGet(() => {
135
- return this.Brightness;
102
+ return this.LightBulb.Brightness;
136
103
  })
137
104
  .onSet(this.BrightnessSet.bind(this));
138
105
 
139
- // handle ColorTemperature events using the ColorTemperature characteristic
140
- this.lightBulbService
106
+ // Initialize LightBulb ColorTemperature
107
+ this.LightBulb.Service
141
108
  .getCharacteristic(this.hap.Characteristic.ColorTemperature)
142
109
  .setProps({
143
110
  minValue: 140,
@@ -145,12 +112,12 @@ export class CeilingLight {
145
112
  validValueRanges: [140, 500],
146
113
  })
147
114
  .onGet(() => {
148
- return this.ColorTemperature!;
115
+ return this.LightBulb.ColorTemperature!;
149
116
  })
150
117
  .onSet(this.ColorTemperatureSet.bind(this));
151
118
 
152
- // handle Hue events using the Hue characteristic
153
- this.lightBulbService
119
+ // Initialize LightBulb Hue
120
+ this.LightBulb.Service
154
121
  .getCharacteristic(this.hap.Characteristic.Hue)
155
122
  .setProps({
156
123
  minValue: 0,
@@ -158,12 +125,12 @@ export class CeilingLight {
158
125
  validValueRanges: [0, 360],
159
126
  })
160
127
  .onGet(() => {
161
- return this.Hue;
128
+ return this.LightBulb.Hue;
162
129
  })
163
130
  .onSet(this.HueSet.bind(this));
164
131
 
165
- // handle Hue events using the Hue characteristic
166
- this.lightBulbService
132
+ // Initialize LightBulb Saturation
133
+ this.LightBulb.Service
167
134
  .getCharacteristic(this.hap.Characteristic.Saturation)
168
135
  .setProps({
169
136
  minValue: 0,
@@ -171,22 +138,12 @@ export class CeilingLight {
171
138
  validValueRanges: [0, 100],
172
139
  })
173
140
  .onGet(() => {
174
- return this.Saturation;
141
+ return this.LightBulb.Saturation;
175
142
  })
176
143
  .onSet(this.SaturationSet.bind(this));
177
144
 
178
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} adaptiveLightingShift: ${this.adaptiveLightingShift}`);
179
- if (this.adaptiveLightingShift !== -1) {
180
- this.AdaptiveLightingController = new platform.api.hap.AdaptiveLightingController(this.lightBulbService, {
181
- customTemperatureAdjustment: this.adaptiveLightingShift,
182
- });
183
- this.accessory.configureController(this.AdaptiveLightingController);
184
- this.accessory.context.adaptiveLighting = true;
185
- this.debugLog(
186
- `${this.device.deviceType}: ${this.accessory.displayName} adaptiveLighting: ${this.accessory.context.adaptiveLighting},` +
187
- ` adaptiveLightingShift: ${this.adaptiveLightingShift}`,
188
- );
189
- }
145
+ // Retrieve initial values and updateHomekit
146
+ this.refreshStatus();
190
147
 
191
148
  // Update Homekit
192
149
  this.updateHomeKitCharacteristics();
@@ -199,27 +156,7 @@ export class CeilingLight {
199
156
  });
200
157
 
201
158
  //regisiter webhook event handler
202
- if (this.device.webhook) {
203
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
204
- this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
205
- try {
206
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
207
- const { powerState, brightness, colorTemperature } = context;
208
- const { On, Brightness, ColorTemperature } = this;
209
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
210
- '(powerState, brightness, colorTemperature) = ' +
211
- `Webhook:(${powerState}, ${brightness}, ${colorTemperature}), ` +
212
- `current:(${On}, ${Brightness}, ${ColorTemperature})`);
213
- this.On = powerState === 'ON' ? true : false;
214
- this.Brightness = brightness;
215
- this.ColorTemperature = colorTemperature;
216
- this.updateHomeKitCharacteristics();
217
- } catch (e: any) {
218
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
219
- + `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
220
- }
221
- };
222
- }
159
+ this.registerWebhook(accessory, device);
223
160
 
224
161
  // Watch for Bulb change events
225
162
  // We put in a debounce of 100ms so we don't make duplicate calls
@@ -228,117 +165,100 @@ export class CeilingLight {
228
165
  tap(() => {
229
166
  this.ceilingLightUpdateInProgress = true;
230
167
  }),
231
- debounceTime(this.platform.config.options!.pushRate! * 1000),
168
+ debounceTime(this.devicePushRate * 1000),
232
169
  )
233
170
  .subscribe(async () => {
234
171
  try {
235
172
  await this.pushChanges();
236
173
  } catch (e: any) {
237
174
  this.apiError(e);
238
- this.errorLog(
239
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` +
240
- ` Error Message: ${JSON.stringify(e.message)}`,
241
- );
175
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
176
+ + ` Error Message: ${JSON.stringify(e.message)}`);
242
177
  }
243
178
  this.ceilingLightUpdateInProgress = false;
244
179
  });
245
180
  }
246
181
 
247
- private model(device): CharacteristicValue {
248
- let model: string;
249
- if (device.deviceType === 'Ceiling Light') {
250
- model = 'W2612230' || 'W2612240';
251
- } else if (device.deviceType === 'Ceiling Light Pro') {
252
- model = 'W2612210' || 'W2612220';
253
- } else {
254
- model = 'unknown';
255
- }
256
- return model;
257
- }
258
-
259
182
  /**
260
- * Parse the device status from the SwitchBot api
183
+ * Parse the device status from the SwitchBotBLE API
261
184
  */
262
- async parseStatus(): Promise<void> {
263
- if (!this.device.enableCloudService && this.OpenAPI) {
264
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`);
265
- }
266
- /*if (this.BLE) {
267
- await this.BLEparseStatus();
268
- } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) {
269
- await this.openAPIparseStatus();
270
- } else {
271
- await this.offlineOff();
272
- this.debugWarnLog(
273
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`,
274
- );
275
- }
276
- }
277
-
278
- async BLEparseStatus(): Promise<void> {
185
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
279
186
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
280
187
  // State
281
- switch (this.BLE_On) {
188
+ switch (serviceData.state) {
282
189
  case 'on':
283
- this.On = true;
190
+ this.LightBulb.On = true;
284
191
  break;
285
192
  default:
286
- this.On = false;
193
+ this.LightBulb.On = false;
287
194
  }
288
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
195
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
289
196
  }
290
197
 
291
- async openAPIparseStatus() {
198
+ /**
199
+ * Parse the device status from the SwitchBot OpenAPI
200
+ */
201
+ async openAPIparseStatus(deviceStatus: deviceStatus) {
292
202
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
293
- switch (this.OpenAPI_On) {
203
+ switch (deviceStatus.body.power) {
294
204
  case 'on':
295
- this.On = true;
205
+ this.LightBulb.On = true;
296
206
  break;
297
207
  default:
298
- this.On = false;
208
+ this.LightBulb.On = false;
299
209
  }
300
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
210
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
301
211
 
302
212
  // Brightness
303
- this.Brightness = Number(this.OpenAPI_Brightness);
304
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
213
+ this.LightBulb.Brightness = Number(deviceStatus.body.brightness);
214
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.LightBulb.Brightness}`);
305
215
 
306
216
  // Color, Hue & Brightness
307
- if (this.OpenAPI_RGB) {
308
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} color: ${JSON.stringify(this.OpenAPI_RGB)}`);
309
- const [red, green, blue] = this.OpenAPI_RGB!.split(':');
217
+ if (deviceStatus.body.color) {
218
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} color: ${JSON.stringify(deviceStatus.body.color)}`);
219
+ const [red, green, blue] = deviceStatus.body.color!.split(':');
310
220
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} red: ${JSON.stringify(red)}`);
311
221
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} green: ${JSON.stringify(green)}`);
312
222
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${JSON.stringify(blue)}`);
313
223
 
314
224
  const [hue, saturation] = rgb2hs(Number(red), Number(green), Number(blue));
315
- this.debugLog(
316
- `${this.device.deviceType}: ${this.accessory.displayName}` + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`,
317
- );
225
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
226
+ + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`);
318
227
 
319
228
  // Hue
320
- this.Hue = hue;
321
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${this.Hue}`);
229
+ this.LightBulb.Hue = hue;
230
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${this.LightBulb.Hue}`);
322
231
 
323
232
  // Saturation
324
- this.Saturation = saturation;
325
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${this.Saturation}`);
233
+ this.LightBulb.Saturation = saturation;
234
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${this.LightBulb.Saturation}`);
326
235
  }
327
236
 
328
237
  // ColorTemperature
329
- if (!Number.isNaN(this.OpenAPI_ColorTemperature)) {
330
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI ColorTemperature: ${this.OpenAPI_ColorTemperature}`);
331
- const mired = Math.round(1000000 / this.OpenAPI_ColorTemperature!);
238
+ if (!Number.isNaN(deviceStatus.body.colorTemperature)) {
239
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI ColorTemperature: ${deviceStatus.body.colorTemperature}`);
240
+ const mired = Math.round(1000000 / deviceStatus.body.colorTemperature!);
332
241
 
333
- this.ColorTemperature = Number(mired);
242
+ this.LightBulb.ColorTemperature = Number(mired);
334
243
 
335
- this.ColorTemperature = Math.max(Math.min(this.ColorTemperature, 500), 140);
336
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ColorTemperature: ${this.ColorTemperature}`);
244
+ this.LightBulb.ColorTemperature = Math.max(Math.min(this.LightBulb.ColorTemperature, 500), 140);
245
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ColorTemperature: ${this.LightBulb.ColorTemperature}`);
337
246
  }
338
247
 
339
- // FirmwareRevision
340
- this.FirmwareRevision = this.OpenAPI_FirmwareRevision!;
341
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
248
+ // Firmware Version
249
+ const version = deviceStatus.body.version?.toString();
250
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
251
+ if (deviceStatus.body.version) {
252
+ const deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
253
+ this.accessory
254
+ .getService(this.hap.Service.AccessoryInformation)!
255
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
256
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
257
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
258
+ .updateValue(deviceVersion);
259
+ this.accessory.context.deviceVersion = deviceVersion;
260
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
261
+ }
342
262
  }
343
263
 
344
264
  /**
@@ -353,141 +273,97 @@ export class CeilingLight {
353
273
  await this.openAPIRefreshStatus();
354
274
  } else {
355
275
  await this.offlineOff();
356
- this.debugWarnLog(
357
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` +
358
- ` ${this.device.connectionType}, refreshStatus will not happen.`,
359
- );
276
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
277
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
360
278
  }
361
279
  }
362
280
 
363
281
  async BLERefreshStatus(): Promise<void> {
364
282
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
365
- const switchbot = await this.platform.connectBLE();
366
- // Convert to BLE Address
367
- this.device.bleMac = this.device
368
- .deviceId!.match(/.{1,2}/g)!
369
- .join(':')
370
- .toLowerCase();
371
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
372
- this.getCustomBLEAddress(switchbot);
373
- // Start to monitor advertisement packets
374
- (async () => {
283
+ const switchbot = await this.switchbotBLE();
284
+
285
+ if (switchbot === undefined) {
286
+ await this.BLERefreshConnection(switchbot);
287
+ } else {
288
+ (async () => {
375
289
  // Start to monitor advertisement packets
376
- await switchbot.startScan({
377
- id: this.device.bleMac,
378
- });
379
- // Set an event handler
380
- switchbot.onadvertisement = (ad: any) => {
381
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
382
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
383
- if (this.device.bleMac === ad.address && ad.model === 's') {
384
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
385
- this.BLE_On = ad.serviceData.state;
386
- //this.delay = ad.serviceData.delay;
387
- //this.timer = ad.serviceData.timer;
388
- //this.syncUtcTime = ad.serviceData.syncUtcTime;
389
- //this.wifiRssi = ad.serviceData.wifiRssi;
390
- //this.overload = ad.serviceData.overload;
391
- //this.currentPower = ad.serviceData.currentPower;
290
+ const serviceData: serviceData = await this.monitorAdvertisementPackets(switchbot);
291
+ // Update HomeKit
292
+ if (serviceData.model !== '' && serviceData.modelName !== '') {
293
+ await this.BLEparseStatus(serviceData);
294
+ await this.updateHomeKitCharacteristics();
392
295
  } else {
393
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
394
- }
395
- };
396
- // Wait 1 seconds
397
- await switchbot.wait(this.scanDuration * 1000);
398
- // Stop to monitor
399
- await switchbot.stopScan();
400
- // Update HomeKit
401
- await this.BLEparseStatus();
402
- await this.updateHomeKitCharacteristics();
403
- })();
404
- /*if (switchbot !== false) {
405
- switchbot
406
- .startScan({
407
- model: '',
408
- id: this.device.bleMac,
409
- })
410
- .then(async () => {
411
- // Set an event handler
412
- switchbot.onadvertisement = async (ad: ad) => {
413
- this.debugLog(
414
- `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` +
415
- ` BLE Address Found: ${ad.address}`,
416
- );
417
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
418
- this.BLE_On = ad.serviceData.state;
419
- //this.delay = ad.serviceData.delay;
420
- //this.timer = ad.serviceData.timer;
421
- //this.syncUtcTime = ad.serviceData.syncUtcTime;
422
- //this.wifiRssi = ad.serviceData.wifiRssi;
423
- //this.overload = ad.serviceData.overload;
424
- //this.currentPower = ad.serviceData.currentPower;
425
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
426
- this.debugLog(
427
- `${this.device.deviceType}: ${this.accessory.displayName} state: ${ad.serviceData.state}, ` +
428
- `delay: ${ad.serviceData.delay}, timer: ${ad.serviceData.timer}, syncUtcTime: ${ad.serviceData.syncUtcTime} ` +
429
- `wifiRssi: ${ad.serviceData.wifiRssi}, overload: ${ad.serviceData.overload}, currentPower: ${ad.serviceData.currentPower}`,
430
- );
431
-
432
- if (ad.serviceData) {
433
- this.BLE_IsConnected = true;
434
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
435
- await this.stopScanning(switchbot);
436
- } else {
437
- this.BLE_IsConnected = false;
438
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
439
- }
440
- };
441
- // Wait
442
- return await sleep(this.scanDuration * 1000);
443
- })
444
- .then(async () => {
445
- // Stop to monitor
446
- await this.stopScanning(switchbot);
447
- })
448
- .catch(async (e: any) => {
449
- this.apiError(e);
450
- this.errorLog(
451
- `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` +
452
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
453
- );
296
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed to get serviceData, serviceData: ${serviceData}`);
454
297
  await this.BLERefreshConnection(switchbot);
455
- });
456
- } else {
457
- await this.BLERefreshConnection(switchbot);
458
- }*/
298
+ }
299
+ })();
300
+ }
459
301
  }
460
302
 
461
- async openAPIRefreshStatus() {
303
+ async openAPIRefreshStatus(): Promise<void> {
462
304
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
463
305
  try {
464
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
465
- headers: this.platform.generateHeaders(),
466
- });
467
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
306
+ const { body, statusCode } = await this.deviceRefreshStatus();
468
307
  const deviceStatus: any = await body.json();
469
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
470
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
308
+ await this.refreshStatusCodes(statusCode, deviceStatus);;
471
309
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
472
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
473
- + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
474
- this.OpenAPI_On = deviceStatus.body.power;
475
- this.OpenAPI_RGB = deviceStatus.body.color;
476
- this.OpenAPI_Brightness = deviceStatus.body.brightness;
477
- this.OpenAPI_ColorTemperature = deviceStatus.body.colorTemperature;
478
- this.OpenAPI_FirmwareRevision = deviceStatus.body.version;
479
- this.openAPIparseStatus();
480
- this.updateHomeKitCharacteristics();
310
+ await this.successfulRefreshStatus(statusCode, deviceStatus);
311
+ await this.openAPIparseStatus(deviceStatus);
312
+ await this.updateHomeKitCharacteristics();
481
313
  } else {
482
- this.statusCode(statusCode);
483
- this.statusCode(deviceStatus.statusCode);
314
+ await this.statusCodes(statusCode, deviceStatus);
484
315
  }
485
316
  } catch (e: any) {
486
317
  this.apiError(e);
487
- this.errorLog(
488
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` +
489
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
490
- );
318
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
319
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
320
+ }
321
+ }
322
+
323
+ async registerWebhook(accessory: PlatformAccessory, device: device & devicesConfig) {
324
+ if (device.webhook) {
325
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is listening webhook.`);
326
+ this.platform.webhookEventHandler[device.deviceId] = async (context) => {
327
+ try {
328
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
329
+ const { powerState, brightness, colorTemperature } = context;
330
+ const { On, Brightness, ColorTemperature } = this.LightBulb;
331
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} ` +
332
+ '(powerState, brightness, colorTemperature) = ' +
333
+ `Webhook:(${powerState}, ${brightness}, ${colorTemperature}), `
334
+ + `current:(${On}, ${Brightness}, ${ColorTemperature})`);
335
+
336
+ // On
337
+ this.LightBulb.On = powerState === 'ON' ? true : false;
338
+ if (accessory.context.Brightness !== this.LightBulb.On) {
339
+ this.infoLog(`${device.deviceType}: ${accessory.displayName} On: ${this.LightBulb.On}`);
340
+ } else {
341
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} On: ${this.LightBulb.On}`);
342
+ }
343
+
344
+ // Brightness
345
+ this.LightBulb.Brightness = brightness;
346
+ if (accessory.context.Brightness !== this.LightBulb.Brightness) {
347
+ this.infoLog(`${device.deviceType}: ${accessory.displayName} Brightness: ${this.LightBulb.Brightness}`);
348
+ } else {
349
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} Brightness: ${this.LightBulb.Brightness}`);
350
+ }
351
+
352
+ // ColorTemperature
353
+ this.LightBulb.ColorTemperature = colorTemperature;
354
+ if (accessory.context.ColorTemperature !== this.LightBulb.ColorTemperature) {
355
+ this.infoLog(`${device.deviceType}: ${accessory.displayName} ColorTemperature: ${this.LightBulb.ColorTemperature}`);
356
+ } else {
357
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} ColorTemperature: ${this.LightBulb.ColorTemperature}`);
358
+ }
359
+ this.updateHomeKitCharacteristics();
360
+ } catch (e: any) {
361
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} `
362
+ + `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
363
+ }
364
+ };
365
+ } else {
366
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is not listening webhook.`);
491
367
  }
492
368
  }
493
369
 
@@ -505,15 +381,14 @@ export class CeilingLight {
505
381
  async pushChanges(): Promise<void> {
506
382
  if (!this.device.enableCloudService && this.OpenAPI) {
507
383
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} pushChanges enableCloudService: ${this.device.enableCloudService}`);
508
- /*} else if (this.BLE) {
509
- await this.BLEpushChanges();*/
384
+ } else if (this.BLE) {
385
+ await this.BLEpushChanges();
510
386
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
511
387
  await this.openAPIpushChanges();
512
388
  } else {
513
389
  await this.offlineOff();
514
- this.debugWarnLog(
515
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`,
516
- );
390
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
391
+ + ` ${this.device.connectionType}, pushChanges will not happen.`);
517
392
  }
518
393
  // Refresh the status from the API
519
394
  interval(15000)
@@ -526,26 +401,20 @@ export class CeilingLight {
526
401
 
527
402
  async BLEpushChanges(): Promise<void> {
528
403
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
529
- if (this.On !== this.accessory.context.On) {
530
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
404
+ if (this.LightBulb.On !== this.accessory.context.On) {
405
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
406
+ + ` BLEpushChanges On: ${this.LightBulb.On} OnCached: ${this.accessory.context.On}`);
531
407
  const switchbot = await this.platform.connectBLE();
532
408
  // Convert to BLE Address
533
- this.device.bleMac = this.device
534
- .deviceId!.match(/.{1,2}/g)!
535
- .join(':')
536
- .toLowerCase();
537
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
409
+ await this.convertBLEAddress();
538
410
  switchbot
539
- .discover({
540
- model: 'u',
541
- id: this.device.bleMac,
542
- })
411
+ .discover({ model: this.device.bleModel, id: this.device.bleMac })
543
412
  .then(async (device_list: any) => {
544
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
545
- return await this.retry({
546
- max: this.maxRetry(),
413
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
414
+ return await this.retryBLE({
415
+ max: await this.maxRetryBLE(),
547
416
  fn: async () => {
548
- if (this.On) {
417
+ if (this.LightBulb.On) {
549
418
  return await device_list[0].turnOn({ id: this.device.bleMac });
550
419
  } else {
551
420
  return await device_list[0].turnOff({ id: this.device.bleMac });
@@ -555,28 +424,28 @@ export class CeilingLight {
555
424
  })
556
425
  .then(() => {
557
426
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
558
- this.On = false;
427
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
428
+ + `On: ${this.LightBulb.On} sent over BLE, sent successfully`);
429
+ this.LightBulb.On = false;
559
430
  })
560
431
  .catch(async (e: any) => {
561
432
  this.apiError(e);
562
- this.errorLog(
563
- `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` +
564
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
565
- );
433
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
434
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
566
435
  await this.BLEPushConnection();
567
436
  });
568
437
  } else {
569
- this.debugLog(
570
- `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`,
571
- );
438
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
439
+ + ` No BLEpushChanges: On: ${this.LightBulb.On}, `
440
+ + `OnCached: ${this.accessory.context.On}`);
572
441
  }
573
442
  }
574
443
 
575
444
  async openAPIpushChanges(): Promise<void> {
576
445
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
577
- if (this.On !== this.accessory.context.On) {
446
+ if (this.LightBulb.On !== this.accessory.context.On) {
578
447
  let command = '';
579
- if (this.On) {
448
+ if (this.LightBulb.On) {
580
449
  command = 'turnOn';
581
450
  } else {
582
451
  command = 'turnOff';
@@ -588,57 +457,46 @@ export class CeilingLight {
588
457
  });
589
458
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
590
459
  try {
591
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
592
- body: bodyChange,
593
- method: 'POST',
594
- headers: this.platform.generateHeaders(),
595
- });
596
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
460
+ const { body, statusCode } = await this.pushChangeRequest(bodyChange);
597
461
  const deviceStatus: any = await body.json();
598
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
599
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
600
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
462
+ await this.pushStatusCodes(statusCode, deviceStatus);
601
463
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
602
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
603
- + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
464
+ await this.successfulPushChange(statusCode, deviceStatus, bodyChange);
465
+ await this.updateHomeKitCharacteristics();
604
466
  } else {
605
- this.statusCode(statusCode);
606
- this.statusCode(deviceStatus.statusCode);
467
+ await this.statusCode(statusCode);
468
+ await this.statusCode(deviceStatus.statusCode);
607
469
  }
608
470
  } catch (e: any) {
609
471
  this.apiError(e);
610
- this.errorLog(
611
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` +
612
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
613
- );
472
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
473
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
614
474
  }
615
475
  } else {
616
- this.debugLog(
617
- `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` +
618
- `On: ${this.On}, ` +
619
- `OnCached: ${this.accessory.context.On}`,
620
- );
476
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.`
477
+ + `On: ${this.LightBulb.On}, `
478
+ + `OnCached: ${this.accessory.context.On}`);
621
479
  }
622
480
  // Push Hue & Saturation Update
623
- if (this.On) {
481
+ if (this.LightBulb.On) {
624
482
  await this.pushHueSaturationChanges();
625
483
  }
626
484
  // Push ColorTemperature Update
627
- if (this.On) {
485
+ if (this.LightBulb.On) {
628
486
  await this.pushColorTemperatureChanges();
629
487
  }
630
488
  // Push Brightness Update
631
- if (this.On) {
489
+ if (this.LightBulb.On) {
632
490
  await this.pushBrightnessChanges();
633
491
  }
634
492
  }
635
493
 
636
494
  async pushHueSaturationChanges(): Promise<void> {
637
495
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushHueSaturationChanges`);
638
- if (this.Hue !== this.accessory.context.Hue || this.Saturation !== this.accessory.context.Saturation) {
639
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${JSON.stringify(this.Hue)}`);
640
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${JSON.stringify(this.Saturation)}`);
641
- const [red, green, blue] = hs2rgb(Number(this.Hue), Number(this.Saturation));
496
+ if (this.LightBulb.Hue !== this.accessory.context.Hue || this.LightBulb.Saturation !== this.accessory.context.Saturation) {
497
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${JSON.stringify(this.LightBulb.Hue)}`);
498
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${JSON.stringify(this.LightBulb.Saturation)}`);
499
+ const [red, green, blue] = hs2rgb(Number(this.LightBulb.Hue), Number(this.LightBulb.Saturation));
642
500
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} rgb: ${JSON.stringify([red, green, blue])}`);
643
501
  const bodyChange = JSON.stringify({
644
502
  command: 'setColor',
@@ -647,43 +505,32 @@ export class CeilingLight {
647
505
  });
648
506
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
649
507
  try {
650
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
651
- body: bodyChange,
652
- method: 'POST',
653
- headers: this.platform.generateHeaders(),
654
- });
655
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
508
+ const { body, statusCode } = await this.pushChangeRequest(bodyChange);
656
509
  const deviceStatus: any = await body.json();
657
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
658
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
659
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
510
+ await this.pushStatusCodes(statusCode, deviceStatus);
660
511
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
661
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
662
- + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
512
+ await this.successfulPushChange(statusCode, deviceStatus, bodyChange);
513
+ await this.updateHomeKitCharacteristics();
663
514
  } else {
664
- this.statusCode(statusCode);
665
- this.statusCode(deviceStatus.statusCode);
515
+ await this.statusCode(statusCode);
516
+ await this.statusCode(deviceStatus.statusCode);
666
517
  }
667
518
  } catch (e: any) {
668
519
  this.apiError(e);
669
- this.errorLog(
670
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}` +
671
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
672
- );
520
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}`
521
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
673
522
  }
674
523
  } else {
675
- this.debugLog(
676
- `${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, ` +
677
- `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`,
678
- );
524
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.LightBulb.Hue}, HueCached: `
525
+ + `${this.accessory.context.Hue}, Saturation: ${this.LightBulb.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`);
679
526
  }
680
527
  }
681
528
 
682
529
  async pushColorTemperatureChanges(): Promise<void> {
683
530
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushColorTemperatureChanges`);
684
- if (this.ColorTemperature !== this.accessory.context.ColorTemperature) {
685
- const kelvin = Math.round(1000000 / Number(this.ColorTemperature));
686
- this.cacheKelvin = kelvin;
531
+ if (this.LightBulb.ColorTemperature !== this.accessory.context.ColorTemperature) {
532
+ const kelvin = Math.round(1000000 / Number(this.LightBulb.ColorTemperature));
533
+ this.accessory.context.kelvin = kelvin;
687
534
  const bodyChange = JSON.stringify({
688
535
  command: 'setColorTemperature',
689
536
  parameter: `${kelvin}`,
@@ -691,78 +538,56 @@ export class CeilingLight {
691
538
  });
692
539
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
693
540
  try {
694
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
695
- body: bodyChange,
696
- method: 'POST',
697
- headers: this.platform.generateHeaders(),
698
- });
699
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
541
+ const { body, statusCode } = await this.pushChangeRequest(bodyChange);
700
542
  const deviceStatus: any = await body.json();
701
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
702
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
703
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
543
+ await this.pushStatusCodes(statusCode, deviceStatus);
704
544
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
705
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
706
- + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
545
+ await this.successfulPushChange(statusCode, deviceStatus, bodyChange);
546
+ await this.updateHomeKitCharacteristics();
707
547
  } else {
708
- this.statusCode(statusCode);
709
- this.statusCode(deviceStatus.statusCode);
548
+ await this.statusCode(statusCode);
549
+ await this.statusCode(deviceStatus.statusCode);
710
550
  }
711
551
  } catch (e: any) {
712
552
  this.apiError(e);
713
- this.errorLog(
714
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushColorTemperatureChanges with ${this.device.connectionType}` +
715
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
716
- );
553
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushColorTemperatureChanges with`
554
+ + ` ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`);
717
555
  }
718
556
  } else {
719
- this.debugLog(
720
- `${this.device.deviceType}: ${this.accessory.displayName} No pushColorTemperatureChanges.` +
721
- `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`,
722
- );
557
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushColorTemperatureChanges.`
558
+ + `ColorTemperature: ${this.LightBulb.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`);
723
559
  }
724
560
  }
725
561
 
726
562
  async pushBrightnessChanges(): Promise<void> {
727
563
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges`);
728
- if (this.Brightness !== this.accessory.context.Brightness) {
564
+ if (this.LightBulb.Brightness !== this.accessory.context.Brightness) {
729
565
  const bodyChange = JSON.stringify({
730
566
  command: 'setBrightness',
731
- parameter: `${this.Brightness}`,
567
+ parameter: `${this.LightBulb.Brightness}`,
732
568
  commandType: 'command',
733
569
  });
734
570
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
735
571
  try {
736
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
737
- body: bodyChange,
738
- method: 'POST',
739
- headers: this.platform.generateHeaders(),
740
- });
741
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
572
+ const { body, statusCode } = await this.pushChangeRequest(bodyChange);
742
573
  const deviceStatus: any = await body.json();
743
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
744
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
745
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
574
+ await this.pushStatusCodes(statusCode, deviceStatus);
746
575
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
747
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
748
- + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
576
+ await this.successfulPushChange(statusCode, deviceStatus, bodyChange);
577
+ await this.updateHomeKitCharacteristics();
749
578
  } else {
750
- this.statusCode(statusCode);
751
- this.statusCode(deviceStatus.statusCode);
579
+ await this.statusCode(statusCode);
580
+ await this.statusCode(deviceStatus.statusCode);
752
581
  }
753
582
  } catch (e: any) {
754
583
  this.apiError(e);
755
- this.errorLog(
756
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}` +
757
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
758
- );
584
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}`
585
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
759
586
  }
760
587
  } else {
761
- this.debugLog(
762
- `${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.` +
763
- `Brightness: ${this.Brightness}, ` +
764
- `BrightnessCached: ${this.accessory.context.Brightness}`,
765
- );
588
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.`
589
+ + `Brightness: ${this.LightBulb.Brightness}, `
590
+ + `BrightnessCached: ${this.accessory.context.Brightness}`);
766
591
  }
767
592
  }
768
593
 
@@ -770,13 +595,13 @@ export class CeilingLight {
770
595
  * Handle requests to set the value of the "On" characteristic
771
596
  */
772
597
  async OnSet(value: CharacteristicValue): Promise<void> {
773
- if (this.On === this.accessory.context.On) {
598
+ if (this.LightBulb.On === this.accessory.context.On) {
774
599
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set On: ${value}`);
775
600
  } else {
776
601
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
777
602
  }
778
603
 
779
- this.On = value;
604
+ this.LightBulb.On = value;
780
605
  this.doCeilingLightUpdate.next();
781
606
  }
782
607
 
@@ -784,15 +609,15 @@ export class CeilingLight {
784
609
  * Handle requests to set the value of the "Brightness" characteristic
785
610
  */
786
611
  async BrightnessSet(value: CharacteristicValue): Promise<void> {
787
- if (this.Brightness === this.accessory.context.Brightness) {
612
+ if (this.LightBulb.Brightness === this.accessory.context.Brightness) {
788
613
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set Brightness: ${value}`);
789
- } else if (this.On) {
614
+ } else if (this.LightBulb.On) {
790
615
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Brightness: ${value}`);
791
616
  } else {
792
617
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Brightness: ${value}`);
793
618
  }
794
619
 
795
- this.Brightness = value;
620
+ this.LightBulb.Brightness = value;
796
621
  this.doCeilingLightUpdate.next();
797
622
  }
798
623
 
@@ -800,30 +625,32 @@ export class CeilingLight {
800
625
  * Handle requests to set the value of the "ColorTemperature" characteristic
801
626
  */
802
627
  async ColorTemperatureSet(value: CharacteristicValue): Promise<void> {
803
- if (this.ColorTemperature === this.accessory.context.ColorTemperature) {
628
+ if (this.LightBulb.ColorTemperature === this.accessory.context.ColorTemperature) {
804
629
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set ColorTemperature: ${value}`);
805
- } else if (this.On) {
630
+ } else if (this.LightBulb.On) {
806
631
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set ColorTemperature: ${value}`);
807
632
  } else {
808
633
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Set ColorTemperature: ${value}`);
809
634
  }
810
635
 
636
+ const minKelvin = 2000;
637
+ const maxKelvin = 9000;
811
638
  // Convert mired to kelvin to nearest 100 (SwitchBot seems to need this)
812
639
  const kelvin = Math.round(1000000 / Number(value) / 100) * 100;
813
640
 
814
641
  // Check and increase/decrease kelvin to range of device
815
- const k = Math.min(Math.max(kelvin, this.minKelvin), this.maxKelvin);
642
+ const k = Math.min(Math.max(kelvin, minKelvin), maxKelvin);
816
643
 
817
- if (!this.accessory.context.On || this.cacheKelvin === k) {
644
+ if (!this.accessory.context.On || this.accessory.context.kelvin === k) {
818
645
  return;
819
646
  }
820
647
 
821
648
  // Updating the hue/sat to the corresponding values mimics native adaptive lighting
822
649
  const hs = m2hs(value);
823
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.Hue, hs[0]);
824
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.Saturation, hs[1]);
650
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.Hue, hs[0]);
651
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.Saturation, hs[1]);
825
652
 
826
- this.ColorTemperature = value;
653
+ this.LightBulb.ColorTemperature = value;
827
654
  this.doCeilingLightUpdate.next();
828
655
  }
829
656
 
@@ -831,17 +658,17 @@ export class CeilingLight {
831
658
  * Handle requests to set the value of the "Hue" characteristic
832
659
  */
833
660
  async HueSet(value: CharacteristicValue): Promise<void> {
834
- if (this.Hue === this.accessory.context.Hue) {
661
+ if (this.LightBulb.Hue === this.accessory.context.Hue) {
835
662
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set Hue: ${value}`);
836
- } else if (this.On) {
663
+ } else if (this.LightBulb.On) {
837
664
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Hue: ${value}`);
838
665
  } else {
839
666
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Hue: ${value}`);
840
667
  }
841
668
 
842
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.ColorTemperature, 140);
669
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.ColorTemperature, 140);
843
670
 
844
- this.Hue = value;
671
+ this.LightBulb.Hue = value;
845
672
  this.doCeilingLightUpdate.next();
846
673
  }
847
674
 
@@ -849,55 +676,56 @@ export class CeilingLight {
849
676
  * Handle requests to set the value of the "Saturation" characteristic
850
677
  */
851
678
  async SaturationSet(value: CharacteristicValue): Promise<void> {
852
- if (this.Saturation === this.accessory.context.Saturation) {
679
+ if (this.LightBulb.Saturation === this.accessory.context.Saturation) {
853
680
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set Saturation: ${value}`);
854
- } else if (this.On) {
681
+ } else if (this.LightBulb.On) {
855
682
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Saturation: ${value}`);
856
683
  } else {
857
684
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Saturation: ${value}`);
858
685
  }
859
686
 
860
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.ColorTemperature, 140);
687
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.ColorTemperature, 140);
861
688
 
862
- this.Saturation = value;
689
+ this.LightBulb.Saturation = value;
863
690
  this.doCeilingLightUpdate.next();
864
691
  }
865
692
 
866
693
  async updateHomeKitCharacteristics(): Promise<void> {
867
- if (this.On === undefined) {
868
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
694
+ if (this.LightBulb.On === undefined) {
695
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LightBulb.On}`);
869
696
  } else {
870
- this.accessory.context.On = this.On;
871
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.On, this.On);
872
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
697
+ this.accessory.context.On = this.LightBulb.On;
698
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.On, this.LightBulb.On);
699
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.LightBulb.On}`);
873
700
  }
874
- if (this.Brightness === undefined) {
875
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
701
+ if (this.LightBulb.Brightness === undefined) {
702
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.LightBulb.Brightness}`);
876
703
  } else {
877
- this.accessory.context.Brightness = this.Brightness;
878
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.Brightness, this.Brightness);
879
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Brightness: ${this.Brightness}`);
704
+ this.accessory.context.Brightness = this.LightBulb.Brightness;
705
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.Brightness, this.LightBulb.Brightness);
706
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Brightness: ${this.LightBulb.Brightness}`);
880
707
  }
881
- if (this.ColorTemperature === undefined) {
882
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ColorTemperature: ${this.ColorTemperature}`);
708
+ if (this.LightBulb.ColorTemperature === undefined) {
709
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ColorTemperature: ${this.LightBulb.ColorTemperature}`);
883
710
  } else {
884
- this.accessory.context.ColorTemperature = this.ColorTemperature;
885
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.ColorTemperature, this.ColorTemperature);
886
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic ColorTemperature: ${this.ColorTemperature}`);
711
+ this.accessory.context.ColorTemperature = this.LightBulb.ColorTemperature;
712
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.ColorTemperature, this.LightBulb.ColorTemperature);
713
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
714
+ + ` updateCharacteristic ColorTemperature: ${this.LightBulb.ColorTemperature}`);
887
715
  }
888
- if (this.Hue === undefined) {
889
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${this.Hue}`);
716
+ if (this.LightBulb.Hue === undefined) {
717
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${this.LightBulb.Hue}`);
890
718
  } else {
891
- this.accessory.context.Hue = this.Hue;
892
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.Hue, this.Hue);
893
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Hue: ${this.Hue}`);
719
+ this.accessory.context.Hue = this.LightBulb.Hue;
720
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.Hue, this.LightBulb.Hue);
721
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Hue: ${this.LightBulb.Hue}`);
894
722
  }
895
- if (this.Saturation === undefined) {
896
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${this.Saturation}`);
723
+ if (this.LightBulb.Saturation === undefined) {
724
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${this.LightBulb.Saturation}`);
897
725
  } else {
898
- this.accessory.context.Saturation = this.Saturation;
899
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.Saturation, this.Saturation);
900
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Saturation: ${this.Saturation}`);
726
+ this.accessory.context.Saturation = this.LightBulb.Saturation;
727
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.Saturation, this.LightBulb.Saturation);
728
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Saturation: ${this.LightBulb.Saturation}`);
901
729
  }
902
730
  }
903
731
 
@@ -911,35 +739,6 @@ export class CeilingLight {
911
739
  }
912
740
  }
913
741
 
914
- async stopScanning(switchbot: any) {
915
- switchbot.stopScan();
916
- if (this.BLE_IsConnected) {
917
- await this.BLEparseStatus();
918
- await this.updateHomeKitCharacteristics();
919
- } else {
920
- await this.BLERefreshConnection(switchbot);
921
- }
922
- }
923
-
924
- async getCustomBLEAddress(switchbot: any) {
925
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
926
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} customBLEaddress: ${this.device.customBLEaddress}`);
927
- (async () => {
928
- // Start to monitor advertisement packets
929
- await switchbot.startScan({
930
- model: 'u',
931
- });
932
- // Set an event handler
933
- switchbot.onadvertisement = (ad: any) => {
934
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
935
- };
936
- await sleep(10000);
937
- // Stop to monitor
938
- switchbot.stopScan();
939
- })();
940
- }
941
- }
942
-
943
742
  async BLEPushConnection() {
944
743
  if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
945
744
  this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Push Changes`);
@@ -956,284 +755,17 @@ export class CeilingLight {
956
755
  }
957
756
  }
958
757
 
959
- async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
960
- return fn().catch(async (e: any) => {
961
- if (max === 0) {
962
- throw e;
963
- }
964
- this.infoLog(e);
965
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Retrying`);
966
- await sleep(1000);
967
- return this.retry({ max: max - 1, fn });
968
- });
969
- }
970
-
971
- maxRetry(): number {
972
- if (this.device.maxRetry) {
973
- return this.device.maxRetry;
974
- } else {
975
- return 5;
976
- }
977
- }
978
-
979
- minStep(device: device & devicesConfig): number {
980
- if (device.ceilinglight?.set_minStep) {
981
- this.set_minStep = device.ceilinglight?.set_minStep;
982
- } else {
983
- this.set_minStep = 1;
984
- }
985
- return this.set_minStep;
986
- }
987
-
988
- async scan(device: device & devicesConfig): Promise<void> {
989
- if (device.scanDuration) {
990
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
991
- if (this.BLE) {
992
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
993
- }
994
- } else {
995
- this.scanDuration = this.accessory.context.scanDuration = 1;
996
- if (this.BLE) {
997
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
998
- }
999
- }
1000
- }
1001
-
1002
- async statusCode(statusCode: number): Promise<void> {
1003
- switch (statusCode) {
1004
- case 151:
1005
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
1006
- break;
1007
- case 152:
1008
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
1009
- break;
1010
- case 160:
1011
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
1012
- break;
1013
- case 161:
1014
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
1015
- this.offlineOff();
1016
- break;
1017
- case 171:
1018
- this.errorLog(
1019
- `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` +
1020
- `Hub: ${this.device.hubDeviceId}`,
1021
- );
1022
- this.offlineOff();
1023
- break;
1024
- case 190:
1025
- this.errorLog(
1026
- `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
1027
- ` Or command format is invalid, statusCode: ${statusCode}`,
1028
- );
1029
- break;
1030
- case 100:
1031
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
1032
- break;
1033
- case 200:
1034
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
1035
- break;
1036
- case 400:
1037
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bad Request, The client has issued an invalid request. `
1038
- + `This is commonly used to specify validation errors in a request payload, statusCode: ${statusCode}`);
1039
- break;
1040
- case 401:
1041
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unauthorized, Authorization for the API is required, `
1042
- + `but the request has not been authenticated, statusCode: ${statusCode}`);
1043
- break;
1044
- case 403:
1045
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Forbidden, The request has been authenticated but does not `
1046
- + `have appropriate permissions, or a requested resource is not found, statusCode: ${statusCode}`);
1047
- break;
1048
- case 404:
1049
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Found, Specifies the requested path does not exist, `
1050
- + `statusCode: ${statusCode}`);
1051
- break;
1052
- case 406:
1053
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Acceptable, The client has requested a MIME type via `
1054
- + `the Accept header for a value not supported by the server, statusCode: ${statusCode}`);
1055
- break;
1056
- case 415:
1057
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unsupported Media Type, The client has defined a contentType `
1058
- + `header that is not supported by the server, statusCode: ${statusCode}`);
1059
- break;
1060
- case 422:
1061
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unprocessable Entity, The client has made a valid request, `
1062
- + `but the server cannot process it. This is often used for APIs for which certain limits have been exceeded, statusCode: ${statusCode}`);
1063
- break;
1064
- case 429:
1065
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Too Many Requests, The client has exceeded the number of `
1066
- + `requests allowed for a given time window, statusCode: ${statusCode}`);
1067
- break;
1068
- case 500:
1069
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Internal Server Error, An unexpected error on the SmartThings `
1070
- + `servers has occurred. These errors should be rare, statusCode: ${statusCode}`);
1071
- break;
1072
- default:
1073
- this.infoLog(
1074
- `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` +
1075
- `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`,
1076
- );
1077
- }
1078
- }
1079
-
1080
758
  async offlineOff(): Promise<void> {
1081
759
  if (this.device.offline) {
1082
- await this.deviceContext();
1083
- await this.updateHomeKitCharacteristics();
760
+ this.LightBulb.Service.updateCharacteristic(this.hap.Characteristic.On, false);
1084
761
  }
1085
762
  }
1086
763
 
1087
764
  apiError(e: any): void {
1088
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.On, e);
1089
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.Hue, e);
1090
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.Brightness, e);
1091
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.Saturation, e);
1092
- this.lightBulbService.updateCharacteristic(this.hap.Characteristic.ColorTemperature, e);
1093
- }
1094
-
1095
- async deviceContext() {
1096
- if (this.On === undefined) {
1097
- this.On = false;
1098
- } else {
1099
- this.On = this.accessory.context.On;
1100
- }
1101
- if (this.Hue === undefined) {
1102
- this.Hue = 0;
1103
- } else {
1104
- this.Hue = this.accessory.context.Hue;
1105
- }
1106
- if (this.Brightness === undefined) {
1107
- this.Brightness = 0;
1108
- } else {
1109
- this.Brightness = this.accessory.context.Brightness;
1110
- }
1111
- if (this.Brightness === undefined) {
1112
- this.Saturation = 0;
1113
- } else {
1114
- this.Saturation = this.accessory.context.Saturation;
1115
- }
1116
- if (this.ColorTemperature === undefined) {
1117
- this.ColorTemperature = 140;
1118
- } else {
1119
- this.ColorTemperature = this.accessory.context.ColorTemperature;
1120
- }
1121
- this.minKelvin = 2000;
1122
- this.maxKelvin = 9000;
1123
- if (this.FirmwareRevision === undefined) {
1124
- this.FirmwareRevision = this.platform.version;
1125
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
1126
- }
1127
- }
1128
-
1129
- async refreshRate(device: device & devicesConfig): Promise<void> {
1130
- if (device.refreshRate) {
1131
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
1132
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
1133
- } else if (this.platform.config.options!.refreshRate) {
1134
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
1135
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
1136
- }
1137
- }
1138
-
1139
- async deviceConfig(device: device & devicesConfig): Promise<void> {
1140
- let config = {};
1141
- if (device.ceilinglight) {
1142
- config = device.ceilinglight;
1143
- }
1144
- if (device.connectionType !== undefined) {
1145
- config['connectionType'] = device.connectionType;
1146
- }
1147
- if (device.external !== undefined) {
1148
- config['external'] = device.external;
1149
- }
1150
- if (device.logging !== undefined) {
1151
- config['logging'] = device.logging;
1152
- }
1153
- if (device.refreshRate !== undefined) {
1154
- config['refreshRate'] = device.refreshRate;
1155
- }
1156
- if (device.scanDuration !== undefined) {
1157
- config['scanDuration'] = device.scanDuration;
1158
- }
1159
- if (device.offline !== undefined) {
1160
- config['offline'] = device.offline;
1161
- }
1162
- if (device.maxRetry !== undefined) {
1163
- config['maxRetry'] = device.maxRetry;
1164
- }
1165
- if (device.webhook !== undefined) {
1166
- config['webhook'] = device.webhook;
1167
- }
1168
- if (Object.entries(config).length !== 0) {
1169
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
1170
- }
1171
- }
1172
-
1173
- async deviceLogs(device: device & devicesConfig): Promise<void> {
1174
- if (this.platform.debugMode) {
1175
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
1176
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
1177
- } else if (device.logging) {
1178
- this.deviceLogging = this.accessory.context.logging = device.logging;
1179
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
1180
- } else if (this.platform.config.options?.logging) {
1181
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
1182
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
1183
- } else {
1184
- this.deviceLogging = this.accessory.context.logging = 'standard';
1185
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
1186
- }
1187
- }
1188
-
1189
- /**
1190
- * Logging for Device
1191
- */
1192
- infoLog(...log: any[]): void {
1193
- if (this.enablingDeviceLogging()) {
1194
- this.platform.log.info(String(...log));
1195
- }
1196
- }
1197
-
1198
- warnLog(...log: any[]): void {
1199
- if (this.enablingDeviceLogging()) {
1200
- this.platform.log.warn(String(...log));
1201
- }
1202
- }
1203
-
1204
- debugWarnLog(...log: any[]): void {
1205
- if (this.enablingDeviceLogging()) {
1206
- if (this.deviceLogging?.includes('debug')) {
1207
- this.platform.log.warn('[DEBUG]', String(...log));
1208
- }
1209
- }
1210
- }
1211
-
1212
- errorLog(...log: any[]): void {
1213
- if (this.enablingDeviceLogging()) {
1214
- this.platform.log.error(String(...log));
1215
- }
1216
- }
1217
-
1218
- debugErrorLog(...log: any[]): void {
1219
- if (this.enablingDeviceLogging()) {
1220
- if (this.deviceLogging?.includes('debug')) {
1221
- this.platform.log.error('[DEBUG]', String(...log));
1222
- }
1223
- }
1224
- }
1225
-
1226
- debugLog(...log: any[]): void {
1227
- if (this.enablingDeviceLogging()) {
1228
- if (this.deviceLogging === 'debug') {
1229
- this.platform.log.info('[DEBUG]', String(...log));
1230
- } else {
1231
- this.platform.log.debug(String(...log));
1232
- }
1233
- }
1234
- }
1235
-
1236
- enablingDeviceLogging(): boolean {
1237
- return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
765
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.On, e);
766
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.Hue, e);
767
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.Brightness, e);
768
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.Saturation, e);
769
+ this.LightBulb!.Service.updateCharacteristic(this.hap.Characteristic.ColorTemperature, e);
1238
770
  }
1239
771
  }