@switchbot/homebridge-switchbot 1.1.1-beta.7 → 1.2.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 (104) hide show
  1. package/CHANGELOG.md +5 -1
  2. package/README.md +67 -28
  3. package/config.schema.json +46 -43
  4. package/dist/devices/bots.d.ts +2 -0
  5. package/dist/devices/bots.d.ts.map +1 -1
  6. package/dist/devices/bots.js +118 -68
  7. package/dist/devices/bots.js.map +1 -1
  8. package/dist/devices/colorbulb.d.ts +19 -3
  9. package/dist/devices/colorbulb.d.ts.map +1 -1
  10. package/dist/devices/colorbulb.js +190 -31
  11. package/dist/devices/colorbulb.js.map +1 -1
  12. package/dist/devices/contact.d.ts +2 -0
  13. package/dist/devices/contact.d.ts.map +1 -1
  14. package/dist/devices/contact.js +22 -5
  15. package/dist/devices/contact.js.map +1 -1
  16. package/dist/devices/curtains.d.ts +5 -3
  17. package/dist/devices/curtains.d.ts.map +1 -1
  18. package/dist/devices/curtains.js +76 -26
  19. package/dist/devices/curtains.js.map +1 -1
  20. package/dist/devices/humidifiers.d.ts +2 -0
  21. package/dist/devices/humidifiers.d.ts.map +1 -1
  22. package/dist/devices/humidifiers.js +84 -27
  23. package/dist/devices/humidifiers.js.map +1 -1
  24. package/dist/devices/indoorcam.d.ts +2 -0
  25. package/dist/devices/indoorcam.d.ts.map +1 -1
  26. package/dist/devices/indoorcam.js +23 -7
  27. package/dist/devices/indoorcam.js.map +1 -1
  28. package/dist/devices/meters.d.ts +2 -0
  29. package/dist/devices/meters.d.ts.map +1 -1
  30. package/dist/devices/meters.js +21 -3
  31. package/dist/devices/meters.js.map +1 -1
  32. package/dist/devices/motion.d.ts +2 -0
  33. package/dist/devices/motion.d.ts.map +1 -1
  34. package/dist/devices/motion.js +21 -3
  35. package/dist/devices/motion.js.map +1 -1
  36. package/dist/devices/plugs.d.ts +2 -0
  37. package/dist/devices/plugs.d.ts.map +1 -1
  38. package/dist/devices/plugs.js +23 -7
  39. package/dist/devices/plugs.js.map +1 -1
  40. package/dist/irdevices/airconditioners.d.ts +2 -0
  41. package/dist/irdevices/airconditioners.d.ts.map +1 -1
  42. package/dist/irdevices/airconditioners.js +14 -5
  43. package/dist/irdevices/airconditioners.js.map +1 -1
  44. package/dist/irdevices/airpurifiers.d.ts +2 -0
  45. package/dist/irdevices/airpurifiers.d.ts.map +1 -1
  46. package/dist/irdevices/airpurifiers.js +14 -5
  47. package/dist/irdevices/airpurifiers.js.map +1 -1
  48. package/dist/irdevices/cameras.d.ts +2 -0
  49. package/dist/irdevices/cameras.d.ts.map +1 -1
  50. package/dist/irdevices/cameras.js +14 -5
  51. package/dist/irdevices/cameras.js.map +1 -1
  52. package/dist/irdevices/fans.d.ts +2 -0
  53. package/dist/irdevices/fans.d.ts.map +1 -1
  54. package/dist/irdevices/fans.js +13 -5
  55. package/dist/irdevices/fans.js.map +1 -1
  56. package/dist/irdevices/lights.d.ts +2 -0
  57. package/dist/irdevices/lights.d.ts.map +1 -1
  58. package/dist/irdevices/lights.js +14 -5
  59. package/dist/irdevices/lights.js.map +1 -1
  60. package/dist/irdevices/others.d.ts +2 -0
  61. package/dist/irdevices/others.d.ts.map +1 -1
  62. package/dist/irdevices/others.js +20 -11
  63. package/dist/irdevices/others.js.map +1 -1
  64. package/dist/irdevices/tvs.d.ts +2 -0
  65. package/dist/irdevices/tvs.d.ts.map +1 -1
  66. package/dist/irdevices/tvs.js +14 -4
  67. package/dist/irdevices/tvs.js.map +1 -1
  68. package/dist/irdevices/vacuumcleaners.d.ts +2 -0
  69. package/dist/irdevices/vacuumcleaners.d.ts.map +1 -1
  70. package/dist/irdevices/vacuumcleaners.js +14 -5
  71. package/dist/irdevices/vacuumcleaners.js.map +1 -1
  72. package/dist/irdevices/waterheaters.d.ts +2 -0
  73. package/dist/irdevices/waterheaters.d.ts.map +1 -1
  74. package/dist/irdevices/waterheaters.js +14 -5
  75. package/dist/irdevices/waterheaters.js.map +1 -1
  76. package/dist/platform.d.ts +1 -0
  77. package/dist/platform.d.ts.map +1 -1
  78. package/dist/platform.js +35 -26
  79. package/dist/platform.js.map +1 -1
  80. package/dist/settings.d.ts +4 -0
  81. package/dist/settings.d.ts.map +1 -1
  82. package/dist/settings.js +557 -1
  83. package/dist/settings.js.map +1 -1
  84. package/package.json +6 -6
  85. package/src/devices/bots.ts +118 -69
  86. package/src/devices/colorbulb.ts +218 -33
  87. package/src/devices/contact.ts +23 -5
  88. package/src/devices/curtains.ts +80 -31
  89. package/src/devices/humidifiers.ts +85 -29
  90. package/src/devices/indoorcam.ts +24 -7
  91. package/src/devices/meters.ts +22 -3
  92. package/src/devices/motion.ts +22 -3
  93. package/src/devices/plugs.ts +24 -7
  94. package/src/irdevices/airconditioners.ts +15 -5
  95. package/src/irdevices/airpurifiers.ts +15 -5
  96. package/src/irdevices/cameras.ts +15 -5
  97. package/src/irdevices/fans.ts +13 -5
  98. package/src/irdevices/lights.ts +15 -5
  99. package/src/irdevices/others.ts +21 -11
  100. package/src/irdevices/tvs.ts +15 -4
  101. package/src/irdevices/vacuumcleaners.ts +15 -5
  102. package/src/irdevices/waterheaters.ts +15 -5
  103. package/src/platform.ts +36 -26
  104. package/src/settings.ts +557 -1
