@switchbot/homebridge-switchbot 2.0.0-beta.2 → 2.0.0-beta.21

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 (113) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/README.md +1 -2
  3. package/config.schema.json +75 -20
  4. package/dist/device/bot.d.ts +32 -28
  5. package/dist/device/bot.d.ts.map +1 -1
  6. package/dist/device/bot.js +646 -648
  7. package/dist/device/bot.js.map +1 -1
  8. package/dist/device/colorbulb.d.ts +34 -19
  9. package/dist/device/colorbulb.d.ts.map +1 -1
  10. package/dist/device/colorbulb.js +429 -304
  11. package/dist/device/colorbulb.js.map +1 -1
  12. package/dist/device/contact.d.ts +16 -7
  13. package/dist/device/contact.d.ts.map +1 -1
  14. package/dist/device/contact.js +288 -230
  15. package/dist/device/contact.js.map +1 -1
  16. package/dist/device/curtain.d.ts +21 -16
  17. package/dist/device/curtain.d.ts.map +1 -1
  18. package/dist/device/curtain.js +519 -489
  19. package/dist/device/curtain.js.map +1 -1
  20. package/dist/device/humidifier.d.ts +22 -18
  21. package/dist/device/humidifier.d.ts.map +1 -1
  22. package/dist/device/humidifier.js +415 -360
  23. package/dist/device/humidifier.js.map +1 -1
  24. package/dist/device/lock.d.ts +22 -8
  25. package/dist/device/lock.d.ts.map +1 -1
  26. package/dist/device/lock.js +253 -147
  27. package/dist/device/lock.js.map +1 -1
  28. package/dist/device/meter.d.ts +21 -16
  29. package/dist/device/meter.d.ts.map +1 -1
  30. package/dist/device/meter.js +325 -255
  31. package/dist/device/meter.js.map +1 -1
  32. package/dist/device/meterplus.d.ts +23 -12
  33. package/dist/device/meterplus.d.ts.map +1 -1
  34. package/dist/device/meterplus.js +346 -208
  35. package/dist/device/meterplus.js.map +1 -1
  36. package/dist/device/motion.d.ts +17 -8
  37. package/dist/device/motion.d.ts.map +1 -1
  38. package/dist/device/motion.js +261 -209
  39. package/dist/device/motion.js.map +1 -1
  40. package/dist/device/plug.d.ts +24 -16
  41. package/dist/device/plug.d.ts.map +1 -1
  42. package/dist/device/plug.js +267 -242
  43. package/dist/device/plug.js.map +1 -1
  44. package/dist/device/striplight.d.ts +51 -16
  45. package/dist/device/striplight.d.ts.map +1 -1
  46. package/dist/device/striplight.js +527 -185
  47. package/dist/device/striplight.js.map +1 -1
  48. package/dist/irdevice/airconditioner.d.ts +7 -12
  49. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  50. package/dist/irdevice/airconditioner.js +261 -230
  51. package/dist/irdevice/airconditioner.js.map +1 -1
  52. package/dist/irdevice/airpurifier.d.ts +3 -3
  53. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  54. package/dist/irdevice/airpurifier.js +137 -104
  55. package/dist/irdevice/airpurifier.js.map +1 -1
  56. package/dist/irdevice/camera.d.ts +9 -8
  57. package/dist/irdevice/camera.d.ts.map +1 -1
  58. package/dist/irdevice/camera.js +116 -86
  59. package/dist/irdevice/camera.js.map +1 -1
  60. package/dist/irdevice/fan.d.ts +8 -7
  61. package/dist/irdevice/fan.d.ts.map +1 -1
  62. package/dist/irdevice/fan.js +143 -109
  63. package/dist/irdevice/fan.js.map +1 -1
  64. package/dist/irdevice/light.d.ts +9 -8
  65. package/dist/irdevice/light.d.ts.map +1 -1
  66. package/dist/irdevice/light.js +120 -103
  67. package/dist/irdevice/light.js.map +1 -1
  68. package/dist/irdevice/other.d.ts +9 -8
  69. package/dist/irdevice/other.d.ts.map +1 -1
  70. package/dist/irdevice/other.js +128 -98
  71. package/dist/irdevice/other.js.map +1 -1
  72. package/dist/irdevice/tv.d.ts +10 -9
  73. package/dist/irdevice/tv.d.ts.map +1 -1
  74. package/dist/irdevice/tv.js +126 -93
  75. package/dist/irdevice/tv.js.map +1 -1
  76. package/dist/irdevice/vacuumcleaner.d.ts +7 -10
  77. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  78. package/dist/irdevice/vacuumcleaner.js +115 -89
  79. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  80. package/dist/irdevice/waterheater.d.ts +6 -9
  81. package/dist/irdevice/waterheater.d.ts.map +1 -1
  82. package/dist/irdevice/waterheater.js +115 -89
  83. package/dist/irdevice/waterheater.js.map +1 -1
  84. package/dist/platform.d.ts +5 -5
  85. package/dist/platform.d.ts.map +1 -1
  86. package/dist/platform.js +227 -199
  87. package/dist/platform.js.map +1 -1
  88. package/dist/settings.d.ts +15 -11
  89. package/dist/settings.d.ts.map +1 -1
  90. package/dist/settings.js.map +1 -1
  91. package/package.json +12 -10
  92. package/src/device/bot.ts +641 -657
  93. package/src/device/colorbulb.ts +440 -339
  94. package/src/device/contact.ts +289 -233
  95. package/src/device/curtain.ts +523 -503
  96. package/src/device/humidifier.ts +421 -396
  97. package/src/device/lock.ts +257 -147
  98. package/src/device/meter.ts +335 -268
  99. package/src/device/meterplus.ts +354 -213
  100. package/src/device/motion.ts +264 -213
  101. package/src/device/plug.ts +270 -251
  102. package/src/device/striplight.ts +552 -207
  103. package/src/irdevice/airconditioner.ts +263 -241
  104. package/src/irdevice/airpurifier.ts +132 -103
  105. package/src/irdevice/camera.ts +112 -85
  106. package/src/irdevice/fan.ts +138 -106
  107. package/src/irdevice/light.ts +116 -103
  108. package/src/irdevice/other.ts +124 -97
  109. package/src/irdevice/tv.ts +123 -93
  110. package/src/irdevice/vacuumcleaner.ts +112 -89
  111. package/src/irdevice/waterheater.ts +111 -89
  112. package/src/platform.ts +216 -214
  113. package/src/settings.ts +15 -11
