@switchbot/homebridge-switchbot 1.3.1-beta.9 → 1.4.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 (80) hide show
  1. package/CHANGELOG.md +4 -2
  2. package/config.schema.json +0 -22
  3. package/dist/devices/bots.d.ts +2 -0
  4. package/dist/devices/bots.d.ts.map +1 -1
  5. package/dist/devices/bots.js +109 -89
  6. package/dist/devices/bots.js.map +1 -1
  7. package/dist/devices/colorbulb.d.ts +1 -0
  8. package/dist/devices/colorbulb.d.ts.map +1 -1
  9. package/dist/devices/colorbulb.js +17 -9
  10. package/dist/devices/colorbulb.js.map +1 -1
  11. package/dist/devices/contact.js +1 -1
  12. package/dist/devices/contact.js.map +1 -1
  13. package/dist/devices/humidifiers.d.ts +1 -0
  14. package/dist/devices/humidifiers.d.ts.map +1 -1
  15. package/dist/devices/humidifiers.js +9 -7
  16. package/dist/devices/humidifiers.js.map +1 -1
  17. package/dist/devices/meters.d.ts +5 -11
  18. package/dist/devices/meters.d.ts.map +1 -1
  19. package/dist/devices/meters.js +49 -47
  20. package/dist/devices/meters.js.map +1 -1
  21. package/dist/devices/plugs.d.ts +2 -0
  22. package/dist/devices/plugs.d.ts.map +1 -1
  23. package/dist/devices/plugs.js +35 -22
  24. package/dist/devices/plugs.js.map +1 -1
  25. package/dist/irdevices/airconditioners.d.ts +2 -0
  26. package/dist/irdevices/airconditioners.d.ts.map +1 -1
  27. package/dist/irdevices/airconditioners.js +17 -1
  28. package/dist/irdevices/airconditioners.js.map +1 -1
  29. package/dist/irdevices/airpurifiers.d.ts +2 -0
  30. package/dist/irdevices/airpurifiers.d.ts.map +1 -1
  31. package/dist/irdevices/airpurifiers.js +17 -0
  32. package/dist/irdevices/airpurifiers.js.map +1 -1
  33. package/dist/irdevices/cameras.d.ts +1 -0
  34. package/dist/irdevices/cameras.d.ts.map +1 -1
  35. package/dist/irdevices/cameras.js +9 -0
  36. package/dist/irdevices/cameras.js.map +1 -1
  37. package/dist/irdevices/fans.d.ts +1 -0
  38. package/dist/irdevices/fans.d.ts.map +1 -1
  39. package/dist/irdevices/fans.js +9 -0
  40. package/dist/irdevices/fans.js.map +1 -1
  41. package/dist/irdevices/lights.d.ts +1 -0
  42. package/dist/irdevices/lights.d.ts.map +1 -1
  43. package/dist/irdevices/lights.js +9 -0
  44. package/dist/irdevices/lights.js.map +1 -1
  45. package/dist/irdevices/others.d.ts +1 -0
  46. package/dist/irdevices/others.d.ts.map +1 -1
  47. package/dist/irdevices/others.js +9 -0
  48. package/dist/irdevices/others.js.map +1 -1
  49. package/dist/irdevices/tvs.d.ts +1 -0
  50. package/dist/irdevices/tvs.d.ts.map +1 -1
  51. package/dist/irdevices/tvs.js +9 -0
  52. package/dist/irdevices/tvs.js.map +1 -1
  53. package/dist/irdevices/vacuumcleaners.d.ts +1 -0
  54. package/dist/irdevices/vacuumcleaners.d.ts.map +1 -1
  55. package/dist/irdevices/vacuumcleaners.js +9 -0
  56. package/dist/irdevices/vacuumcleaners.js.map +1 -1
  57. package/dist/irdevices/waterheaters.d.ts +1 -0
  58. package/dist/irdevices/waterheaters.d.ts.map +1 -1
  59. package/dist/irdevices/waterheaters.js +9 -0
  60. package/dist/irdevices/waterheaters.js.map +1 -1
  61. package/dist/settings.d.ts +5 -5
  62. package/dist/settings.d.ts.map +1 -1
  63. package/dist/settings.js.map +1 -1
  64. package/package.json +66 -66
  65. package/src/devices/bots.ts +88 -68
  66. package/src/devices/colorbulb.ts +17 -9
  67. package/src/devices/contact.ts +1 -1
  68. package/src/devices/humidifiers.ts +10 -7
  69. package/src/devices/meters.ts +50 -48
  70. package/src/devices/plugs.ts +38 -23
  71. package/src/irdevices/airconditioners.ts +17 -1
  72. package/src/irdevices/airpurifiers.ts +18 -0
  73. package/src/irdevices/cameras.ts +10 -0
  74. package/src/irdevices/fans.ts +10 -0
  75. package/src/irdevices/lights.ts +10 -0
  76. package/src/irdevices/others.ts +10 -0
  77. package/src/irdevices/tvs.ts +10 -0
  78. package/src/irdevices/vacuumcleaners.ts +10 -0
  79. package/src/irdevices/waterheaters.ts +10 -0
  80. package/src/settings.ts +6 -5