@@ -31,6 +31,10 @@ export class Bot {
31
31
  state!: serviceData['state'];
32
32
  battery!: serviceData['battery'];
33
33
 
34
+ // Config
35
+ private readonly deviceDebug = this.platform.config.options?.debug === 'device' || this.platform.debugMode;
36
+ private readonly debugDebug = this.platform.config.options?.debug === 'debug' || this.platform.debugMode;
37
+
34
38
  // Updates
35
39
  botUpdateInProgress!: boolean;
36
40
  doBotUpdate!: Subject<void>;
@@ -65,39 +69,36 @@ export class Bot {
65
69
 
66
70
  // get the LightBulb service if it exists, otherwise create a new LightBulb service
67
71
  // you can create multiple services for each accessory
68
- switch (device.bot!.deviceType) {
69
- case 'switch':
70
- // If outletService still pressent, then remove first
71
- if (this.outletService) {
72
- this.platform.device(`Bot: ${this.accessory.displayName} Removing Leftover outletService first`);
73
- }
74
- this.outletService = this.accessory.getService(this.platform.Service.Outlet);
75
- accessory.removeService(this.outletService!);
72
+ if (device.bot?.deviceType === 'switch') {
73
+ // If outletService still pressent, then remove first
74
+ if (this.outletService) {
75
+ this.platform.device(`Bot: ${this.accessory.displayName} Removing Leftover outletService first`);
76
+ }
77
+ this.outletService = this.accessory.getService(this.platform.Service.Outlet);
78
+ accessory.removeService(this.outletService!);
76
79
 
77
- // Add switchService
78
- (this.switchService =
79
- accessory.getService(this.platform.Service.Switch) ||
80
- accessory.addService(this.platform.Service.Switch)), `${accessory.displayName} Switch`;
81
- this.platform.log.info(`Bot: ${this.accessory.displayName} Displaying as Switch`);
80
+ // Add switchService
81
+ (this.switchService =
82
+ accessory.getService(this.platform.Service.Switch) ||
83
+ accessory.addService(this.platform.Service.Switch)), `${accessory.displayName} Switch`;
84
+ this.platform.log.info(`Bot: ${this.accessory.displayName} Displaying as Switch`);
82
85
 
83
- this.switchService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
84
- break;
85
- case 'outlet':
86
- default:
87
- // If switchService still pressent, then remove first
88
- if (this.switchService) {
89
- this.platform.device(`Bot: ${this.accessory.displayName} Removing Leftover switchService first`);
90
- }
91
- this.switchService = this.accessory.getService(this.platform.Service.Switch);
92
- accessory.removeService(this.switchService!);
86
+ this.switchService?.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
87
+ } else {
88
+ // If switchService still pressent, then remove first
89
+ if (this.switchService) {
90
+ this.platform.device(`Bot: ${this.accessory.displayName} Removing Leftover switchService first`);
91
+ }
92
+ this.switchService = this.accessory.getService(this.platform.Service.Switch);
93
+ accessory.removeService(this.switchService!);
93
94
 
94
- // Add outletService
95
- (this.outletService =
96
- accessory.getService(this.platform.Service.Outlet) ||
97
- accessory.addService(this.platform.Service.Outlet)), `${accessory.displayName} Outlet`;
98
- this.platform.log.info(`Bot: ${this.accessory.displayName} Displaying as Outlet`);
95
+ // Add outletService
96
+ (this.outletService =
97
+ accessory.getService(this.platform.Service.Outlet) ||
98
+ accessory.addService(this.platform.Service.Outlet)), `${accessory.displayName} Outlet`;
99
+ this.platform.log.info(`Bot: ${this.accessory.displayName} Displaying as Outlet`);
99
100
 
100
- this.outletService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
101
+ this.outletService?.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
101
102
  }
102
103
 
103
104
  if (device.ble) {
@@ -141,10 +142,15 @@ export class Bot {
141
142
  try {
142
143
  await this.pushChanges();
143
144
  } catch (e: any) {
144
- this.platform.log.error(`Bot: ${this.accessory.displayName} failed to pushChanges,`
145
- + ` Error Message: ${JSON.stringify(e.message)}`);
146
- this.platform.debug(`Bot: ${this.accessory.displayName} Error: ${JSON.stringify(e)}`);
147
- this.apiError(e);
145
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges`);
146
+ if (this.deviceDebug) {
147
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges,`
148
+ + ` Error Message: ${JSON.stringify(e.message)}`);
149
+ }
150
+ if (this.debugDebug) {
151
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges,`
152
+ + ` Error: ${JSON.stringify(e)}`);
153
+ }
148
154
  }
149
155
  this.botUpdateInProgress = false;
150
156
  });
@@ -239,7 +245,15 @@ export class Bot {
239
245
  this.parseStatus();
240
246
  this.updateHomeKitCharacteristics();
241
247
  }).catch(async (e: any) => {
242
- this.platform.log.error(`Bot: ${this.accessory.displayName} BLE Connection failed refreshStatus, Error Message: ${JSON.stringify(e.message)}`);
248
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
249
+ if (this.deviceDebug) {
250
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
251
+ + ` Error Message: ${JSON.stringify(e.message)}`);
252
+ }
253
+ if (this.debugDebug) {
254
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
255
+ + ` Error: ${JSON.stringify(e)}`);
256
+ }
243
257
  if (this.platform.config.credentials?.openToken) {
244
258
  this.platform.log.warn(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
245
259
  await this.openAPIRefreshStatus();
@@ -264,8 +278,15 @@ export class Bot {
264
278
  this.parseStatus();
265
279
  this.updateHomeKitCharacteristics();
266
280
  } catch (e: any) {
267
- this.platform.log.error(`Bot: ${this.accessory.displayName} failed to refresh status, Error Message: ${JSON.stringify(e.message)}`);
268
- this.platform.debug(`Bot: ${this.accessory.displayName} Error: ${JSON.stringify(e)}`);
281
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
282
+ if (this.deviceDebug) {
283
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
284
+ + ` Error Message: ${JSON.stringify(e.message)}`);
285
+ }
286
+ if (this.debugDebug) {
287
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
288
+ + ` Error: ${JSON.stringify(e)}`);
289
+ }
269
290
  this.apiError(e);
270
291
  }
271
292
  }
@@ -298,7 +319,15 @@ export class Bot {
298
319
  }).then(() => {
299
320
  this.platform.device(`Bot: ${this.accessory.displayName} Done.`);
300
321
  }).catch(async (e: any) => {
301
- this.platform.log.error(`Bot: ${this.accessory.displayName} BLE Connection failed pushChanges, Error Message: ${JSON.stringify(e.message)}`);
322
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
323
+ if (this.deviceDebug) {
324
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
325
+ + ` Error Message: ${JSON.stringify(e.message)}`);
326
+ }
327
+ if (this.debugDebug) {
328
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
329
+ + ` Error: ${JSON.stringify(e)}`);
330
+ }
302
331
  if (this.platform.config.credentials?.openToken) {
303
332
  this.platform.log.warn(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
304
333
  await this.openAPIpushChanges();
@@ -306,20 +335,28 @@ export class Bot {
306
335
  });
307
336
  } else if (this.device.bot?.mode === 'switch') {
308
337
  this.platform.device(`Bot: ${this.accessory.displayName} Press Mode: ${this.device.bot?.mode}`);
309
- switchbot.discover({ model: 'H', quick: true, id: this.device.bleMac }).then((device_list) => {
338
+ switchbot.discover({ model: 'H', quick: true, id: this.device.bleMac }).then((device_list: any) => {
310
339
  this.platform.log.info(`Bot: ${this.accessory.displayName} On: ${this.SwitchOn}`);
311
340
  return this.turnOnOff(device_list);
312
341
  }).then(() => {
313
342
  this.platform.device(`Bot: ${this.accessory.displayName} Done.`);
314
343
  }).catch(async (e: any) => {
315
- this.platform.log.error(`Bot: ${this.accessory.displayName} BLE Connection failed pushChanges, Error Message: ${JSON.stringify(e.message)}`);
344
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
345
+ if (this.deviceDebug) {
346
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
347
+ + ` Error Message: ${JSON.stringify(e.message)}`);
348
+ }
349
+ if (this.debugDebug) {
350
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
351
+ + ` Error: ${JSON.stringify(e)}`);
352
+ }
316
353
  if (this.platform.config.credentials?.openToken) {
317
354
  this.platform.log.warn(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
318
355
  await this.openAPIpushChanges();
319
356
  }
320
357
  });
321
358
  } else {
322
- this.platform.log.error(`Bot: ${this.accessory.displayName} Mode Not Set.`);
359
+ this.platform.log.error(`Bot: ${this.accessory.displayName} Mode Not Set, mode: ${this.device.bot?.mode}`);
323
360
  }
324
361
  }
325
362
 
@@ -333,35 +370,47 @@ export class Bot {
333
370
 
334
371
  private async openAPIpushChanges() {
335
372
  if (this.platform.config.credentials?.openToken) {
336
- this.platform.debug(`Bot: ${this.accessory.displayName} OpenAPI pushChanges`);
337
- const payload = {
338
- commandType: 'command',
339
- parameter: 'default',
340
- } as payload;
341
-
342
- if (this.device.bot?.mode === 'switch' && this.SwitchOn) {
343
- payload.command = 'turnOn';
344
- this.SwitchOn = true;
345
- this.platform.debug(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.SwitchOn}`);
346
- } else if (this.device.bot?.mode === 'switch' && !this.SwitchOn) {
347
- payload.command = 'turnOff';
348
- this.SwitchOn = false;
349
- this.platform.debug(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.SwitchOn}`);
350
- } else if (this.device.bot?.mode === 'press') {
351
- payload.command = 'press';
352
- this.platform.debug(`Bot: ${this.accessory.displayName} Press Mode`);
353
- this.SwitchOn = false;
354
- } else {
355
- throw new Error(`Bot: ${this.accessory.displayName} Device Paramters not set for this Bot.`);
356
- }
373
+ try {
374
+ this.platform.debug(`Bot: ${this.accessory.displayName} OpenAPI pushChanges`);
375
+ const payload = {
376
+ commandType: 'command',
377
+ parameter: 'default',
378
+ } as payload;
379
+
380
+ if (this.device.bot?.mode === 'switch' && this.SwitchOn) {
381
+ payload.command = 'turnOn';
382
+ this.SwitchOn = true;
383
+ this.platform.debug(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.SwitchOn}`);
384
+ } else if (this.device.bot?.mode === 'switch' && !this.SwitchOn) {
385
+ payload.command = 'turnOff';
386
+ this.SwitchOn = false;
387
+ this.platform.debug(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.SwitchOn}`);
388
+ } else if (this.device.bot?.mode === 'press') {
389
+ payload.command = 'press';
390
+ this.platform.debug(`Bot: ${this.accessory.displayName} Press Mode`);
391
+ this.SwitchOn = false;
392
+ } else {
393
+ throw new Error(`Bot: ${this.accessory.displayName} Device Paramters not set for this Bot.`);
394
+ }
357
395
 
358
- this.platform.log.info(`Bot: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
359
- + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
396
+ this.platform.log.info(`Bot: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
397
+ + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
360
398
 
361
- // Make the API request
362
- const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
363
- this.platform.debug(`Bot ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
364
- this.statusCode(push);
399
+ // Make the API request
400
+ const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
401
+ this.platform.debug(`Bot ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
402
+ this.statusCode(push);
403
+ } catch (e: any) {
404
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
405
+ if (this.deviceDebug) {
406
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,`
407
+ + ` Error Message: ${JSON.stringify(e.message)}`);
408
+ }
409
+ if (this.debugDebug) {
410
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,`
411
+ + ` Error: ${JSON.stringify(e)}`);
412
+ }
413
+ }
365
414
  }
366
415
  }
367
416
 
@@ -425,8 +474,8 @@ export class Bot {
425
474
  this.platform.log.error(`Bot: ${this.accessory.displayName} Hub Device is offline.`);
426
475
  break;
427
476
  case 190:
428
- // eslint-disable-next-line max-len
429
- this.platform.log.error(`Bot: ${this.accessory.displayName} Device internal error due to device states not synchronized with server. Or command fomrat is invalid.`);
477
+ this.platform.log.error(`Bot: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,`
478
+ + ` Or command: ${JSON.stringify(push.data)} format is invalid`);
430
479
  break;
431
480
  case 100:
432
481
  this.platform.debug(`Bot: ${this.accessory.displayName} Command successfully sent.`);
@@ -2,7 +2,7 @@ import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
2
2
  import { SwitchBotPlatform } from '../platform';
3
3
  import { interval, Subject } from 'rxjs';
4
4
  import { debounceTime, skipWhile, tap } from 'rxjs/operators';
5
- import { DeviceURL, device, devicesConfig, switchbot, deviceStatusResponse, payload } from '../settings';
5
+ import { DeviceURL, device, devicesConfig, switchbot, deviceStatusResponse, payload, hs2rgb, rgb2hs } from '../settings';
6
6
  import { AxiosResponse } from 'axios';
7
7
 
8
8
  /**
@@ -16,7 +16,9 @@ export class ColorBulb {
16
16
 
17
17
  // Characteristic Values
18
18
  On!: CharacteristicValue;
19
+ Hue!: CharacteristicValue;
19
20
  Brightness!: CharacteristicValue;
21
+ Saturation!: CharacteristicValue;
20
22
  ColorTemperature!: CharacteristicValue;
21
23
 
22
24
  // OpenAPI Others
@@ -27,6 +29,8 @@ export class ColorBulb {
27
29
 
28
30
  // Config
29
31
  set_minStep?: number;
32
+ private readonly deviceDebug = this.platform.config.options?.debug === 'device' || this.platform.debugMode;
33
+ private readonly debugDebug = this.platform.config.options?.debug === 'debug' || this.platform.debugMode;
30
34
 
31
35
  // Updates
32
36
  colorBulbUpdateInProgress!: boolean;
@@ -93,15 +97,38 @@ export class ColorBulb {
93
97
  // handle ColorTemperature events using the ColorTemperature characteristic
94
98
  this.service.getCharacteristic(this.platform.Characteristic.ColorTemperature)
95
99
  .setProps({
96
- minStep: this.minStep(),
100
+ minValue: 140,
101
+ maxValue: 500,
102
+ validValueRanges: [140, 500],
103
+ })
104
+ .onGet(() => {
105
+ return this.ColorTemperature;
106
+ })
107
+ .onSet(this.ColorTemperatureSet.bind(this));
108
+
109
+ // handle Hue events using the Hue characteristic
110
+ this.service.getCharacteristic(this.platform.Characteristic.Hue)
111
+ .setProps({
112
+ minValue: 0,
113
+ maxValue: 360,
114
+ validValueRanges: [0, 360],
115
+ })
116
+ .onGet(() => {
117
+ return this.Hue;
118
+ })
119
+ .onSet(this.HueSet.bind(this));
120
+
121
+ // handle Hue events using the Hue characteristic
122
+ this.service.getCharacteristic(this.platform.Characteristic.Saturation)
123
+ .setProps({
97
124
  minValue: 0,
98
125
  maxValue: 100,
99
126
  validValueRanges: [0, 100],
100
127
  })
101
128
  .onGet(() => {
102
- return this.ColorTemperature;
129
+ return this.Saturation;
103
130
  })
104
- .onSet(this.ColorTemperatureSet.bind(this));
131
+ .onSet(this.SaturationSet.bind(this));
105
132
 
106
133
  // Update Homekit
107
134
  this.updateHomeKitCharacteristics();
@@ -126,9 +153,15 @@ export class ColorBulb {
126
153
  try {
127
154
  await this.pushChanges();
128
155
  } catch (e: any) {
129
- this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed to pushChanges,`
130
- + ` Error Message: ${JSON.stringify(e.message)}`);
131
- this.platform.debug(`Color Bulb: ${this.accessory.displayName} Error: ${JSON.stringify(e)}`);
156
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed pushChanges`);
157
+ if (this.deviceDebug) {
158
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed pushChanges,`
159
+ + ` Error Message: ${JSON.stringify(e.message)}`);
160
+ }
161
+ if (this.debugDebug) {
162
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed pushChanges,`
163
+ + ` Error: ${JSON.stringify(e)}`);
164
+ }
132
165
  this.apiError(e);
133
166
  }
134
167
  this.colorBulbUpdateInProgress = false;
@@ -152,9 +185,40 @@ export class ColorBulb {
152
185
  default:
153
186
  this.On = false;
154
187
  }
155
- this.platform.debug(`Color Bulb: ${this.accessory.displayName} On: ${this.On}`);
156
- this.deviceStatus.body.brightness = Number(this.Brightness);
157
- this.deviceStatus.body.colorTemperature = Number(this.ColorTemperature);
188
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} On: ${this.On}`);
189
+
190
+ // Brightness
191
+ this.Brightness = Number(this.deviceStatus.body.brightness);
192
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} Brightness: ${this.Brightness}`);
193
+
194
+ // Color, Hue & Brightness
195
+ if (this.deviceStatus.body.color) {
196
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} color: ${JSON.stringify(this.deviceStatus.body.color)}`);
197
+ const [red, green, blue] = this.deviceStatus.body.color!.split(':');
198
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} red: ${JSON.stringify(red)}`);
199
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} green: ${JSON.stringify(green)}`);
200
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} blue: ${JSON.stringify(blue)}`);
201
+
202
+ const [hue, saturation] = rgb2hs(Number(red), Number(green), Number(blue));
203
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`);
204
+
205
+ // Hue
206
+ this.Hue = hue;
207
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} Hue: ${this.Hue}`);
208
+
209
+ // Saturation
210
+ this.Saturation = saturation;
211
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} Saturation: ${this.Saturation}`);
212
+ }
213
+
214
+ // ColorTemperature
215
+ if (this.deviceStatus.body.colorTemperature) {
216
+ // Convert mired to kelvin to nearest 100 (Govee seems to need this)
217
+ const mired = Math.round(1000000 / this.deviceStatus.body.colorTemperature);
218
+
219
+ this.ColorTemperature = Number(mired);
220
+ this.platform.log.warn(`Color Bulb: ${this.accessory.displayName} ColorTemperature: ${this.ColorTemperature}`);
221
+ }
158
222
  }