@@ -3,10 +3,11 @@ import crypto from 'crypto';
3
3
  import { Context } from 'vm';
4
4
  import { IncomingMessage } from 'http';
5
5
  import { interval, Subject } from 'rxjs';
6
+ import superStringify from 'super-stringify';
6
7
  import { SwitchBotPlatform } from '../platform';
7
- import { debounceTime, skipWhile, tap } from 'rxjs/operators';
8
+ import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
8
9
  import { Service, PlatformAccessory, CharacteristicValue, ControllerConstructor, Controller, ControllerServiceMap } from 'homebridge';
9
- import { device, devicesConfig, switchbot, hs2rgb, rgb2hs, deviceStatus, HostDomain, DevicePath } from '../settings';
10
+ import { device, devicesConfig, switchbot, hs2rgb, rgb2hs, deviceStatus, HostDomain, DevicePath, ad, serviceData } from '../settings';
10
11
 
11
12
  /**
12
13
  * Platform Accessory
@@ -19,13 +20,10 @@ export class StripLight {
19
20
 
20
21
  // Characteristic Values
21
22
  On!: CharacteristicValue;
22
- OnCached!: CharacteristicValue;
23
23
  Hue!: CharacteristicValue;
24
- HueCached!: CharacteristicValue;
25
24
  Saturation!: CharacteristicValue;
26
- SaturationCached!: CharacteristicValue;
27
25
  Brightness!: CharacteristicValue;
28
- BrightnessCached!: CharacteristicValue;
26
+ ColorTemperature?: CharacteristicValue;
29
27
 
30
28
  // OpenAPI Others
31
29
  power: deviceStatus['power'];
@@ -34,10 +32,18 @@ export class StripLight {
34
32
  deviceStatus!: any; //deviceStatusResponse;
35
33
 
36
34
  // BLE Others
35
+ connected?: boolean;
37
36
  switchbot!: switchbot;
37
+ address!: ad['address'];
38
+ SwitchToOpenAPI?: boolean;
39
+ serviceData!: serviceData;
40
+ state: serviceData['state'];
41
+ delay: serviceData['delay'];
42
+ wifiRssi: serviceData['wifiRssi'];
38
43
 
39
44
  // Config
40
45
  set_minStep?: number;
46
+ scanDuration!: number;
41
47
  deviceLogging!: string;
42
48
  deviceRefreshRate!: number;
43
49
  adaptiveLightingShift?: number;
@@ -51,27 +57,23 @@ export class StripLight {
51
57
  cacheKelvin!: number;
52
58
 
53
59
  // Updates
54
- colorBulbUpdateInProgress!: boolean;
55
- doColorBulbUpdate!: Subject<void>;
60
+ stripLightUpdateInProgress!: boolean;
61
+ doStripLightUpdate!: Subject<void>;
62
+
63
+ // Connection
64
+ private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'Both');
65
+ private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'Both');
56
66
 
57
67
  constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
58
68
  // default placeholders
59
69
  this.logs(device);
70
+ this.scan(device);
60
71
  this.refreshRate(device);
61
72
  this.config(device);
62
- if (this.On === undefined) {
63
- this.On = false;
64
- } else {
65
- this.On = this.accessory.context.On;
66
- }
67
- this.Hue = 0;
68
- this.Brightness = 0;
69
- this.Saturation = 0;
70
- this.minKelvin = 2000;
71
- this.maxKelvin = 9000;
73
+ this.context();
72
74
  // this is subject we use to track when we need to POST changes to the SwitchBot API
73
- this.doColorBulbUpdate = new Subject();
74
- this.colorBulbUpdateInProgress = false;
75
+ this.doStripLightUpdate = new Subject();
76
+ this.stripLightUpdateInProgress = false;
75
77
 
76
78
  // Retrieve initial values and updateHomekit
77
79
  this.refreshStatus();
@@ -89,7 +91,15 @@ export class StripLight {
89
91
  // get the Lightbulb service if it exists, otherwise create a new Lightbulb service
90
92
  // you can create multiple services for each accessory
91
93
  (this.lightBulbService = accessory.getService(this.platform.Service.Lightbulb) || accessory.addService(this.platform.Service.Lightbulb)),
92
- `${accessory.displayName} Strip Light`;
94
+ `${accessory.displayName} ${device.deviceType}`;
95
+
96
+
97
+ /*if (this.adaptiveLightingShift === -1 && this.accessory.context.adaptiveLighting) {
98
+ this.accessory.removeService(this.lightBulbService);
99
+ this.lightBulbService = this.accessory.addService(this.platform.Service.Lightbulb);
100
+ this.accessory.context.adaptiveLighting = false;
101
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} adaptiveLighting: ${this.accessory.context.adaptiveLighting}`);
102
+ }*/
93
103
 
94
104
  // To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
95
105
  // when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
@@ -142,22 +152,35 @@ export class StripLight {
142
152
  })
143
153
  .onSet(this.SaturationSet.bind(this));
144
154
 
155
+ /*this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} adaptiveLightingShift: ${this.adaptiveLightingShift}`);
156
+ if (this.adaptiveLightingShift !== -1) {
157
+ this.AdaptiveLightingController = new platform.api.hap.AdaptiveLightingController(this.lightBulbService, {
158
+ customTemperatureAdjustment: this.adaptiveLightingShift,
159
+ });
160
+ this.accessory.configureController(this.AdaptiveLightingController);
161
+ this.accessory.context.adaptiveLighting = true;
162
+ this.debugLog(
163
+ `${this.device.deviceType}: ${this.accessory.displayName} adaptiveLighting: ${this.accessory.context.adaptiveLighting},` +
164
+ ` adaptiveLightingShift: ${this.adaptiveLightingShift}`,
165
+ );
166
+ }*/
167
+
145
168
  // Update Homekit
146
169
  this.updateHomeKitCharacteristics();
147
170
 
148
171
  // Start an update interval
149
172
  interval(this.deviceRefreshRate * 1000)
150
- .pipe(skipWhile(() => this.colorBulbUpdateInProgress))
173
+ .pipe(skipWhile(() => this.stripLightUpdateInProgress))
151
174
  .subscribe(async () => {
152
175
  await this.refreshStatus();
153
176
  });
154
177
 
155
178
  // Watch for Bulb change events