@@ -20,6 +20,7 @@ export class Bot {
20
20
 
21
21
  // Characteristic Values
22
22
  On!: CharacteristicValue;
23
+ OnCached!: CharacteristicValue;
23
24
  BatteryLevel!: CharacteristicValue;
24
25
  StatusLowBattery!: CharacteristicValue;
25
26
 
@@ -48,11 +49,15 @@ export class Bot {
48
49
  public device: device & devicesConfig,
49
50
  ) {
50
51
  // Bot Config
51
- this.platform.device(`Bot: ${this.accessory.displayName} Config: (ble: ${device.ble}, mode: ${device.bot?.mode},`
52
+ this.platform.device(`Bot: ${this.accessory.displayName} Config: (ble: ${device.ble}, offline: ${device.offline}, mode: ${device.bot?.mode},`
52
53
  + ` deviceType: ${device.bot?.deviceType})`);
53
54
 
54
55
  // default placeholders
55
- this.On = false;
56
+ if (this.On === undefined) {
57
+ this.On = false;
58
+ } else {
59
+ this.On = this.accessory.context.On;
60
+ }
56
61
  this.BatteryLevel = 100;
57
62
  this.StatusLowBattery = 1;
58
63
 
@@ -340,14 +345,38 @@ export class Bot {
340
345
  }
341
346
 
342
347
  private async BLEpushChanges() {
343
- this.platform.debug(`Bot: ${this.accessory.displayName} BLE pushChanges`);
344
- const switchbot = this.connectBLE();
345
- if (this.device.bot?.mode === 'press') {
346
- this.platform.device(`Bot: ${this.accessory.displayName} Press Mode: ${this.device.bot?.mode}`);
347
- switchbot.discover({ model: 'H', quick: true, id: this.device.bleMac })
348
- .then((device_list: { press: (arg0: { id: string | undefined; }) => any; }[]) => {
349
- this.platform.log.info(`Bot: ${this.accessory.displayName}, On: ${this.On}`);
350
- return device_list[0].press({ id: this.device.bleMac });
348
+ if (this.On !== this.OnCached) {
349
+ this.platform.debug(`Bot: ${this.accessory.displayName} BLE pushChanges`);
350
+ const switchbot = this.connectBLE();
351
+ if (this.device.bot?.mode === 'press') {
352
+ this.platform.device(`Bot: ${this.accessory.displayName} Press Mode: ${this.device.bot?.mode}`);
353
+ switchbot.discover({ model: 'H', quick: true, id: this.device.bleMac })
354
+ .then((device_list: { press: (arg0: { id: string | undefined; }) => any; }[]) => {
355
+ this.platform.log.info(`Bot: ${this.accessory.displayName}, On: ${this.On}`);
356
+ return device_list[0].press({ id: this.device.bleMac });
357
+ }).then(() => {
358
+ this.platform.device(`Bot: ${this.accessory.displayName} Done.`);
359
+ }).catch(async (e: any) => {
360
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
361
+ if (this.deviceDebug) {
362
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
363
+ + ` Error Message: ${JSON.stringify(e.message)}`);
364
+ }
365
+ if (this.debugDebug) {
366
+ this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
367
+ + ` Error: ${JSON.stringify(e)}`);
368
+ }
369
+ if (this.platform.config.credentials?.openToken) {
370
+ this.platform.log.warn(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
371
+ await this.openAPIpushChanges();
372
+ }
373
+ this.apiError(e);
374
+ });
375
+ } else if (this.device.bot?.mode === 'switch') {
376
+ this.platform.device(`Bot: ${this.accessory.displayName} Press Mode: ${this.device.bot?.mode}`);
377
+ switchbot.discover({ model: 'H', quick: true, id: this.device.bleMac }).then((device_list: any) => {
378
+ this.platform.log.info(`Bot: ${this.accessory.displayName} On: ${this.On}`);
379
+ return this.turnOnOff(device_list);
351
380
  }).then(() => {
352
381
  this.platform.device(`Bot: ${this.accessory.displayName} Done.`);
353
382
  }).catch(async (e: any) => {
@@ -366,32 +395,12 @@ export class Bot {
366
395
  }
367
396
  this.apiError(e);
368
397
  });
369
- } else if (this.device.bot?.mode === 'switch') {
370
- this.platform.device(`Bot: ${this.accessory.displayName} Press Mode: ${this.device.bot?.mode}`);
371
- switchbot.discover({ model: 'H', quick: true, id: this.device.bleMac }).then((device_list: any) => {
372
- this.platform.log.info(`Bot: ${this.accessory.displayName} On: ${this.On}`);
373
- return this.turnOnOff(device_list);
374
- }).then(() => {
375
- this.platform.device(`Bot: ${this.accessory.displayName} Done.`);
376
- }).catch(async (e: any) => {
377
- this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
378
- if (this.deviceDebug) {
379
- this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
380
- + ` Error Message: ${JSON.stringify(e.message)}`);
381
- }
382
- if (this.debugDebug) {
383
- this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
384
- + ` Error: ${JSON.stringify(e)}`);
385
- }
386
- if (this.platform.config.credentials?.openToken) {
387
- this.platform.log.warn(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
388
- await this.openAPIpushChanges();
389
- }
390
- this.apiError(e);
391
- });
392
- } else {
393
- this.platform.log.error(`Bot: ${this.accessory.displayName} Mode Not Set, mode: ${this.device.bot?.mode}`);
398
+ } else {
399
+ this.platform.log.error(`Bot: ${this.accessory.displayName} Mode Not Set, mode: ${this.device.bot?.mode}`);
400
+ }
394
401
  }
402
+ this.OnCached = this.On;
403
+ this.accessory.context.On = this.OnCached;
395
404
  }
396
405
 
397
406
  private turnOnOff(device_list: any) {
@@ -405,35 +414,39 @@ export class Bot {
405
414
  private async openAPIpushChanges() {
406
415
  if (this.platform.config.credentials?.openToken) {
407
416
  try {
408
- this.platform.debug(`Bot: ${this.accessory.displayName} OpenAPI pushChanges`);
409
- const payload = {
410
- commandType: 'command',
411
- parameter: 'default',
412
- } as payload;
413
-
414
- if (this.device.bot?.mode === 'switch' && this.On) {
415
- payload.command = 'turnOn';
416
- this.On = true;
417
- this.platform.debug(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
418
- } else if (this.device.bot?.mode === 'switch' && !this.On) {
419
- payload.command = 'turnOff';
420
- this.On = false;
421
- this.platform.debug(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
422
- } else if (this.device.bot?.mode === 'press') {
423
- payload.command = 'press';
424
- this.platform.debug(`Bot: ${this.accessory.displayName} Press Mode`);
425
- this.On = false;
426
- } else {
427
- throw new Error(`Bot: ${this.accessory.displayName} Device Paramters not set for this Bot.`);
428
- }
417
+ if (this.On !== this.OnCached) {
418
+ this.platform.debug(`Bot: ${this.accessory.displayName} OpenAPI pushChanges`);
419
+ const payload = {
420
+ commandType: 'command',
421
+ parameter: 'default',
422
+ } as payload;
423
+
424
+ if (this.device.bot?.mode === 'switch' && this.On) {
425
+ payload.command = 'turnOn';
426
+ this.On = true;
427
+ this.platform.debug(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
428
+ } else if (this.device.bot?.mode === 'switch' && !this.On) {
429
+ payload.command = 'turnOff';
430
+ this.On = false;
431
+ this.platform.debug(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
432
+ } else if (this.device.bot?.mode === 'press') {
433
+ payload.command = 'press';
434
+ this.platform.debug(`Bot: ${this.accessory.displayName} Press Mode`);
435
+ this.On = false;
436
+ } else {
437
+ throw new Error(`Bot: ${this.accessory.displayName} Device Paramters not set for this Bot.`);
438
+ }
429
439
 
430
- this.platform.log.info(`Bot: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
431
- + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
440
+ this.platform.log.info(`Bot: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
441
+ + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
432
442
 
433
- // Make the API request
434
- const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
435
- this.platform.debug(`Bot ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
436
- this.statusCode(push);
443
+ // Make the API request
444
+ const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
445
+ this.platform.debug(`Bot ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
446
+ this.statusCode(push);
447
+ this.OnCached = this.On;
448
+ this.accessory.context.On = this.OnCached;
449
+ }
437
450
  } catch (e: any) {
438
451
  this.platform.log.error(`Bot: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
439
452
  if (this.deviceDebug) {
@@ -504,15 +517,11 @@ export class Bot {
504
517
  break;
505
518
  case 161:
506
519
  this.platform.log.error(`Bot: ${this.accessory.displayName} Device is offline.`);
507
- if (this.device.offline) {
508
- this.On = false;
509
- }
520
+ this.offlineOff();
510
521
  break;
511
522
  case 171:
512
523
  this.platform.log.error(`Bot: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
513
- if (this.device.offline) {
514
- this.On = false;
515
- }
524
+ this.offlineOff();
516
525
  break;
517
526
  case 190:
518
527
  this.platform.log.error(`Bot: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,`
@@ -526,6 +535,17 @@ export class Bot {
526
535
  }
527
536
  }
528
537
 
538
+ private offlineOff() {
539
+ if (this.device.offline) {
540
+ this.On = false;
541
+ if (this.device.bot?.deviceType === 'switch') {
542
+ this.switchService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
543
+ } else {
544
+ this.outletService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
545
+ }
546
+ }
547
+ }
548
+
529
549
  /**
530
550
  * Handle requests to set the "On" characteristic
531
551
  */
@@ -56,13 +56,17 @@ export class ColorBulb {
56
56
  this.platform.device(`Color Bulb: ${this.accessory.displayName} Config: (ble: ${device.ble}, set_minStep: ${device.colorbulb?.set_minStep}`);
57
57
 
58
58
  // default placeholders
59
- this.minKelvin = 2000;
60
- this.maxKelvin = 9000;
59
+ if (this.On === undefined) {
60
+ this.On = false;
61
+ } else {
62
+ this.On = this.accessory.context.On;
63
+ }
61
64
  this.Hue = 0;
62
- this.On = false;
63
65
  this.Brightness = 0;
64
66
  this.Saturation = 0;
65
67
  this.ColorTemperature = 140;
68
+ this.minKelvin = 2000;
69
+ this.maxKelvin = 9000;
66
70
 
67
71
  // this is subject we use to track when we need to POST changes to the SwitchBot API
68
72
  this.doColorBulbUpdate = new Subject();
@@ -299,6 +303,7 @@ export class ColorBulb {
299
303
  this.platform.debug(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
300
304
  this.statusCode(push);
301
305
  this.OnCached = this.On;
306
+ this.accessory.context.On = this.OnCached;
302
307
  }
303
308
  // Push Brightness Update
304
309
  if (this.On) {
@@ -498,15 +503,11 @@ export class ColorBulb {
498
503
  break;
499
504
  case 161:
500
505
  this.platform.log.error(`Color Bulb: ${this.accessory.displayName} Device is offline.`);
501
- if (this.device.offline) {
502
- this.On = false;
503
- }
506
+ this.offlineOff();
504
507
  break;
505
508
  case 171:
506
509
  this.platform.log.error(`Color Bulb: ${this.accessory.displayName} is offline. Hub: ${this.device.hubDeviceId}`);
507
- if (this.device.offline) {
508
- this.On = false;
509
- }
510
+ this.offlineOff();
510
511
  break;
511
512
  case 190:
512
513
  this.platform.log.error(`Color Bulb: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,`
@@ -520,6 +521,13 @@ export class ColorBulb {
520
521
  }
521
522
  }
522
523
 
524
+ private offlineOff() {
525
+ if (this.device.offline) {
526
+ this.On = false;
527
+ this.service.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
528
+ }
529
+ }
530
+
523
531
  /**
524
532
  * Handle requests to set the value of the "On" characteristic
525
533
  */
@@ -50,7 +50,7 @@ export class Contact {
50
50
  public device: device & devicesConfig,
51
51
  ) {
52
52
  // Contact Config
53
- this.platform.device(`Contact Sensor: ${this.accessory.displayName} Config: (ble: ${device.ble},`
53
+ this.platform.device(`Contact Sensor: ${this.accessory.displayName} Config: (ble: ${device.ble}, offline: ${device.offline},`
54
54
  + ` hide_lightsensor: ${device.contact?.hide_lightsensor}, hide_motionsensor: ${device.contact?.hide_motionsensor})`);
55
55
 
56
56
 
@@ -50,7 +50,7 @@ export class Humidifier {
50
50
  public device: device & devicesConfig,
51
51
  ) {
52
52
  // Humidifiers Config
53
- this.platform.device(`Humidifier: ${this.accessory.displayName} Config: (ble: ${device.ble}, hide_temperature: `
53
+ this.platform.device(`Humidifier: ${this.accessory.displayName} Config: (ble: ${device.ble}, offline: ${device.offline}, hide_temperature: `
54
54
  + `${device.humidifier?.hide_temperature}, set_minStep: ${device.humidifier?.set_minStep})`);
55
55
 
56
56
  // default placeholders
@@ -633,15 +633,11 @@ export class Humidifier {
633
633
  break;
634
634
  case 161:
635
635
  this.platform.log.error(`Humidifier: ${this.accessory.displayName} Device is offline.`);
636
- if (this.device.offline) {
637
- this.Active = false;
638
- }
636
+ this.offlineOff();
639
637
  break;
640
638
  case 171:
641
639
  this.platform.log.error(`Humidifier: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
642
- if (this.device.offline) {
643
- this.Active = false;
644
- }
640
+ this.offlineOff();
645
641
  break;
646
642
  case 190:
647
643
  this.platform.log.error(`Humidifier: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,`
@@ -655,6 +651,13 @@ export class Humidifier {
655
651
  }
656
652
  }
657
653
 
654
+ private offlineOff() {
655
+ if (this.device.offline) {
656
+ this.Active = this.platform.Characteristic.Active.INACTIVE;
657
+ this.service.getCharacteristic(this.platform.Characteristic.Active).updateValue(this.Active);
658
+ }
659
+ }
660
+
658
661
  /**
659
662
  * Handle requests to set the "Target Humidifier Dehumidifier State" characteristic
660
663
  */
@@ -3,7 +3,7 @@ import { interval, Subject } from 'rxjs';
3
3
  import { skipWhile } from 'rxjs/operators';
4
4
  import { SwitchBotPlatform } from '../platform';
5
5
  import { Service, PlatformAccessory, Units, CharacteristicValue } from 'homebridge';
6
- import { DeviceURL, device, devicesConfig, serviceData, ad, switchbot, deviceStatusResponse } from '../settings';
6
+ import { DeviceURL, device, devicesConfig, serviceData, ad, switchbot, deviceStatusResponse, temperature } from '../settings';
7
7
 
8
8
  /**
9
9
  * Platform Accessory
@@ -18,8 +18,11 @@ export class Meter {
18
18
 
19
19
  // Characteristic Values
20
20
  CurrentRelativeHumidity!: CharacteristicValue;
21
+ CurrentRelativeHumidityCached!: CharacteristicValue;
21
22
  CurrentTemperature!: CharacteristicValue;
23
+ CurrentTemperatureCached!: CharacteristicValue;
22
24
  BatteryLevel!: CharacteristicValue;
25
+ BatteryLevelCached!: CharacteristicValue;
23
26
  ChargingState!: CharacteristicValue;
24
27
  StatusLowBattery!: CharacteristicValue;
25
28
  Active!: CharacteristicValue;
@@ -32,10 +35,9 @@ export class Meter {
32
35
  connected?: boolean;
33
36
  switchbot!: switchbot;
34
37
  serviceData!: serviceData;
38
+ temperature!: temperature['c'];
35
39
  battery!: serviceData['battery'];
36
40
  humidity!: serviceData['humidity'];
37
- fahrenheit!: serviceData['fahrenheit'];
38
- temperature!: serviceData['temperature'];
39
41
 
40
42
  // Config
41
43
  private readonly deviceDebug = this.platform.config.options?.debug === 'device' || this.platform.debugMode;
@@ -51,15 +53,31 @@ export class Meter {
51
53
  public device: device & devicesConfig,
52
54
  ) {
53
55
  // Meter Config
54
- this.platform.device(`Meter: ${this.accessory.displayName} Config: (ble: ${device.ble}, unit: ${device.meter?.unit},`
55
- + ` hide_temperature: ${device.meter?.hide_temperature}, hide_humidity: ${device.meter?.hide_humidity})`);
56
+ this.platform.device(`Meter: ${this.accessory.displayName} Config: (ble: ${device.ble}, hide_temperature: ${device.meter?.hide_temperature},`
57
+ + ` hide_humidity: ${device.meter?.hide_humidity})`);
56
58
 
57
59
  // default placeholders
58
- this.BatteryLevel = 0;
59
- this.ChargingState = 2;
60
- this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
61
- this.CurrentRelativeHumidity = 0;
62
- this.CurrentTemperature = 0;
60
+ if (this.BatteryLevel === undefined) {
61
+ this.BatteryLevel = 100;
62
+ } else {
63
+ this.BatteryLevel = this.accessory.context.BatteryLevel;
64
+ }
65
+ if (this.BatteryLevel < 15) {
66
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
67
+ } else {
68
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
69
+ }
70
+ this.ChargingState = this.platform.Characteristic.ChargingState.NOT_CHARGEABLE;
71
+ if (this.CurrentRelativeHumidity === undefined) {
72
+ this.CurrentRelativeHumidity = 0;
73
+ } else {
74
+ this.CurrentRelativeHumidity = this.accessory.context.CurrentRelativeHumidity;
75
+ }
76
+ if (this.CurrentTemperature === undefined) {
77
+ this.CurrentTemperature = 0;
78
+ } else {
79
+ this.CurrentTemperature = this.accessory.context.CurrentTemperature;
80
+ }
63
81
 
64
82
  // this is subject we use to track when we need to POST changes to the SwitchBot API
65
83
  this.doMeterUpdate = new Subject();
@@ -177,9 +195,9 @@ export class Meter {
177
195
  // Battery
178
196
  this.BatteryLevel = Number(this.battery);
179
197
  if (this.BatteryLevel < 15) {
180
- this.StatusLowBattery = 1;
198
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
181
199
  } else {
182
- this.StatusLowBattery = 0;
200
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
183
201
  }
184
202
  this.platform.debug(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
185
203
 
@@ -191,13 +209,8 @@ export class Meter {
191
209
 
192
210
  // Current Temperature
193
211
  if (!this.device.meter?.hide_temperature) {
194
- if (this.device.meter?.unit === 1) {
195
- this.CurrentTemperature = this.toFahrenheit(this.temperature!.c);
196
- } else if (this.device.meter?.unit === 0) {
197
- this.CurrentTemperature = this.toCelsius(this.temperature!.c);
198
- } else {
199
- this.CurrentTemperature = Number(this.temperature?.c);
200
- }
212
+ this.temperature < 0 ? 0 : this.temperature > 100 ? 100 : this.temperature;
213
+ this.CurrentTemperature = this.temperature;
201
214
  this.platform.debug(`Meter: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
202
215
  }
203
216
  }
@@ -211,9 +224,9 @@ export class Meter {
211
224
  this.BatteryLevel = 10;
212
225
  }
213
226
  if (this.BatteryLevel < 15) {
214
- this.StatusLowBattery = 1;
227
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
215
228
  } else {
216
- this.StatusLowBattery = 0;
229
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
217
230
  }
218
231
  // Current Relative Humidity
219
232
  if (!this.device.meter?.hide_humidity) {
@@ -223,13 +236,7 @@ export class Meter {
223
236
 
224
237
  // Current Temperature
225
238
  if (!this.device.meter?.hide_temperature) {
226
- if (this.device.meter?.unit === 1) {
227
- this.CurrentTemperature = this.toFahrenheit(this.deviceStatus.body.temperature!);
228
- } else if (this.device.meter?.unit === 0) {
229
- this.CurrentTemperature = this.toCelsius(this.deviceStatus.body.temperature!);
230
- } else {
231
- this.CurrentTemperature = Number(this.deviceStatus.body.temperature);
232
- }
239
+ this.CurrentTemperature = Number(this.deviceStatus.body.temperature);
233
240
  this.platform.debug(`Meter: ${this.accessory.displayName} Temperature: ${this.CurrentTemperature}°c`);
234
241
  }
235
242
  }
@@ -259,20 +266,18 @@ export class Meter {
259
266
  const switchbot = this.connectBLE();
260
267
  // Start to monitor advertisement packets
261
268
  switchbot.startScan({
262
- model: 'T',
263
269
  id: this.device.bleMac,
264
270
  }).then(() => {
265
271
  // Set an event hander
266
272
  switchbot.onadvertisement = (ad: ad) => {
267
273
  this.serviceData = ad.serviceData;
268
- this.temperature = ad.serviceData.temperature;
269
- this.fahrenheit = ad.serviceData.fahrenheit;
274
+ this.temperature = ad.serviceData.temperature!.c;
270
275
  this.humidity = ad.serviceData.humidity;
271
276
  this.battery = ad.serviceData.battery;
272
277
  this.platform.device(`Meter: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
273
278
  this.platform.device(`Meter: ${this.accessory.displayName} model: ${ad.serviceData.model}, modelName: ${ad.serviceData.modelName}, `
274
- + `temperature: ${JSON.stringify(ad.serviceData.temperature)}, fahrenheit: ${ad.serviceData.fahrenheit}, `
275
- + `humidity: ${ad.serviceData.humidity}, battery: ${ad.serviceData.battery}`);
279
+ + `temperature: ${JSON.stringify(ad.serviceData.temperature?.c)}, humidity: ${ad.serviceData.humidity}, `
280
+ + `battery: ${ad.serviceData.battery}`);
276
281
 
277
282
  if (this.serviceData) {
278
283
  this.connected = true;
@@ -288,6 +293,12 @@ export class Meter {
288
293
  // Stop to monitor
289
294
  switchbot.stopScan();
290
295
  if (this.connected) {
296
+ this.CurrentTemperatureCached = this.temperature;
297
+ this.accessory.context.CurrentTemperature = this.CurrentTemperatureCached;
298
+ this.CurrentRelativeHumidityCached = this.humidity!;
299
+ this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidityCached;
300
+ this.BatteryLevelCached = this.battery!;
301
+ this.accessory.context.BatteryLevel = this.BatteryLevelCached;
291
302
  this.parseStatus();
292
303
  this.updateHomeKitCharacteristics();
293
304
  } else {
@@ -321,6 +332,12 @@ export class Meter {
321
332
  try {
322
333
  this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
323
334
  this.platform.debug(`Meter: ${this.accessory.displayName} openAPIRefreshStatus: ${JSON.stringify(this.deviceStatus)}`);
335
+ this.CurrentTemperatureCached = this.deviceStatus.body.humidity!;
336
+ this.accessory.context.CurrentTemperature = this.CurrentTemperatureCached;
337
+ this.CurrentRelativeHumidityCached = this.deviceStatus.body.humidity!;
338
+ this.accessory.context.CurrentRelativeHumidity = this.CurrentRelativeHumidityCached;
339
+ this.BatteryLevelCached = 100;
340
+ this.accessory.context.BatteryLevel = this.BatteryLevelCached;
324
341
  this.parseStatus();
325
342
  this.updateHomeKitCharacteristics();
326
343
  } catch (e: any) {
@@ -382,19 +399,4 @@ export class Meter {
382
399
  this.temperatureservice?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e);
383
400
  }
384
401
  }
385
-
386
- /**
387
- * Converts the value to celsius if the temperature units are in Fahrenheit
388
- */
389
- toCelsius(value: number) {
390
- // celsius should be to the nearest 0.5 degree
391
- return Math.round((5 / 9) * (value - 32) * 2) / 2;
392
- }
393
-
394
- /**
395
- * Converts the value to fahrenheit if the temperature units are in Fahrenheit
396
- */
397
- toFahrenheit(value: number) {
398
- return Math.round((value * 9) / 5 + 32);
399
- }
400
402
  }
@@ -12,6 +12,7 @@ export class Plug {
12
12
 
13
13
  // Characteristic Values
14
14
  On!: CharacteristicValue;
15
+ OnCached!: CharacteristicValue;
15
16
 
16
17
  // OpenAPI Others
17
18
  deviceStatus!: deviceStatusResponse;
@@ -29,8 +30,15 @@ export class Plug {
29
30
  private accessory: PlatformAccessory,
30
31
  public device: device & devicesConfig,
31
32
  ) {
33
+ // Bot Config
34
+ this.platform.device(`Plug: ${this.accessory.displayName} Config: (offline: ${device.offline})`);
35
+
32
36
  // default placeholders
33
- this.On = false;
37
+ if (this.On === undefined) {
38
+ this.On = false;
39
+ } else {
40
+ this.On = this.accessory.context.On;
41
+ }
34
42
 
35
43
  // this is subject we use to track when we need to POST changes to the SwitchBot API
36
44
  this.doPlugUpdate = new Subject();
@@ -142,24 +150,28 @@ export class Plug {
142
150
  * Plug - "command" "turnOn" "default" = set to ON state
143
151
  */
144
152
  async pushChanges() {
145
- const payload = {
146
- commandType: 'command',
147
- parameter: 'default',
148
- } as payload;
149
-
150
- if (this.On) {
151
- payload.command = 'turnOn';
152
- } else {
153
- payload.command = 'turnOff';
154
- }
153
+ if (this.On !== this.OnCached) {
154
+ const payload = {
155
+ commandType: 'command',
156
+ parameter: 'default',
157
+ } as payload;
158
+
159
+ if (this.On) {
160
+ payload.command = 'turnOn';
161
+ } else {
162
+ payload.command = 'turnOff';
163
+ }
155
164
 
156
- this.platform.log.info(`Plug: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
157
- + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
165
+ this.platform.log.info(`Plug: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},`
166
+ + ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`);
158
167
 
159
- // Make the API request
160
- const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
161
- this.platform.debug(`Plug: ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
162
- this.statusCode(push);
168
+ // Make the API request
169
+ const push: any = (await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload));
170
+ this.platform.debug(`Plug: ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
171
+ this.statusCode(push);
172
+ this.OnCached = this.On;
173
+ this.accessory.context.On = this.OnCached;
174
+ }
163
175
  interval(5000)
164
176
  .pipe(skipWhile(() => this.plugUpdateInProgress))
165
177
  .pipe(take(1))
@@ -194,15 +206,11 @@ export class Plug {
194
206
  break;
195
207
  case 161:
196
208
  this.platform.log.error(`Plug: ${this.accessory.displayName} Device is offline.`);
197
- if (this.device.offline) {
198
- this.On = false;
199
- }
209
+ this.offlineOff();
200
210
  break;
201
211
  case 171:
202
212
  this.platform.log.error(`Plug: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
203
- if (this.device.offline) {
204
- this.On = false;
205
- }
213
+ this.offlineOff();
206
214
  break;
207
215
  case 190:
208
216
  this.platform.log.error(`Plug: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,`
@@ -216,6 +224,13 @@ export class Plug {
216
224
  }
217
225
  }
218
226
 
227
+ private offlineOff() {
228
+ if (this.device.offline) {
229
+ this.On = false;
230
+ this.service.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
231
+ }
232
+ }
233
+
219
234
  /**
220
235
  * Handle requests to set the value of the "On" characteristic
221
236
  */
@@ -14,9 +14,11 @@ export class AirConditioner {
14
14
 
15
15
  // Characteristic Values
16
16
  Active!: CharacteristicValue;
17
+ ActiveCached!: CharacteristicValue;
17
18
  RotationSpeed!: CharacteristicValue;
18
19
  LastTemperature!: CharacteristicValue;
19
20
  CurrentTemperature!: CharacteristicValue;
21
+ CurrentTemperatureCached!: CharacteristicValue;
20
22
  TargetHeaterCoolerState?: CharacteristicValue;
21
23
  CurrentHeaterCoolerState!: CharacteristicValue;
22
24
  HeatingThresholdTemperature?: CharacteristicValue;
@@ -41,7 +43,17 @@ export class AirConditioner {
41
43
  private accessory: PlatformAccessory,
42
44
  public device: irdevice & irDevicesConfig,
43
45
  ) {
44
- this.CurrentTemperature = 24;
46
+ // default placeholders
47
+ if (this.Active === undefined) {
48
+ this.Active = this.platform.Characteristic.Active.INACTIVE;
49
+ } else {
50
+ this.Active = this.accessory.context.Active;
51
+ }
52
+ if (this.CurrentTemperature === undefined) {
53
+ this.CurrentTemperature = 24;
54
+ } else {
55
+ this.CurrentTemperature = this.accessory.context.CurrentTemperature;
56
+ }
45
57
 
46
58
  // set accessory information
47
59
  accessory
@@ -161,6 +173,8 @@ export class AirConditioner {
161
173
  this.platform.device(`Air Conditioner: ${this.accessory.displayName} pushAirConditionerOffChanges, Active: ${this.Active}`);
162
174
  }
163
175
  this.Active = value;
176
+ this.ActiveCached = this.Active;
177
+ this.accessory.context.Active = this.ActiveCached;
164
178
  }
165
179
 
166
180
  private updateHomeKitCharacteristics() {
@@ -349,6 +363,8 @@ export class AirConditioner {
349
363
  const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
350
364
  this.platform.log.error(`Air Conditioner: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
351
365
  this.statusCode(push);
366
+ this.CurrentTemperatureCached = this.CurrentTemperature;
367
+ this.accessory.context.CurrentTemperature = this.CurrentTemperatureCached;
352
368
  this.updateHomeKitCharacteristics();
353
369
  } catch (e: any) {
354
370
  this.platform.log.error(`Air Conditioner: ${this.accessory.displayName} failed pushChanges`);