159
223
 
160
224
  async refreshStatus() {
@@ -164,37 +228,123 @@ export class ColorBulb {
164
228
  this.parseStatus();
165
229
  this.updateHomeKitCharacteristics();
166
230
  } catch (e: any) {
167
- this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed to refresh status, Error Message ${JSON.stringify(e.message)}`);
168
- this.platform.debug(`Color Bulb: ${this.accessory.displayName} Error: ${JSON.stringify(e)}`);
231
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
232
+ if (this.deviceDebug) {
233
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
234
+ + ` Error Message: ${JSON.stringify(e.message)}`);
235
+ }
236
+ if (this.debugDebug) {
237
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
238
+ + ` Error: ${JSON.stringify(e)}`);
239
+ }
169
240
  this.apiError(e);
170
241
  }
171
242
  }
172
243
 
173
244
  /**
174
245
  * Pushes the requested changes to the SwitchBot API
175
- * deviceType commandType Command command parameter Description
176
- * Color Bulb - "command" "turnOff" "default" = set to OFF state
177
- * Color Bulb - "command" "turnOn" "default" = set to ON state
246
+ * deviceType commandType Command command parameter Description
247
+ * Color Bulb - "command" "turnOff" "default" = set to OFF state
248
+ * Color Bulb - "command" "turnOn" "default" = set to ON state
249
+ * Color Bulb - "command" "toggle" "default" = toggle state
250
+ * Color Bulb - "command" "setBrightness" "{1-100}" = set brightness
251
+ * Color Bulb - "command" "setColor" "{0-255}:{0-255}:{0-255}" = set RGB color value
252
+ * Color Bulb - "command" "setColorTemperature" "{2700-6500}" = set color temperature
178
253
  */
179
254
  async pushChanges() {
180
- const payload = {
181
- commandType: 'command',
182
- parameter: 'default',
183
- } as payload;
184
-
185
- if (this.On) {
186
- payload.command = 'turnOn';
187
- } else {
188
- payload.command = 'turnOff';
189
- }
255
+ try {
256
+ // Push On Update
257
+ if (this.On) {
258
+ const payload = {
259
+ commandType: 'command',
260
+ parameter: 'default',
261
+ } as payload;
262
+
263
+ if (this.On) {
264
+ payload.command = 'turnOn';
265
+ } else {
266
+ payload.command = 'turnOff';
267
+ }
190
268
 
191
- this.platform.log.info(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
192
- + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
269
+ this.platform.log.info(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
270
+ + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
271
+
272
+ // Make the API request
273
+ const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
274
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
275
+ this.statusCode(push);
276
+ }
277
+
278
+ // Push Brightness Update
279
+ if (this.On) {
280
+ const payload = {
281
+ commandType: 'command',
282
+ command: 'setBrightness',
283
+ parameter: `{${this.Brightness}}`,
284
+ } as payload;
285
+
286
+ this.platform.log.info(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
287
+ + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
288
+
289
+ // Make the API request
290
+ const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
291
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
292
+ this.statusCode(push);
293
+ }
294
+
295
+ // Push ColorTemperature Update
296
+ if (this.On) {
297
+ const kelvin = Math.round(1000000 / Number(this.ColorTemperature));
298
+
299
+ const payload = {
300
+ commandType: 'command',
301
+ command: 'setColorTemperature',
302
+ parameter: `{${kelvin}}`,
303
+ } as payload;
304
+
305
+ this.platform.log.info(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
306
+ + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
307
+
308
+ // Make the API request
309
+ const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
310
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
311
+ this.statusCode(push);
312
+ }
313
+
314
+ // Push Hue & Saturation Update
315
+ if (this.On) {
316
+ this.platform.log.warn(JSON.stringify(this.Hue));
317
+ this.platform.log.warn(JSON.stringify(this.Saturation));
318
+
319
+ const [red, green, blue] = hs2rgb(Number(this.Hue), Number(this.Saturation));
320
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} rgb: ${JSON.stringify([red, green, blue])}`);
321
+
322
+ const payload = {
323
+ commandType: 'command',
324
+ command: 'setColor',
325
+ parameter: `{${red}}:{${green}}:{${blue}}`,
326
+ } as payload;
327
+
328
+ this.platform.log.info(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
329
+ + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
330
+
331
+ // Make the API request
332
+ const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
333
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
334
+ this.statusCode(push);
335
+ }
193
336
 
194
- // Make the API request
195
- const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
196
- this.platform.debug(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
197
- this.statusCode(push);
337
+ } catch (e: any) {
338
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
339
+ if (this.deviceDebug) {
340
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,`
341
+ + ` Error Message: ${JSON.stringify(e.message)}`);
342
+ }
343
+ if (this.debugDebug) {
344
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,`
345
+ + ` Error: ${JSON.stringify(e)}`);
346
+ }
347
+ }
198
348
  }