156
- // We put in a debounce of 100ms so we don't make duplicate calls
157
- this.doColorBulbUpdate
179
+ // We put in a debounce of 1000ms so we don't make duplicate calls
180
+ this.doStripLightUpdate
158
181
  .pipe(
159
182
  tap(() => {
160
- this.colorBulbUpdateInProgress = true;
183
+ this.stripLightUpdateInProgress = true;
161
184
  }),
162
185
  debounceTime(this.platform.config.options!.pushRate! * 1000),
163
186
  )
@@ -165,17 +188,51 @@ export class StripLight {
165
188
  try {
166
189
  await this.pushChanges();
167
190
  } catch (e: any) {
168
- this.errorLog(`Strip Light: ${this.accessory.displayName} failed pushChanges`);
169
- if (this.deviceLogging.includes('debug')) {
170
- this.errorLog(`Strip Light: ${this.accessory.displayName} failed pushChanges,` + ` Error Message: ${JSON.stringify(e.message)}`);
171
- }
172
191
  this.apiError(e);
192
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
193
+ + ` Error Message: ${superStringify(e.message)}`);
173
194
  }
174
- this.colorBulbUpdateInProgress = false;
195
+ this.stripLightUpdateInProgress = false;
196
+ // Refresh the status from the API
197
+ interval(15000)
198
+ .pipe(skipWhile(() => this.stripLightUpdateInProgress))
199
+ .pipe(take(1))
200
+ .subscribe(async () => {
201
+ await this.refreshStatus();
202
+ });
175
203
  });
176
204
  }
177
205
 