199
349
 
200
350
  updateHomeKitCharacteristics() {
@@ -216,11 +366,25 @@ export class ColorBulb {
216
366
  this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.ColorTemperature);
217
367
  this.platform.debug(`Color Bulb: ${this.accessory.displayName} updateCharacteristic ColorTemperature: ${this.ColorTemperature}`);
218
368
  }
369
+ if (this.Hue === undefined) {
370
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} Hue: ${this.Hue}`);
371
+ } else {
372
+ this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.Hue);
373
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} updateCharacteristic Hue: ${this.Hue}`);
374
+ }
375
+ if (this.Saturation === undefined) {
376
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} Saturation: ${this.Saturation}`);
377
+ } else {
378
+ this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.Saturation);
379
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} updateCharacteristic Saturation: ${this.Saturation}`);
380
+ }
219
381
  }
220
382
 
221
383
  public apiError(e: any) {
222
384
  this.service.updateCharacteristic(this.platform.Characteristic.On, e);
385
+ this.service.updateCharacteristic(this.platform.Characteristic.Hue, e);
223
386
  this.service.updateCharacteristic(this.platform.Characteristic.Brightness, e);
387
+ this.service.updateCharacteristic(this.platform.Characteristic.Saturation, e);
224
388
  this.service.updateCharacteristic(this.platform.Characteristic.ColorTemperature, e);
225
389
  }
226
390
 
@@ -242,8 +406,8 @@ export class ColorBulb {
242
406
  this.platform.log.error(`Color Bulb: ${this.accessory.displayName} Hub Device is offline.`);
243
407
  break;
244
408
  case 190:
245
- // eslint-disable-next-line max-len
246
- this.platform.log.error(`Color Bulb: ${this.accessory.displayName} Device internal error due to device states not synchronized with server. Or command fomrat is invalid.`);
409
+ this.platform.log.error(`Color Bulb: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,`
410
+ + ` Or command: ${JSON.stringify(push.data)} format is invalid`);
247
411
  break;
248
412
  case 100:
249
413
  this.platform.debug(`Color Bulb: ${this.accessory.displayName} Command successfully sent.`);
@@ -282,4 +446,25 @@ export class ColorBulb {
282
446
  this.ColorTemperature = value;
283
447
  this.doColorBulbUpdate.next();
284
448
  }
449
+
450
+ /**
451
+ * Handle requests to set the value of the "Hue" characteristic
452
+ */
453
+ HueSet(value: CharacteristicValue) {
454
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} Hue: ${value}`);
455
+
456
+ this.Hue = value;
457
+ this.doColorBulbUpdate.next();
458
+ }
459
+
460
+ /**
461
+ * Handle requests to set the value of the "Saturation" characteristic
462
+ */
463
+ SaturationSet(value: CharacteristicValue) {
464
+ this.platform.debug(`Color Bulb: ${this.accessory.displayName} Saturation: ${value}`);
465
+
466
+ this.Saturation = value;
467
+ this.doColorBulbUpdate.next();
468
+ }
285
469
  }
470
+