206
+ /**
207
+ * Parse the device status from the SwitchBot api
208
+ */
178
209
  async parseStatus(): Promise<void> {
210
+ /*if (this.BLE && !this.SwitchToOpenAPI) {
211
+ await this.BLEparseStatus();
212
+ } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) {
213
+ this.SwitchToOpenAPI = false;
214
+ await this.openAPIparseStatus();
215
+ } else {
216
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
217
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
218
+ }
219
+ }
220
+
221
+ async BLEparseStatus(): Promise<void> {
222
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
223
+ // State
224
+ switch (this.state) {
225
+ case 'on':
226
+ this.On = true;
227
+ break;
228
+ default:
229
+ this.On = false;
230
+ }
231
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
232
+ }
233
+
234
+ async openAPIparseStatus(): Promise<void> {
235
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
179
236
  switch (this.power) {
180
237
  case 'on':
181
238
  this.On = true;
@@ -183,41 +240,132 @@ export class StripLight {
183
240
  default:
184
241
  this.On = false;
185
242
  }
186
- this.debugLog(`Strip Light: ${this.accessory.displayName} On: ${this.On}`);
243
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
187
244
 
188
245
  // Brightness
189
246
  this.Brightness = Number(this.brightness);
190
- this.debugLog(`Strip Light: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
247
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
191
248
 
192
249
  // Color, Hue & Brightness
193
250
  if (this.color) {
194
- this.debugLog(`Strip Light: ${this.accessory.displayName} color: ${JSON.stringify(this.color)}`);
251
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} color: ${superStringify(this.color)}`);
195
252
  const [red, green, blue] = this.color!.split(':');
196
- this.debugLog(`Strip Light: ${this.accessory.displayName} red: ${JSON.stringify(red)}`);
197
- this.debugLog(`Strip Light: ${this.accessory.displayName} green: ${JSON.stringify(green)}`);
198
- this.debugLog(`Strip Light: ${this.accessory.displayName} blue: ${JSON.stringify(blue)}`);
253
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} red: ${superStringify(red)}`);
254
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} green: ${superStringify(green)}`);
255
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${superStringify(blue)}`);
199
256
 
200
257
  const [hue, saturation] = rgb2hs(Number(red), Number(green), Number(blue));
201
- this.debugLog(`Strip Light: ${this.accessory.displayName} hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`);
258
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
259
+ +` hs: ${superStringify(rgb2hs(Number(red), Number(green), Number(blue)))}`);
202
260
 
203
261
  // Hue
204
262
  this.Hue = hue;
205
- this.debugLog(`Strip Light: ${this.accessory.displayName} Hue: ${this.Hue}`);
263
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${this.Hue}`);
206
264
 
207
265
  // Saturation
208
266
  this.Saturation = saturation;
209
- this.debugLog(`Strip Light: ${this.accessory.displayName} Saturation: ${this.Saturation}`);
267
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${this.Saturation}`);
210
268
  }
211
269
  }
212
270
 
271
+ /**
272
+ * Asks the SwitchBot API for the latest device information
273
+ */
213
274
  async refreshStatus(): Promise<void> {
275
+ /*if (this.BLE) {
276
+ await this.BLERefreshStatus();
277
+ } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) {
278
+ await this.openAPIRefreshStatus();
279
+ } else {
280
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
281
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
282
+ }
283
+ }
284
+
285
+ async BLERefreshStatus(): Promise<void> {
286
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
287
+ const switchbot = await this.platform.connectBLE();
288
+ // Convert to BLE Address
289
+ this.device.bleMac = this.device
290
+ .deviceId!.match(/.{1,2}/g)!
291
+ .join(':')
292
+ .toLowerCase();
293
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
294
+ this.getCustomBLEAddress(switchbot);
295
+ // Start to monitor advertisement packets
296
+ if (switchbot !== false) {
297
+ switchbot
298
+ .startScan({
299
+ model: 'r',
300
+ id: this.device.bleMac,
301
+ })
302
+ .then(() => {
303
+ // Set an event hander
304
+ switchbot.onadvertisement = (ad: any) => {
305
+ this.address = ad.address;
306
+ if (this.deviceLogging.includes('debug')) {
307
+ this.infoLog(this.address);
308
+ this.infoLog(this.device.bleMac);
309
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address Found: ${this.address}`);
310
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac}`);
311
+ }
312
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
313
+ this.serviceData = ad.serviceData;
314
+ //this.state = ad.serviceData.state;
315
+ //this.delay = ad.serviceData.delay;
316
+ //this.timer = ad.serviceData.timer;
317
+ //this.syncUtcTime = ad.serviceData.syncUtcTime;
318
+ //this.wifiRssi = ad.serviceData.wifiRssi;
319
+ //this.overload = ad.serviceData.overload;
320
+ //this.currentPower = ad.serviceData.currentPower;
321
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
322
+ /*this.debugLog(
323
+ `${this.device.deviceType}: ${this.accessory.displayName} state: ${ad.serviceData.state}, ` +
324
+ `delay: ${ad.serviceData.delay}, timer: ${ad.serviceData.timer}, syncUtcTime: ${ad.serviceData.syncUtcTime} ` +
325
+ `wifiRssi: ${ad.serviceData.wifiRssi}, overload: ${ad.serviceData.overload}, currentPower: ${ad.serviceData.currentPower}`,
326
+ );*/
327
+
328
+ if (this.serviceData) {
329
+ this.connected = true;
330
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
331
+ } else {
332
+ this.connected = false;
333
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
334
+ }
335
+ };
336
+ // Wait 2 seconds
337
+ return switchbot.wait(this.scanDuration * 1000);
338
+ })
339
+ .then(async () => {
340
+ // Stop to monitor
341
+ switchbot.stopScan();
342
+ if (this.connected) {
343
+ this.parseStatus();
344
+ this.updateHomeKitCharacteristics();
345
+ } else {
346
+ await this.BLEconnection(switchbot);
347
+ }
348
+ })
349
+ .catch(async (e: any) => {
350
+ this.apiError(e);
351
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
352
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
353
+ await this.BLEconnection(switchbot);
354
+ });
355
+ } else {
356
+ await this.BLEconnection(switchbot);
357
+ }
358
+ }
359
+
360
+ async openAPIRefreshStatus(): Promise<void> {
361
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
214
362
  try {
215
363
  const t = Date.now();
216
364
  const nonce = 'requestID';
217
365
  const data = this.platform.config.credentials?.token + t + nonce;
218
366
  const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
219
367
  const sign = signTerm.toString('base64');
220
- this.debugLog(`Strip Light: ${this.accessory.displayName} sign: ${sign}`);
368
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
221
369
  const options = {
222
370
  hostname: HostDomain,
223
371
  port: 443,
@@ -232,38 +380,35 @@ export class StripLight {
232
380
  },
233
381
  };
234
382
  const req = https.request(options, (res) => {
235
- this.debugLog(`Strip Light: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
383
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
384
+ this.statusCode({ res });
236
385
  let rawData = '';
237
386
  res.on('data', (d) => {
238
387
  rawData += d;
239
- this.debugLog(`Strip Light: ${this.accessory.displayName} d: ${d}`);
388
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
240
389
  });
241
390
  res.on('end', () => {
242
391
  try {
243
392
  this.deviceStatus = JSON.parse(rawData);
244
- this.debugLog(`Strip Light: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
393
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${superStringify(this.deviceStatus)}`);
245
394
  this.power = this.deviceStatus.body.power;
246
395
  this.color = this.deviceStatus.body.color;
247
396
  this.brightness = this.deviceStatus.body.brightness;
248
397
  this.parseStatus();
249
398
  this.updateHomeKitCharacteristics();
250
399
  } catch (e: any) {
251
- this.errorLog(`Strip Light: ${this.accessory.displayName} error message: ${e.message}`);
400
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
252
401
  }
253
402
  });
254
403
  });
255
404
  req.on('error', (e: any) => {
256
- this.errorLog(`Strip Light: ${this.accessory.displayName} error message: ${e.message}`);
405
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
257
406
  });
258
407
  req.end();
259
408
  } catch (e: any) {
260
- this.errorLog(`Strip Light: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
261
- if (this.deviceLogging.includes('debug')) {
262
- this.errorLog(
263
- `Strip Light: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
264
- );
265
- }
266
409
  this.apiError(e);
410
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
411
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
267
412
  }
268
413
  }
269
414
 
@@ -278,8 +423,64 @@ export class StripLight {
278
423
  *
279
424
  */
280
425
  async pushChanges(): Promise<void> {
426
+ /*if (this.BLE) {
427
+ await this.BLERefreshStatus();
428
+ } else*/ if (this.OpenAPI && this.platform.config.credentials?.token) {
429
+ await this.openAPIpushChanges();
430
+ } else {
431
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
432
+ + ` ${this.device.connectionType}, pushChanges will not happen.`);
433
+ }
434
+ interval(5000)
435
+ .pipe(take(1))
436
+ .subscribe(async () => {
437
+ await this.refreshStatus();
438
+ });
439
+ }
440
+
441
+ async BLEpushChanges(): Promise<void> {
442
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
443
+ if (this.On !== this.accessory.context.On) {
444
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
445
+ const switchbot = await this.platform.connectBLE();
446
+ // Convert to BLE Address
447
+ this.device.bleMac = this.device
448
+ .deviceId!.match(/.{1,2}/g)!
449
+ .join(':')
450
+ .toLowerCase();
451
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
452
+ switchbot
453
+ .discover({
454
+ model: 'r',
455
+ id: this.device.bleMac,
456
+ })
457
+ .then((device_list: any) => {
458
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
459
+ return this.turnOnOff(device_list);
460
+ })
461
+ .then(() => {
462
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
463
+ this.On = false;
464
+ })
465
+ .catch(async (e: any) => {
466
+ this.apiError(e);
467
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
468
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
469
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
470
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
471
+ await this.openAPIpushChanges();
472
+ }
473
+ });
474
+ } else {
475
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, `
476
+ +`OnCached: ${this.accessory.context.On}`);
477
+ }
478
+ }
479
+
480
+ async openAPIpushChanges() {
281
481
  try {
282
- if (this.On !== this.OnCached) {
482
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
483
+ if (this.On !== this.accessory.context.On) {
283
484
  // Make Push On request to the API
284
485
  const t = Date.now();
285
486
  const nonce = 'requestID';
@@ -288,7 +489,7 @@ export class StripLight {
288
489
  .update(Buffer.from(data, 'utf-8'))
289
490
  .digest();
290
491
  const sign = signTerm.toString('base64');
291
- this.debugLog(`Strip Light: ${this.accessory.displayName} sign: ${sign}`);
492
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
292
493
 
293
494
  let command = '';
294
495
  if (this.On) {
@@ -296,12 +497,12 @@ export class StripLight {
296
497
  } else {
297
498
  command = 'turnOff';
298
499
  }
299
- const body = JSON.stringify({
500
+ const body = superStringify({
300
501
  'command': `${command}`,
301
502
  'parameter': 'default',
302
503
  'commandType': 'command',
303
504
  });
304
- this.infoLog(`Strip Light: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
505
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
305
506
  const options = {
306
507
  hostname: HostDomain,
307
508
  port: 443,
@@ -317,49 +518,49 @@ export class StripLight {
317
518
  },
318
519
  };
319
520
  const req = https.request(options, res => {
320
- this.debugLog(`Strip Light: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
521
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
321
522
  this.statusCode({ res });
322
523
  res.on('data', d => {
323
- this.debugLog(`Strip Light: ${this.accessory.displayName} d: ${d}`);
524
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
324
525
  });
325
526
  });
326
527
  req.on('error', (e: any) => {
327
- this.errorLog(`Strip Light: ${this.accessory.displayName} error message: ${e.message}`);
528
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
328
529
  });
329
530
  req.write(body);
330
531
  req.end();
331
- this.debugLog(`Strip Light: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
332
- this.OnCached = this.On;
333
- this.accessory.context.On = this.OnCached;
532
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${superStringify(req)}`);
533
+ } else {
534
+ this.debugLog(
535
+ `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, `
536
+ +`OnCached: ${this.accessory.context.On}`,
537
+ );
334
538
  }
335
539
  // Push Brightness Update
336
540
  if (this.On) {
337
541
  await this.pushBrightnessChanges();
338
542
  }
339
-
340
543
  // Push Hue & Saturation Update
341
544
  if (this.On) {
342
545
  await this.pushHueSaturationChanges();
343
546
  }
344
547
  } catch (e: any) {
345
- this.errorLog(`Strip Light: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
346
- if (this.deviceLogging.includes('debug')) {
347
- this.errorLog(
348
- `Strip Light: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
349
- );
350
- }
351
548
  this.apiError(e);
549
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
550
+ + ` Connection, Error Message: ${superStringify(e.message)}`,
551
+ );
352
552
  }
353
553
  }
354
554
 
355
555
  async pushHueSaturationChanges(): Promise<void> {
356
556
  try {
357
- if (this.Hue !== this.HueCached || this.Saturation !== this.SaturationCached) {
358
- this.debugLog(`Strip Light: ${this.accessory.displayName} Hue: ${JSON.stringify(this.Hue)}`);
359
- this.debugLog(`Strip Light: ${this.accessory.displayName} Saturation: ${JSON.stringify(this.Saturation)}`);
557
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushHueSaturationChanges`);
558
+ if (this.Hue !== this.accessory.context.Hue || this.Saturation !== this.accessory.context.Saturation) {
559
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${superStringify(this.Hue)}`);
560
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${superStringify(this.Saturation)}`);
360
561
 
361
562
  const [red, green, blue] = hs2rgb(Number(this.Hue), Number(this.Saturation));
362
- this.debugLog(`Strip Light: ${this.accessory.displayName} rgb: ${JSON.stringify([red, green, blue])}`);
563
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} rgb: ${superStringify([red, green, blue])}`);
363
564
  // Make Push On request to the API
364
565
  const t = Date.now();
365
566
  const nonce = 'requestID';
@@ -368,13 +569,13 @@ export class StripLight {
368
569
  .update(Buffer.from(data, 'utf-8'))
369
570
  .digest();
370
571
  const sign = signTerm.toString('base64');
371
- this.debugLog(`Strip Light: ${this.accessory.displayName} sign: ${sign}`);
372
- const body = JSON.stringify({
572
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
573
+ const body = superStringify({
373
574
  'command': 'setColor',
374
575
  'parameter': `${red}:${green}:${blue}`,
375
576
  'commandType': 'command',
376
577
  });
377
- this.infoLog(`Strip Light: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
578
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
378
579
  const options = {
379
580
  hostname: HostDomain,
380
581
  port: 443,
@@ -390,41 +591,33 @@ export class StripLight {
390
591
  },
391
592
  };
392
593
  const req = https.request(options, res => {
393
- this.debugLog(`Strip Light: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
594
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushHueSaturationChanges statusCode: ${res.statusCode}`);
394
595
  this.statusCode({ res });
395
596
  res.on('data', d => {
396
- this.debugLog(`Strip Light: ${this.accessory.displayName} d: ${d}`);
597
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
397
598
  });
398
599
  });
399
600
  req.on('error', (e: any) => {
400
- this.errorLog(`Strip Light: ${this.accessory.displayName} error message: ${e.message}`);
601
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
401
602
  });
402
603
  req.write(body);
403
604
  req.end();
404
- this.debugLog(`Strip Light: ${this.accessory.displayName} pushHueSaturationChanges: ${JSON.stringify(req)}`);
405
- this.HueCached = this.Hue;
406
- this.SaturationCached = this.Saturation;
605
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushHueSaturationChanges: ${superStringify(req)}`);
407
606
  } else {
408
- this.debugLog(
409
- `Strip Light: ${this.accessory.displayName} No Changes.` +
410
- `Hue: ${this.Hue}, HueCached: ${this.HueCached}, Saturation: ${this.Saturation}, SaturationCached: ${this.SaturationCached}`,
411
- );
607
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, `
608
+ + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`);
412
609
  }
413
610
  } catch (e: any) {
414
- this.errorLog(`Strip Light: ${this.accessory.displayName} failed pushHueSaturationChanges with OpenAPI Connection`);
415
- if (this.deviceLogging.includes('debug')) {
416
- this.errorLog(
417
- `Strip Light: ${this.accessory.displayName} failed pushHueSaturationChanges with OpenAPI Connection,`
418
- + ` Error Message: ${JSON.stringify(e.message)}`,
419
- );
420
- }
421
611
  this.apiError(e);
612
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}`
613
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
422
614
  }
423
615
  }
424
616
 
425
617
  async pushBrightnessChanges(): Promise<void> {
426
618
  try {
427
- if (this.Brightness !== this.BrightnessCached) {
619
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges`);
620
+ if (this.Brightness !== this.accessory.context.Brightness) {
428
621
  // Make Push On request to the API
429
622
  const t = Date.now();
430
623
  const nonce = 'requestID';
@@ -433,13 +626,13 @@ export class StripLight {
433
626
  .update(Buffer.from(data, 'utf-8'))
434
627
  .digest();
435
628
  const sign = signTerm.toString('base64');
436
- this.debugLog(`Strip Light: ${this.accessory.displayName} sign: ${sign}`);
437
- const body = JSON.stringify({
629
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
630
+ const body = superStringify({
438
631
  'command': 'setBrightness',
439
632
  'parameter': `${this.Brightness}`,
440
633
  'commandType': 'command',
441
634
  });
442
- this.infoLog(`Strip Light: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
635
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
443
636
  const options = {
444
637
  hostname: HostDomain,
445
638
  port: 443,
@@ -455,104 +648,266 @@ export class StripLight {
455
648
  },
456
649
  };
457
650
  const req = https.request(options, res => {
458
- this.debugLog(`Strip Light: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
651
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges statusCode: ${res.statusCode}`);
459
652
  this.statusCode({ res });
460
653
  res.on('data', d => {
461
- this.debugLog(`Strip Light: ${this.accessory.displayName} d: ${d}`);
654
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
462
655
  });
463
656
  });
464
657
  req.on('error', (e: any) => {
465
- this.errorLog(`Strip Light: ${this.accessory.displayName} error message: ${e.message}`);
658
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
466
659
  });
467
660
  req.write(body);
468
661
  req.end();
469
- this.debugLog(`Strip Light: ${this.accessory.displayName} pushBrightnessChanges: ${JSON.stringify(req)}`);
470
- this.BrightnessCached = this.Brightness;
662
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges: ${superStringify(req)}`);
471
663
  } else {
472
- this.debugLog(
473
- `Strip Light: ${this.accessory.displayName} No Changes.` + `Brightness: ${this.Brightness}, BrightnessCached: ${this.BrightnessCached}`,
474
- );
664
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.` + `Brightness: ${this.Brightness}, `
665
+ +`BrightnessCached: ${this.accessory.context.Brightness}`);
475
666
  }
476
667
  } catch (e: any) {
477
- this.errorLog(`Strip Light: ${this.accessory.displayName} failed pushBrightnessChanges with OpenAPI Connection`);
478
- if (this.deviceLogging.includes('debug')) {
479
- this.errorLog(
480
- `Strip Light: ${this.accessory.displayName} failed pushBrightnessChanges with OpenAPI Connection,`
481
- + ` Error Message: ${JSON.stringify(e.message)}`,
482
- );
483
- }
484
668
  this.apiError(e);
669
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}`
670
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
485
671
  }
486
672
  }
487
673
 
674
+ /**
675
+ * Handle requests to set the value of the "On" characteristic
676
+ */
677
+ async OnSet(value: CharacteristicValue): Promise<void> {
678
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
679
+
680
+ this.On = value;
681
+ this.doStripLightUpdate.next();
682
+ }
683
+
684
+ /**
685
+ * Handle requests to set the value of the "Brightness" characteristic
686
+ */
687
+ async BrightnessSet(value: CharacteristicValue): Promise<void> {
688
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Brightness: ${value}`);
689
+
690
+ this.Brightness = value;
691
+ this.doStripLightUpdate.next();
692
+ }
693
+
694
+ /**
695
+ * Handle requests to set the value of the "ColorTemperature" characteristic
696
+ */
697
+ /*async ColorTemperatureSet(value: CharacteristicValue): Promise<void> {
698
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ColorTemperature: ${value}`);
699
+
700
+ // Convert mired to kelvin to nearest 100 (SwitchBot seems to need this)
701
+ const kelvin = Math.round(1000000 / Number(value) / 100) * 100;
702
+
703
+ // Check and increase/decrease kelvin to range of device
704
+ const k = Math.min(Math.max(kelvin, this.minKelvin), this.maxKelvin);
705
+
706
+ if (!this.accessory.context.On || this.cacheKelvin === k) {
707
+ return;
708
+ }
709
+
710
+ // Updating the hue/sat to the corresponding values mimics native adaptive lighting
711
+ const hs = m2hs(value);
712
+ this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Hue, hs[0]);
713
+ this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Saturation, hs[1]);
714
+
715
+ this.ColorTemperature = value;
716
+ this.doColorBulbUpdate.next();
717
+ }*/
718
+
719
+ /**
720
+ * Handle requests to set the value of the "Hue" characteristic
721
+ */
722
+ async HueSet(value: CharacteristicValue): Promise<void> {
723
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Hue: ${value}`);
724
+
725
+ //this.lightBulbService.updateCharacteristic(this.platform.Characteristic.ColorTemperature, 140);
726
+
727
+ this.Hue = value;
728
+ this.doStripLightUpdate.next();
729
+ }
730
+
731
+ /**
732
+ * Handle requests to set the value of the "Saturation" characteristic
733
+ */
734
+ async SaturationSet(value: CharacteristicValue): Promise<void> {
735
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Saturation: ${value}`);
736
+
737
+ //this.lightBulbService.updateCharacteristic(this.platform.Characteristic.ColorTemperature, 140);
738
+
739
+ this.Saturation = value;
740
+ this.doStripLightUpdate.next();
741
+ }
742
+
488
743
  async updateHomeKitCharacteristics(): Promise<void> {
489
744
  if (this.On === undefined) {
490
- this.debugLog(`Strip Light: ${this.accessory.displayName} On: ${this.On}`);
745
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
491
746
  } else {
747
+ this.accessory.context.On = this.On;
492
748
  this.lightBulbService.updateCharacteristic(this.platform.Characteristic.On, this.On);
493
- this.debugLog(`Strip Light: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
749
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
494
750
  }
495
751
  if (this.Brightness === undefined) {
496
- this.debugLog(`Strip Light: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
752
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
497
753
  } else {
754
+ this.accessory.context.Brightness = this.Brightness;
498
755
  this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Brightness, this.Brightness);
499
- this.debugLog(`Strip Light: ${this.accessory.displayName} updateCharacteristic Brightness: ${this.Brightness}`);
756
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Brightness: ${this.Brightness}`);
500
757
  }
758
+ /*
759
+ if (this.ColorTemperature === undefined) {
760
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ColorTemperature: ${this.ColorTemperature}`);
761
+ } else {
762
+ this.accessory.context.ColorTemperature = this.ColorTemperature;
763
+ this.lightBulbService.updateCharacteristic(this.platform.Characteristic.ColorTemperature, this.ColorTemperature);
764
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic ColorTemperature: ${this.ColorTemperature}`);
765
+ }*/
501
766
  if (this.Hue === undefined) {
502
- this.debugLog(`Strip Light: ${this.accessory.displayName} Hue: ${this.Hue}`);
767
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${this.Hue}`);
503
768
  } else {
769
+ this.accessory.context.Hue = this.Hue;
504
770
  this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Hue, this.Hue);
505
- this.debugLog(`Strip Light: ${this.accessory.displayName} updateCharacteristic Hue: ${this.Hue}`);
771
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Hue: ${this.Hue}`);
506
772
  }
507
773
  if (this.Saturation === undefined) {
508
- this.debugLog(`Strip Light: ${this.accessory.displayName} Saturation: ${this.Saturation}`);
774
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${this.Saturation}`);
509
775
  } else {
776
+ this.accessory.context.Saturation = this.Saturation;
510
777
  this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Saturation, this.Saturation);
511
- this.debugLog(`Strip Light: ${this.accessory.displayName} updateCharacteristic Saturation: ${this.Saturation}`);
778
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Saturation: ${this.Saturation}`);
512
779
  }
513
780
  }
514
781
 
515
- apiError(e: any): void {
516
- this.lightBulbService.updateCharacteristic(this.platform.Characteristic.On, e);
517
- this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Hue, e);
518
- this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Brightness, e);
519
- this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Saturation, e);
520
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
782
+ async getCustomBLEAddress(switchbot: any) {
783
+ if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
784
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} customBLEaddress: ${this.device.customBLEaddress}`);
785
+ (async () => {
786
+ // Start to monitor advertisement packets
787
+ await switchbot.startScan({
788
+ model: 'r',
789
+ });
790
+ // Set an event handler
791
+ switchbot.onadvertisement = (ad: any) => {
792
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
793
+ };
794
+ await switchbot.wait(10000);
795
+ // Stop to monitor
796
+ switchbot.stopScan();
797
+ })();
798
+ }
799
+ }
800
+
801
+ async BLEconnection(switchbot: any): Promise<void> {
802
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
803
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
804
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
805
+ this.SwitchToOpenAPI = true;
806
+ await this.openAPIRefreshStatus();
807
+ }
808
+ }
809
+
810
+ async turnOnOff(device_list: any): Promise<any> {
811
+ return await this.retry({
812
+ max: await this.maxRetry(),
813
+ fn: () => {
814
+ if (this.On) {
815
+ return device_list[0].turnOn({ id: this.device.bleMac });
816
+ } else {
817
+ return device_list[0].turnOff({ id: this.device.bleMac });
818
+ }
819
+ },
820
+ });
821
+ }
822
+
823
+ async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
824
+ return fn().catch(async (err: any) => {
825
+ if (max === 0) {
826
+ throw err;
827
+ }
828
+ this.infoLog(err);
829
+ this.infoLog('Retrying');
830
+ await this.switchbot.wait(1000);
831
+ return this.retry({ max: max - 1, fn });
832
+ });
833
+ }
834
+
835
+ async maxRetry(): Promise<number> {
836
+ let maxRetry: number;
837
+ if (this.device.bot?.maxRetry) {
838
+ maxRetry = this.device.bot?.maxRetry;
839
+ } else {
840
+ maxRetry = 5;
841
+ }
842
+ return maxRetry;
843
+ }
844
+
845
+ minStep(device: device & devicesConfig): number {
846
+ if (device.colorbulb?.set_minStep) {
847
+ this.set_minStep = device.colorbulb?.set_minStep;
848
+ } else {
849
+ this.set_minStep = 1;
850
+ }
851
+ return this.set_minStep;
852
+ }
853
+
854
+ /*async adaptiveLighting(device: device & devicesConfig): Promise<void> {
855
+ if (device.colorbulb?.adaptiveLightingShift) {
856
+ this.adaptiveLightingShift = device.colorbulb.adaptiveLightingShift;
857
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} adaptiveLightingShift: ${this.adaptiveLightingShift}`);
858
+ } else {
859
+ this.adaptiveLightingShift = 0;
860
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} adaptiveLightingShift: ${this.adaptiveLightingShift}`);
861
+ }
862
+ }*/
863
+
864
+ async scan(device: device & devicesConfig): Promise<void> {
865
+ if (device.scanDuration) {
866
+ this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
867
+ if (this.BLE) {
868
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
869
+ }
870
+ } else {
871
+ this.scanDuration = this.accessory.context.scanDuration = 1;
872
+ if (this.BLE) {
873
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
874
+ }
875
+ }
521
876
  }
522
877
 
523
878
  async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
524
879
  switch (res.statusCode) {
525
880
  case 151:
526
- this.errorLog(`Strip Light: ${this.accessory.displayName} Command not supported by this device type.`);
881
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
527
882
  break;
528
883
  case 152:
529
- this.errorLog(`Strip Light: ${this.accessory.displayName} Device not found.`);
884
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
530
885
  break;
531
886
  case 160:
532
- this.errorLog(`Strip Light: ${this.accessory.displayName} Command is not supported.`);
887
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
533
888
  break;
534
889
  case 161:
535
- this.errorLog(`Strip Light: ${this.accessory.displayName} Device is offline.`);
890
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
536
891
  this.offlineOff();
537
892
  break;
538
893
  case 171:
539
- this.errorLog(`Strip Light: ${this.accessory.displayName} is offline. Hub: ${this.device.hubDeviceId}`);
894
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} is offline. Hub: ${this.device.hubDeviceId}`);
540
895
  this.offlineOff();
541
896
  break;
542
897
  case 190:
543
898
  this.errorLog(
544
- `Strip Light: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
545
- ` Or command: ${JSON.stringify(res)} format is invalid`,
899
+ `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
900
+ ` Or command: ${superStringify(res)} format is invalid`,
546
901
  );
547
902
  break;
548
903
  case 100:
549
904
  if (this.platform.debugMode) {
550
- this.debugLog(`Strip Light: ${this.accessory.displayName} Command successfully sent.`);
905
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
551
906
  }
552
907
  break;
553
908
  default:
554
909
  if (this.platform.debugMode) {
555
- this.debugLog(`Strip Light: ${this.accessory.displayName} Unknown statusCode.`);
910
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
556
911
  }
557
912
  }
558
913
  }
@@ -561,47 +916,71 @@ export class StripLight {
561
916
  if (this.device.offline) {
562
917
  this.On = false;
563
918
  this.lightBulbService.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
919
+ await this.updateHomeKitCharacteristics();
564
920
  }
565
921
  }
566
922
 
567
- /**
568
- * Handle requests to set the value of the "On" characteristic
569
- */
570
- async OnSet(value: CharacteristicValue): Promise<void> {
571
- this.debugLog(`Strip Light: ${this.accessory.displayName} On: ${value}`);
572
-
573
- this.On = value;
574
- this.doColorBulbUpdate.next();
923
+ apiError(e: any): void {
924
+ this.lightBulbService.updateCharacteristic(this.platform.Characteristic.On, e);
925
+ this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Hue, e);
926
+ this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Brightness, e);
927
+ this.lightBulbService.updateCharacteristic(this.platform.Characteristic.Saturation, e);
575
928
  }
576
929
 
577
- /**
578
- * Handle requests to set the value of the "Brightness" characteristic
579
- */
580
- async BrightnessSet(value: CharacteristicValue): Promise<void> {
581
- this.debugLog(`Strip Light: ${this.accessory.displayName} Brightness: ${value}`);
582
-
583
- this.Brightness = value;
584
- this.doColorBulbUpdate.next();
930
+ FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
931
+ let FirmwareRevision: string;
932
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} `
933
+ +`accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
934
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
935
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
936
+ if (accessory.context.FirmwareRevision) {
937
+ FirmwareRevision = accessory.context.FirmwareRevision;
938
+ } else if (device.firmware) {
939
+ FirmwareRevision = device.firmware;
940
+ } else {
941
+ FirmwareRevision = this.platform.version;
942
+ }
943
+ return FirmwareRevision;
585
944
  }
586
945
 
587
- /**
588
- * Handle requests to set the value of the "Hue" characteristic
589
- */
590
- async HueSet(value: CharacteristicValue): Promise<void> {
591
- this.debugLog(`Strip Light: ${this.accessory.displayName} Hue: ${value}`);
592
-
593
- this.Hue = value;
594
- this.doColorBulbUpdate.next();
946
+ async context() {
947
+ if (this.On === undefined) {
948
+ this.On = false;
949
+ } else {
950
+ this.On = this.accessory.context.On;
951
+ }
952
+ if (this.Hue === undefined) {
953
+ this.Hue = 0;
954
+ } else {
955
+ this.Hue = this.accessory.context.Hue;
956
+ }
957
+ if (this.Brightness === undefined) {
958
+ this.Brightness = 0;
959
+ } else {
960
+ this.Brightness = this.accessory.context.Brightness;
961
+ }
962
+ if (this.Brightness === undefined) {
963
+ this.Saturation = 0;
964
+ } else {
965
+ this.Saturation = this.accessory.context.Saturation;
966
+ }
967
+ /*if (this.ColorTemperature === undefined) {
968
+ this.ColorTemperature = 140;
969
+ } else {
970
+ this.ColorTemperature = this.accessory.context.ColorTemperature;
971
+ }*/
972
+ this.minKelvin = 2000;
973
+ this.maxKelvin = 9000;
595
974
  }
596
975
 
597
- /**
598
- * Handle requests to set the value of the "Saturation" characteristic
599
- */
600
- async SaturationSet(value: CharacteristicValue): Promise<void> {
601
- this.debugLog(`Strip Light: ${this.accessory.displayName} Saturation: ${value}`);
602
-
603
- this.Saturation = value;
604
- this.doColorBulbUpdate.next();
976
+ async refreshRate(device: device & devicesConfig): Promise<void> {
977
+ if (device.refreshRate) {
978
+ this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
979
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
980
+ } else if (this.platform.config.options!.refreshRate) {
981
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
982
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
983
+ }
605
984
  }
606
985
 
607
986
  async config(device: device & devicesConfig): Promise<void> {
@@ -609,8 +988,8 @@ export class StripLight {
609
988
  if (device.colorbulb) {
610
989
  config = device.colorbulb;
611
990
  }
612
- if (device.ble) {
613
- config['ble'] = device.ble;
991
+ if (device.connectionType !== undefined) {
992
+ config['connectionType'] = device.connectionType;
614
993
  }
615
994
  if (device.logging !== undefined) {
616
995
  config['logging'] = device.logging;
@@ -625,58 +1004,24 @@ export class StripLight {
625
1004
  config['offline'] = device.offline;
626
1005
  }
627
1006
  if (Object.entries(config).length !== 0) {
628
- this.infoLog(`Strip Light: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
629
- }
630
- }
631
-
632
- async refreshRate(device: device & devicesConfig): Promise<void> {
633
- if (device.refreshRate) {
634
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
635
- this.debugLog(`Strip Light: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
636
- } else if (this.platform.config.options!.refreshRate) {
637
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
638
- this.debugLog(`Strip Light: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
1007
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
639
1008
  }
640
1009
  }
641
1010
 
642
1011
  async logs(device: device & devicesConfig): Promise<void> {
643
1012
  if (this.platform.debugMode) {
644
1013
  this.deviceLogging = this.accessory.context.logging = 'debugMode';
645
- this.debugLog(`Strip Light: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
1014
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
646
1015
  } else if (device.logging) {
647
1016
  this.deviceLogging = this.accessory.context.logging = device.logging;
648
- this.debugLog(`Strip Light: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
1017
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
649
1018
  } else if (this.platform.config.options?.logging) {
650
1019
  this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
651
- this.debugLog(`Strip Light: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
1020
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
652
1021
  } else {
653
1022
  this.deviceLogging = this.accessory.context.logging = 'standard';
654
- this.debugLog(`Strip Light: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
655
- }
656
- }
657
-
658
- FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
659
- let FirmwareRevision: string;
660
- this.debugLog(`Strip Light: ${this.accessory.displayName} accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
661
- this.debugLog(`Strip Light: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
662
- this.debugLog(`Strip Light: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
663
- if (accessory.context.FirmwareRevision) {
664
- FirmwareRevision = accessory.context.FirmwareRevision;
665
- } else if (device.firmware) {
666
- FirmwareRevision = device.firmware;
667
- } else {
668
- FirmwareRevision = this.platform.version;
669
- }
670
- return FirmwareRevision;
671
- }
672
-
673
- minStep(device: device & devicesConfig): number {
674
- if (device.colorbulb?.set_minStep) {
675
- this.set_minStep = device.colorbulb?.set_minStep;
676
- } else {
677
- this.set_minStep = 1;
1023
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
678
1024
  }
679
- return this.set_minStep;
680
1025
  }
681
1026
 
682
1027
  /**