@switchbot/homebridge-switchbot 0.2.0-alpha.2 → 1.0.1-beta.2

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 (99) hide show
  1. package/.github/workflows/nodejs-beta.yml +1 -1
  2. package/.github/workflows/nodejs.yml +1 -1
  3. package/.github/workflows/{prerelease.js → prerelease-beta.js} +0 -0
  4. package/CHANGELOG.md +1 -1
  5. package/README.md +9 -5
  6. package/config.schema.json +370 -142
  7. package/dist/devices/bots.d.ts +18 -34
  8. package/dist/devices/bots.d.ts.map +1 -1
  9. package/dist/devices/bots.js +166 -171
  10. package/dist/devices/bots.js.map +1 -1
  11. package/dist/devices/{bulb.d.ts → colorbulb.d.ts} +12 -19
  12. package/dist/devices/colorbulb.d.ts.map +1 -0
  13. package/dist/devices/{bulb.js → colorbulb.js} +34 -32
  14. package/dist/devices/colorbulb.js.map +1 -0
  15. package/dist/devices/contact.d.ts +18 -16
  16. package/dist/devices/contact.d.ts.map +1 -1
  17. package/dist/devices/contact.js +101 -44
  18. package/dist/devices/contact.js.map +1 -1
  19. package/dist/devices/curtains.d.ts +17 -51
  20. package/dist/devices/curtains.d.ts.map +1 -1
  21. package/dist/devices/curtains.js +170 -248
  22. package/dist/devices/curtains.js.map +1 -1
  23. package/dist/devices/humidifiers.d.ts +13 -4
  24. package/dist/devices/humidifiers.d.ts.map +1 -1
  25. package/dist/devices/humidifiers.js +81 -8
  26. package/dist/devices/humidifiers.js.map +1 -1
  27. package/dist/devices/indoorcam.d.ts +6 -13
  28. package/dist/devices/indoorcam.d.ts.map +1 -1
  29. package/dist/devices/indoorcam.js.map +1 -1
  30. package/dist/devices/meters.d.ts +12 -15
  31. package/dist/devices/meters.d.ts.map +1 -1
  32. package/dist/devices/meters.js +38 -44
  33. package/dist/devices/meters.js.map +1 -1
  34. package/dist/devices/motion.d.ts +17 -15
  35. package/dist/devices/motion.d.ts.map +1 -1
  36. package/dist/devices/motion.js +87 -40
  37. package/dist/devices/motion.js.map +1 -1
  38. package/dist/devices/plugs.d.ts +6 -13
  39. package/dist/devices/plugs.d.ts.map +1 -1
  40. package/dist/devices/plugs.js.map +1 -1
  41. package/dist/irdevices/airconditioners.d.ts +10 -10
  42. package/dist/irdevices/airconditioners.d.ts.map +1 -1
  43. package/dist/irdevices/airconditioners.js +29 -9
  44. package/dist/irdevices/airconditioners.js.map +1 -1
  45. package/dist/irdevices/airpurifiers.d.ts +11 -11
  46. package/dist/irdevices/airpurifiers.d.ts.map +1 -1
  47. package/dist/irdevices/airpurifiers.js.map +1 -1
  48. package/dist/irdevices/cameras.d.ts +3 -3
  49. package/dist/irdevices/cameras.d.ts.map +1 -1
  50. package/dist/irdevices/cameras.js.map +1 -1
  51. package/dist/irdevices/fans.d.ts +6 -6
  52. package/dist/irdevices/fans.d.ts.map +1 -1
  53. package/dist/irdevices/fans.js +10 -10
  54. package/dist/irdevices/fans.js.map +1 -1
  55. package/dist/irdevices/lights.d.ts +3 -3
  56. package/dist/irdevices/lights.d.ts.map +1 -1
  57. package/dist/irdevices/lights.js.map +1 -1
  58. package/dist/irdevices/others.d.ts +3 -3
  59. package/dist/irdevices/others.d.ts.map +1 -1
  60. package/dist/irdevices/others.js.map +1 -1
  61. package/dist/irdevices/tvs.d.ts +3 -3
  62. package/dist/irdevices/tvs.d.ts.map +1 -1
  63. package/dist/irdevices/tvs.js +7 -5
  64. package/dist/irdevices/tvs.js.map +1 -1
  65. package/dist/irdevices/vacuumcleaners.d.ts +3 -3
  66. package/dist/irdevices/vacuumcleaners.d.ts.map +1 -1
  67. package/dist/irdevices/vacuumcleaners.js.map +1 -1
  68. package/dist/irdevices/waterheaters.d.ts +3 -3
  69. package/dist/irdevices/waterheaters.d.ts.map +1 -1
  70. package/dist/irdevices/waterheaters.js.map +1 -1
  71. package/dist/platform.d.ts +3 -2
  72. package/dist/platform.d.ts.map +1 -1
  73. package/dist/platform.js +136 -46
  74. package/dist/platform.js.map +1 -1
  75. package/dist/settings.d.ts +51 -8
  76. package/dist/settings.d.ts.map +1 -1
  77. package/package.json +65 -65
  78. package/src/devices/bots.ts +188 -193
  79. package/src/devices/{bulb.ts → colorbulb.ts} +46 -51
  80. package/src/devices/contact.ts +124 -68
  81. package/src/devices/curtains.ts +192 -300
  82. package/src/devices/humidifiers.ts +97 -14
  83. package/src/devices/indoorcam.ts +10 -20
  84. package/src/devices/meters.ts +57 -69
  85. package/src/devices/motion.ts +108 -62
  86. package/src/devices/plugs.ts +8 -19
  87. package/src/irdevices/airconditioners.ts +43 -20
  88. package/src/irdevices/airpurifiers.ts +15 -11
  89. package/src/irdevices/cameras.ts +5 -3
  90. package/src/irdevices/fans.ts +22 -16
  91. package/src/irdevices/lights.ts +5 -3
  92. package/src/irdevices/others.ts +5 -3
  93. package/src/irdevices/tvs.ts +13 -7
  94. package/src/irdevices/vacuumcleaners.ts +5 -3
  95. package/src/irdevices/waterheaters.ts +5 -3
  96. package/src/platform.ts +148 -49
  97. package/src/settings.ts +80 -8
  98. package/dist/devices/bulb.d.ts.map +0 -1
  99. package/dist/devices/bulb.js.map +0 -1
@@ -1,46 +1,34 @@
1
1
  /// <reference types="node" />
2
- import { PlatformAccessory, CharacteristicValue, MacAddress } from 'homebridge';
2
+ import { PlatformAccessory, CharacteristicValue } from 'homebridge';
3
3
  import { SwitchBotPlatform } from '../platform';
4
- import { device, devicesConfig } from '../settings';
4
+ import { Subject } from 'rxjs';
5
+ import { device, devicesConfig, serviceData, switchbot, deviceStatusResponse } from '../settings';
5
6
  export declare class Curtain {
6
7
  private readonly platform;
7
8
  private accessory;
8
9
  device: device & devicesConfig;
9
10
  private service;
10
11
  private lightSensorService;
12
+ private batteryService?;
11
13
  CurrentPosition: CharacteristicValue;
12
14
  PositionState: CharacteristicValue;
13
15
  TargetPosition: CharacteristicValue;
14
16
  CurrentAmbientLightLevel: CharacteristicValue;
15
- deviceStatus: any;
16
- moveTimer: NodeJS.Timeout;
17
- ScanIntervalId: NodeJS.Timeout;
18
- setNewTargetTimer: NodeJS.Timeout;
19
- AutoDisableFastScanTimeoutId: NodeJS.Timeout;
17
+ BatteryLevel?: CharacteristicValue;
18
+ StatusLowBattery?: CharacteristicValue;
19
+ deviceStatus: deviceStatusResponse;
20
20
  setNewTarget: boolean;
21
- moveTime: number;
22
- ScanDuration: any;
23
- ReverseDir: any;
24
- FastScanEnabled: boolean;
25
- FastScanInterval: number;
26
- SlowScanInterval: number;
27
- OpenCloseThreshold: any;
28
- PreviousPosition: any;
29
- Position: any;
30
- FastScanDuration: number | undefined;
21
+ setNewTargetTimer: NodeJS.Timeout;
22
+ switchbot: switchbot;
23
+ serviceData: serviceData;
24
+ calibration: serviceData['calibration'];
25
+ battery: serviceData['battery'];
26
+ position: serviceData['position'];
27
+ lightLevel: serviceData['lightLevel'];
31
28
  set_minStep: number;
32
29
  refreshRate: number;
33
- switchbot: {
34
- discover: (arg0: {
35
- duration: any;
36
- model: string;
37
- quick: boolean;
38
- id: MacAddress;
39
- }) => Promise<any>;
40
- wait: (arg0: number) => any;
41
- };
42
30
  curtainUpdateInProgress: boolean;
43
- doCurtainUpdate: any;
31
+ doCurtainUpdate: Subject<void>;
44
32
  constructor(platform: SwitchBotPlatform, accessory: PlatformAccessory, device: device & devicesConfig);
45
33
  private curtainRefreshRate;
46
34
  private minStep;
@@ -48,7 +36,8 @@ export declare class Curtain {
48
36
  private BLEparseStatus;
49
37
  private openAPIparseStatus;
50
38
  refreshStatus(): Promise<void>;
51
- private BLErefreshStatus;
39
+ private connectBLE;
40
+ private BLERefreshStatus;
52
41
  private openAPIRefreshStatus;
53
42
  pushChanges(): Promise<void>;
54
43
  private BLEpushChanges;
@@ -60,29 +49,6 @@ export declare class Curtain {
60
49
  * Handle requests to set the value of the "Target Position" characteristic
61
50
  */
62
51
  TargetPositionSet(value: CharacteristicValue): void;
63
- /**
64
- * Convert to/from device/HomeKit's position, since:
65
- *
66
- * - opened is 0% in HomeKit and 100% in Curtain device.
67
- * - closed is 100% in HomeKit, 0% in Curtain device.
68
- */
69
- convertFromHomeKitPosition(n: number): number;
70
- /**
71
- * Ask the device to start moving to the given position (which must be a device value and not an HomeKit value).
72
- * Returns a Promise that's resolved as soon as the command was sent to the device.
73
- */
74
- runToPosition(pos: number): Promise<void>;
75
- /**
76
- * Start a faster scan loop (using fastScanInterval). Used in calls to `runToPosition` to
77
- * report quicker on device position change. Will disable on its own as soon if the curtain's
78
- * device position does not change for more than `fastScanDuration`.
79
- */
80
- private startFastScan;
81
- private stopFastScan;
82
- private get scanInterval();
83
- private startScanLoop;
84
- private scan;
85
- private applyPosition;
86
52
  setMinMax(): void;
87
53
  }
88
54
  //# sourceMappingURL=curtains.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"curtains.d.ts","sourceRoot":"","sources":["../../src/devices/curtains.ts"],"names":[],"mappings":";AACA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAa,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,qBAAa,OAAO;IAkDhB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,SAAS;IACV,MAAM,EAAE,MAAM,GAAG,aAAa;IAlDvC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,kBAAkB,CAAU;IAGpC,eAAe,EAAG,mBAAmB,CAAC;IACtC,aAAa,EAAG,mBAAmB,CAAC;IACpC,cAAc,EAAG,mBAAmB,CAAC;IACrC,wBAAwB,EAAG,mBAAmB,CAAC;IAG/C,YAAY,EAAG,GAAG,CAAC;IACnB,SAAS,EAAG,MAAM,CAAC,OAAO,CAAC;IAC3B,cAAc,EAAG,MAAM,CAAC,OAAO,CAAC;IAChC,iBAAiB,EAAG,MAAM,CAAC,OAAO,CAAC;IACnC,4BAA4B,EAAG,MAAM,CAAC,OAAO,CAAC;IAC9C,YAAY,EAAG,OAAO,CAAC;IACvB,QAAQ,EAAG,MAAM,CAAC;IAClB,YAAY,EAAE,GAAG,CAAC;IAClB,UAAU,EAAE,GAAG,CAAC;IAChB,eAAe,EAAG,OAAO,CAAC;IAC1B,gBAAgB,EAAG,MAAM,CAAC;IAC1B,gBAAgB,EAAG,MAAM,CAAC;IAC1B,kBAAkB,EAAE,GAAG,CAAC;IACxB,gBAAgB,EAAE,GAAG,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC;IACd,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,WAAW,EAAG,MAAM,CAAC;IACrB,WAAW,EAAG,MAAM,CAAC;IACrB,SAAS,EAAG;QACV,QAAQ,EAAE,CACR,IAAI,EACF;YACE,QAAQ,EAAE,GAAG,CAAC;YACd,KAAK,EAAE,MAAM,CAAC;YACd,KAAK,EAAE,OAAO,CAAC;YACf,EAAE,EAAE,UAAU,CAAC;SAChB,KACA,OAAO,CAAC,GAAG,CAAC,CAAC;QAClB,IAAI,EAAE,CACJ,IAAI,EAAE,MAAM,KACT,GAAG,CAAC;KACV,CAAC;IAGF,uBAAuB,EAAG,OAAO,CAAC;IAClC,eAAe,MAAC;gBAGG,QAAQ,EAAE,iBAAiB,EACpC,SAAS,EAAE,iBAAiB,EAC7B,MAAM,EAAE,MAAM,GAAG,aAAa;IAqIvC,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,OAAO;IAST,WAAW;YAUH,cAAc;YAId,kBAAkB;IA2C1B,aAAa;YAUL,gBAAgB;YAkDhB,oBAAoB;IAc5B,WAAW;YAUH,cAAc;YAId,kBAAkB;IA8BhC,4BAA4B;IAoCrB,QAAQ,CAAC,CAAC,EAAE,GAAG;IAOtB,OAAO,CAAC,UAAU;IA4BlB;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,mBAAmB;IA6E5C;;;;;OAKG;IACH,0BAA0B,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAU7C;;;OAGG;IACU,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8BtD;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,YAAY;IAQpB,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,IAAI;IAqBZ,OAAO,CAAC,aAAa;IAyBd,SAAS;CAYjB"}
1
+ {"version":3,"file":"curtains.d.ts","sourceRoot":"","sources":["../../src/devices/curtains.ts"],"names":[],"mappings":";AACA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAY,OAAO,EAAE,MAAM,MAAM,CAAC;AAEzC,OAAO,EAAa,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAG7G,qBAAa,OAAO;IAoChB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,SAAS;IACV,MAAM,EAAE,MAAM,GAAG,aAAa;IApCvC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,cAAc,CAAC,CAAU;IAGjC,eAAe,EAAG,mBAAmB,CAAC;IACtC,aAAa,EAAG,mBAAmB,CAAC;IACpC,cAAc,EAAG,mBAAmB,CAAC;IACrC,wBAAwB,EAAG,mBAAmB,CAAC;IAC/C,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;IAGvC,YAAY,EAAG,oBAAoB,CAAC;IACpC,YAAY,EAAG,OAAO,CAAC;IACvB,iBAAiB,EAAG,MAAM,CAAC,OAAO,CAAC;IAGnC,SAAS,EAAG,SAAS,CAAC;IACtB,WAAW,EAAG,WAAW,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACxC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAClC,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IAGtC,WAAW,EAAG,MAAM,CAAC;IACrB,WAAW,EAAG,MAAM,CAAC;IAGrB,uBAAuB,EAAG,OAAO,CAAC;IAClC,eAAe,EAAG,OAAO,CAAC,IAAI,CAAC,CAAC;gBAGb,QAAQ,EAAE,iBAAiB,EACpC,SAAS,EAAE,iBAAiB,EAC7B,MAAM,EAAE,MAAM,GAAG,aAAa;IA+HvC,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,OAAO;IAST,WAAW;YAUH,cAAc;YA0Ed,kBAAkB;IA4C1B,aAAa;IAUnB,OAAO,CAAC,UAAU;YAWJ,gBAAgB;YAkChB,oBAAoB;IAc5B,WAAW;YAUH,cAAc;YAad,kBAAkB;IA6BhC,4BAA4B;IAiDrB,QAAQ,CAAC,CAAC,EAAE,GAAG;IAWtB,OAAO,CAAC,UAAU;IA4BlB;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,mBAAmB;IAgCrC,SAAS;CAYjB"}
@@ -9,12 +9,14 @@ class Curtain {
9
9
  this.platform = platform;
10
10
  this.accessory = accessory;
11
11
  this.device = device;
12
+ // Curtain Config
13
+ this.platform.device(`[Curtain Config] ble: ${device.ble}, disable_group: ${device.curtain?.disable_group},`
14
+ + ` refreshRate: ${device.curtain?.refreshRate}, set_max: ${device.curtain?.set_max}, set_min: ${device.curtain?.set_min},`
15
+ + ` set_minStep: ${device.curtain?.set_minStep}`);
12
16
  // default placeholders
13
- this.setMinMax();
14
17
  this.CurrentPosition = 0;
15
18
  this.TargetPosition = 0;
16
19
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
17
- this.ScanDuration = this.platform.config.options.refreshRate;
18
20
  // BLE Connection
19
21
  if (device.ble) {
20
22
  // eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -61,7 +63,7 @@ class Curtain {
61
63
  validValueRanges: [0, 100],
62
64
  })
63
65
  .onGet(() => {
64
- return Number.isNaN(this.CurrentPosition);
66
+ return this.CurrentPosition;
65
67
  });
66
68
  this.service
67
69
  .getCharacteristic(this.platform.Characteristic.TargetPosition)
@@ -75,15 +77,6 @@ class Curtain {
75
77
  accessory.getService(this.platform.Service.LightSensor) ||
76
78
  accessory.addService(this.platform.Service.LightSensor)), `${device.deviceName} Light Sensor`;
77
79
  this.lightSensorService.setCharacteristic(this.platform.Characteristic.Name, `${device.deviceName} Light Sensor`);
78
- // handle on / off events using the On characteristic
79
- this.lightSensorService.getCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel).onGet(() => {
80
- if (this.CurrentAmbientLightLevel === 'bright') {
81
- return 100000;
82
- }
83
- else {
84
- return 0.0001;
85
- }
86
- });
87
80
  // Update Homekit
88
81
  this.updateHomeKitCharacteristics();
89
82
  // Start an update interval
@@ -153,9 +146,81 @@ class Curtain {
153
146
  }
154
147
  async BLEparseStatus() {
155
148
  this.platform.device('Curtains BLE Device parseStatus');
149
+ this.CurrentPosition = 100 - Number(this.position);
150
+ this.setMinMax();
151
+ this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition - Device is Currently: ${this.CurrentPosition}`);
152
+ if (this.setNewTarget) {
153
+ this.platform.log.info(`Checking ${this.accessory.displayName} Status ...`);
154
+ }
155
+ if (this.setNewTarget) {
156
+ if (this.TargetPosition > this.CurrentPosition) {
157
+ this.platform.debug(`Curtain ${this.accessory.displayName} - Current position: ${this.CurrentPosition} closing`);
158
+ this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
159
+ }
160
+ else if (this.TargetPosition < this.CurrentPosition) {
161
+ this.platform.debug(`Curtain ${this.accessory.displayName} - Current position: ${this.CurrentPosition} opening`);
162
+ this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
163
+ }
164
+ else {
165
+ this.platform.debug(`Curtain ${this.CurrentPosition} - standby`);
166
+ this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
167
+ }
168
+ }
169
+ else {
170
+ this.platform.debug(`Curtain ${this.accessory.displayName} - Current position: ${this.CurrentPosition} standby`);
171
+ if (!this.setNewTarget) {
172
+ /*If Curtain calibration distance is short, there will be an error between the current percentage and the target percentage.*/
173
+ this.TargetPosition = this.CurrentPosition;
174
+ this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
175
+ }
176
+ }
177
+ // Brightness
178
+ switch (this.lightLevel) {
179
+ case 1:
180
+ this.CurrentAmbientLightLevel = 0.0001;
181
+ break;
182
+ case 2:
183
+ this.CurrentAmbientLightLevel = 100;
184
+ break;
185
+ case 3:
186
+ this.CurrentAmbientLightLevel = 200;
187
+ break;
188
+ case 4:
189
+ this.CurrentAmbientLightLevel = 4000;
190
+ break;
191
+ case 5:
192
+ this.CurrentAmbientLightLevel = 12000;
193
+ break;
194
+ case 6:
195
+ this.CurrentAmbientLightLevel = 28000;
196
+ break;
197
+ case 7:
198
+ this.CurrentAmbientLightLevel = 56000;
199
+ break;
200
+ case 8:
201
+ this.CurrentAmbientLightLevel = 75000;
202
+ break;
203
+ case 9:
204
+ this.CurrentAmbientLightLevel = 90000;
205
+ break;
206
+ case 10:
207
+ default:
208
+ this.CurrentAmbientLightLevel = 100000;
209
+ }
210
+ // Battery
211
+ this.BatteryLevel = Number(this.battery);
212
+ if (this.BatteryLevel < 10) {
213
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
214
+ }
215
+ else {
216
+ this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
217
+ }
218
+ this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},`
219
+ + ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`
220
+ + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
156
221
  }
157
222
  async openAPIparseStatus() {
158
- this.setMinMax();
223
+ this.platform.device('Curtains OpenAPI Device parseStatus');
159
224
  this.CurrentPosition = 100 - this.deviceStatus.body.slidePosition;
160
225
  this.setMinMax();
161
226
  this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition - Device is Currently: ${this.CurrentPosition}`);
@@ -189,77 +254,72 @@ class Curtain {
189
254
  case 'dim':
190
255
  this.CurrentAmbientLightLevel = 0.0001;
191
256
  break;
257
+ case 'bright':
192
258
  default:
193
259
  this.CurrentAmbientLightLevel = 100000;
194
260
  }
195
- this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}
196
- , TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState}
197
- , CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
261
+ this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},`
262
+ + ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`
263
+ + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
198
264
  }
199
265
  async refreshStatus() {
200
266
  if (this.device.ble) {
201
267
  this.platform.device('BLE');
202
- await this.BLErefreshStatus();
268
+ await this.BLERefreshStatus();
203
269
  }
204
270
  else {
205
271
  this.platform.device('OpenAPI');
206
272
  await this.openAPIRefreshStatus();
207
273
  }
208
274
  }
209
- async BLErefreshStatus() {
210
- this.platform.debug('Curtains BLE Device RefreshStatus');
275
+ connectBLE() {
211
276
  // eslint-disable-next-line @typescript-eslint/no-var-requires
212
277
  const Switchbot = require('node-switchbot');
213
278
  const switchbot = new Switchbot();
214
279
  const colon = this.device.deviceId.match(/.{1,2}/g);
215
280
  const bleMac = colon.join(':'); //returns 1A:23:B4:56:78:9A;
216
281
  this.device.bleMac = bleMac.toLowerCase();
217
- this.platform.debug(this.device.bleMac);
218
- switchbot.onadvertisement = (ad) => {
219
- this.platform.debug(JSON.stringify(ad, null, ' '));
220
- this.platform.device(`ad: ${JSON.stringify(ad)}`);
221
- };
222
- this.parseStatus();
223
- this.updateHomeKitCharacteristics();
224
- switchbot
225
- .startScan({
282
+ this.platform.device(this.device.bleMac);
283
+ return switchbot;
284
+ }
285
+ async BLERefreshStatus() {
286
+ this.platform.debug('Curtains BLE Device RefreshStatus');
287
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
288
+ const switchbot = this.connectBLE();
289
+ // Start to monitor advertisement packets
290
+ switchbot.startScan({
291
+ model: 'c',
226
292
  id: this.device.bleMac,
227
- })
228
- .then(() => {
229
- return switchbot.wait(this.platform.config.options.refreshRate * 1000);
230
- })
231
- .then(() => {
293
+ }).then(() => {
294
+ // Set an event hander
295
+ switchbot.onadvertisement = (ad) => {
296
+ this.serviceData = ad.serviceData;
297
+ this.platform.device(`${this.device.bleMac}: ${JSON.stringify(ad.serviceData)}`);
298
+ this.calibration = ad.serviceData.calibration;
299
+ this.battery = ad.serviceData.battery;
300
+ this.position = ad.serviceData.position;
301
+ this.lightLevel = ad.serviceData.lightLevel;
302
+ this.platform.device(`${this.accessory.displayName}, Calibration: ${ad.serviceData.calibration}, Position: ${ad.serviceData.position},`
303
+ + ` Light Level: ${ad.serviceData.lightLevel}, Battery: ${ad.serviceData.battery}`);
304
+ };
305
+ // Wait 10 seconds
306
+ return switchbot.wait(10000);
307
+ }).then(() => {
308
+ // Stop to monitor
232
309
  switchbot.stopScan();
233
- })
234
- .catch(async (error) => {
235
- this.platform.log.error(error);
310
+ this.parseStatus();
311
+ this.updateHomeKitCharacteristics();
312
+ }).catch(async (e) => {
313
+ this.platform.log.error(`BLE Connection Failed: ${e.message}`);
314
+ this.platform.log.warn('Using OpenAPI Connection');
236
315
  await this.openAPIRefreshStatus();
237
316
  });
238
- setInterval(() => {
239
- this.platform.log.info('Start scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
240
- switchbot
241
- .startScan({
242
- mode: 'T',
243
- id: bleMac,
244
- })
245
- .then(() => {
246
- return switchbot.wait(this.platform.config.options.refreshRate * 1000);
247
- })
248
- .then(() => {
249
- switchbot.stopScan();
250
- this.platform.log.info('Stop scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
251
- })
252
- .catch(async (error) => {
253
- this.platform.log.error(error);
254
- await this.openAPIRefreshStatus();
255
- });
256
- }, this.platform.config.options.refreshRate * 60000);
257
317
  }
258
318
  async openAPIRefreshStatus() {
319
+ this.platform.debug('Curtains OpenAPI Device RefreshStatus');
259
320
  try {
260
321
  this.deviceStatus = (await this.platform.axios.get(`${settings_1.DeviceURL}/${this.device.deviceId}/status`)).data;
261
322
  this.platform.debug(`Curtain ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
262
- this.setMinMax();
263
323
  this.parseStatus();
264
324
  this.updateHomeKitCharacteristics();
265
325
  }
@@ -281,6 +341,15 @@ class Curtain {
281
341
  }
282
342
  async BLEpushChanges() {
283
343
  this.platform.device('Curtains BLE Device pushChanges');
344
+ const switchbot = this.connectBLE();
345
+ switchbot.discover({ model: 'c', quick: true, id: this.device.bleMac }).then((device_list) => {
346
+ this.platform.log.info(`${this.accessory.displayName}, Target Position: ${this.TargetPosition}`);
347
+ return device_list[0].runToPos(100 - Number(this.TargetPosition));
348
+ }).then(() => {
349
+ this.platform.device('Done.');
350
+ }).catch((e) => {
351
+ this.platform.log.error(`BLE pushChanges Error Message: ${e.message}`);
352
+ });
284
353
  }
285
354
  async OpenAPIpushChanges() {
286
355
  if (this.TargetPosition !== this.CurrentPosition) {
@@ -294,7 +363,6 @@ class Curtain {
294
363
  this.platform.log.info('Sending request for', this.accessory.displayName, 'to SwitchBot API. command:', payload.command, 'parameter:', payload.parameter, 'commandType:', payload.commandType);
295
364
  this.platform.debug(`Curtain ${this.accessory.displayName} pushchanges: ${JSON.stringify(payload)}`);
296
365
  // Make the API request
297
- this.platform.log.error(this.device.deviceId);
298
366
  const push = (await this.platform.axios.post(`${settings_1.DeviceURL}/${this.device.deviceId}/commands`, payload));
299
367
  this.platform.debug(`Curtain ${this.accessory.displayName} Changes pushed: ${JSON.stringify(push.data)}`);
300
368
  this.statusCode(push);
@@ -302,12 +370,11 @@ class Curtain {
302
370
  }
303
371
  updateHomeKitCharacteristics() {
304
372
  this.platform.debug(`Curtain ${this.accessory.displayName} updateHomeKitCharacteristics - ${JSON.stringify({
305
- CurrentPosition: Number.isNaN(this.CurrentPosition),
373
+ CurrentPosition: this.CurrentPosition,
306
374
  PositionState: this.PositionState,
307
- TargetPosition: Number.isNaN(this.TargetPosition),
375
+ TargetPosition: this.TargetPosition,
308
376
  CurrentAmbientLightLevel: this.CurrentAmbientLightLevel,
309
377
  })}`);
310
- this.setMinMax();
311
378
  if (this.CurrentPosition === undefined) {
312
379
  this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
313
380
  }
@@ -336,12 +403,32 @@ class Curtain {
336
403
  this.lightSensorService.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
337
404
  this.platform.device(`Curtain ${this.accessory.displayName} updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
338
405
  }
406
+ if (this.device.ble) {
407
+ if (this.BatteryLevel === undefined) {
408
+ this.platform.debug(`Curtain ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
409
+ }
410
+ else {
411
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
412
+ this.platform.device(`Curtain ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
413
+ }
414
+ if (this.StatusLowBattery === undefined) {
415
+ this.platform.debug(`Curtain ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
416
+ }
417
+ else {
418
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
419
+ this.platform.device(`Curtain ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
420
+ }
421
+ }
339
422
  }
340
423
  apiError(e) {
341
424
  this.service.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
342
425
  this.service.updateCharacteristic(this.platform.Characteristic.PositionState, e);
343
426
  this.service.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
344
427
  this.lightSensorService.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
428
+ if (this.device.ble) {
429
+ this.batteryService.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
430
+ this.batteryService.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
431
+ }
345
432
  }
346
433
  statusCode(push) {
347
434
  switch (push.data.statusCode) {
@@ -374,199 +461,34 @@ class Curtain {
374
461
  * Handle requests to set the value of the "Target Position" characteristic
375
462
  */
376
463
  TargetPositionSet(value) {
377
- if (this.device.ble) {
378
- this.TargetPosition = value;
379
- this.platform.log.info('Target position of Curtain setting: ' + this.TargetPosition + '%');
380
- clearTimeout(this.moveTimer);
381
- if (this.TargetPosition > this.CurrentPosition) {
382
- this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
383
- }
384
- else if (this.TargetPosition < this.CurrentPosition) {
385
- this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
386
- }
387
- else {
388
- this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
389
- }
390
- if (this.PositionState === this.platform.Characteristic.PositionState.STOPPED) {
391
- this.service?.getCharacteristic(this.platform.Characteristic.TargetPosition).updateValue(this.TargetPosition);
392
- this.service?.getCharacteristic(this.platform.Characteristic.CurrentPosition).updateValue(this.CurrentPosition);
393
- this.service?.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
394
- }
395
- else {
396
- this.runToPosition(this.convertFromHomeKitPosition(this.TargetPosition))
397
- .then(() => {
398
- this.platform.log.info('Done.');
399
- this.platform.log.info('Target position of Curtain has been set to: ' + this.TargetPosition + '%');
400
- this.moveTimer = setTimeout(() => {
401
- // log.info("setTimeout", this.positionState.toString(), this.currentPosition.toString(), this.targetPosition.toString());
402
- this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
403
- // this.curtainService?.getCharacteristic(hap.Characteristic.TargetPosition).updateValue(this.targetPosition);
404
- this.service?.getCharacteristic(this.platform.Characteristic.CurrentPosition).updateValue(this.CurrentPosition);
405
- this.service?.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
406
- }, this.moveTime);
407
- })
408
- .catch((error) => {
409
- this.platform.log.error(error);
410
- this.moveTimer = setTimeout(() => {
411
- this.TargetPosition = this.CurrentPosition;
412
- this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
413
- this.service?.getCharacteristic(this.platform.Characteristic.TargetPosition).updateValue(this.TargetPosition);
414
- // this.curtainService?.getCharacteristic(hap.Characteristic.CurrentPosition).updateValue(this.currentPosition);
415
- this.service?.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
416
- }, 1000);
417
- this.platform.log.info('Target position of Curtain failed to be set to: ' + this.TargetPosition + '%');
418
- });
419
- }
420
- }
421
- else {
422
- this.platform.debug(`Curtain ${this.accessory.displayName} - Set TargetPosition: ${value}`);
423
- this.TargetPosition = value;
424
- if (value > this.CurrentPosition) {
425
- this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
426
- this.setNewTarget = true;
427
- this.setMinMax();
428
- }
429
- else if (value < this.CurrentPosition) {
430
- this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
431
- this.setNewTarget = true;
432
- this.setMinMax();
433
- }
434
- else {
435
- this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
436
- this.setNewTarget = false;
437
- this.setMinMax();
438
- }
439
- this.service.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
440
- /**
441
- * If Curtain movement time is short, the moving flag from backend is always false.
442
- * The minimum time depends on the network control latency.
443
- */
444
- clearTimeout(this.setNewTargetTimer);
445
- if (this.setNewTarget) {
446
- this.setNewTargetTimer = setTimeout(() => {
447
- this.platform.debug(`Curtain ${this.accessory.displayName} - setNewTarget ${this.setNewTarget} timeout`);
448
- this.setNewTarget = false;
449
- }, 10000);
450
- }
451
- this.doCurtainUpdate.next();
464
+ this.platform.debug(`Curtain ${this.accessory.displayName} - Set TargetPosition: ${value}`);
465
+ this.TargetPosition = value;
466
+ this.setMinMax();
467
+ if (value > this.CurrentPosition) {
468
+ this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
469
+ this.setNewTarget = true;
452
470
  }
453
- }
454
- /**
455
- * Convert to/from device/HomeKit's position, since:
456
- *
457
- * - opened is 0% in HomeKit and 100% in Curtain device.
458
- * - closed is 100% in HomeKit, 0% in Curtain device.
459
- */
460
- convertFromHomeKitPosition(n) {
461
- let covertToDevicePosition;
462
- if (this.ReverseDir) {
463
- covertToDevicePosition = n;
471
+ else if (value < this.CurrentPosition) {
472
+ this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
473
+ this.setNewTarget = true;
464
474
  }
465
475
  else {
466
- covertToDevicePosition = 100 - n;
467
- }
468
- return covertToDevicePosition;
469
- }
470
- /**
471
- * Ask the device to start moving to the given position (which must be a device value and not an HomeKit value).
472
- * Returns a Promise that's resolved as soon as the command was sent to the device.
473
- */
474
- async runToPosition(pos) {
475
- const SwitchBot = require('node-switchbot');
476
- const switchbot = new SwitchBot();
477
- return switchbot
478
- .discover({ duration: this.ScanDuration, model: 'c', quick: false })
479
- .then((device_list) => {
480
- let targetDevice = null;
481
- for (const device of device_list) {
482
- this.platform.log.info(device.modelName, device.address);
483
- if (device.address === this.device.bleMac.toLowerCase()) {
484
- targetDevice = device;
485
- break;
486
- }
487
- }
488
- if (!targetDevice) {
489
- return new Promise((resolve, reject) => {
490
- reject(new Error('Curtain \'' + this.device.deviceName + '\' (' + this.device.bleMac.toLowerCase() + '): device not found.'));
491
- });
492
- }
493
- this.startFastScan();
494
- this.platform.log.info(`Curtain ${this.device.deviceName} (${this.device.bleMac.toLowerCase()}) is moving to ${pos}...`);
495
- return targetDevice.runToPos(pos);
496
- });
497
- }
498
- /**
499
- * Start a faster scan loop (using fastScanInterval). Used in calls to `runToPosition` to
500
- * report quicker on device position change. Will disable on its own as soon if the curtain's
501
- * device position does not change for more than `fastScanDuration`.
502
- */
503
- startFastScan() {
504
- if (this.FastScanEnabled) {
505
- return;
476
+ this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
477
+ this.setNewTarget = false;
506
478
  }
507
- this.FastScanEnabled = true;
508
- this.startScanLoop();
509
- }
510
- stopFastScan() {
511
- if (!this.FastScanEnabled) {
512
- return;
513
- }
514
- this.FastScanEnabled = false;
515
- this.startScanLoop();
516
- }
517
- get scanInterval() {
518
- return this.FastScanEnabled ? this.FastScanInterval : this.SlowScanInterval;
519
- }
520
- startScanLoop() {
521
- if (this.ScanIntervalId !== null) {
522
- clearInterval(this.ScanIntervalId);
523
- }
524
- this.platform.log.info(`Curtain ${this.device.deviceName}: starting scan loop with interval ${this.scanInterval}`);
525
- this.ScanIntervalId = setInterval(() => {
526
- this.scan().catch((err) => {
527
- this.platform.log.error(`error while scanning for Curtain ${this.device.deviceName}: ${err}`);
528
- });
529
- }, this.scanInterval);
530
- }
531
- scan() {
532
- return new Promise((resolve, reject) => {
533
- const SwitchBot = require('node-switchbot');
534
- const switchbot = new SwitchBot();
535
- switchbot.onadvertisement = (ad) => {
536
- this.applyPosition(ad);
537
- };
538
- switchbot.startScan({ id: this.device.bleMac.toLowerCase() })
539
- .then(() => {
540
- return switchbot.wait(this.ScanDuration);
541
- })
542
- .then(() => {
543
- resolve();
544
- switchbot.stopScan();
545
- })
546
- .catch((err) => {
547
- reject(err);
548
- });
549
- });
550
- }
551
- applyPosition(ad) {
552
- let pos = ad.serviceData.position;
553
- if (pos + this.OpenCloseThreshold >= 100) {
554
- pos = 100;
555
- }
556
- else if (pos - this.OpenCloseThreshold <= 0) {
557
- pos = 0;
558
- }
559
- if (pos === this.PreviousPosition) {
560
- return;
561
- }
562
- this.PreviousPosition = this.Position;
563
- this.Position = pos;
564
- if (this.AutoDisableFastScanTimeoutId !== null) {
565
- clearTimeout(this.AutoDisableFastScanTimeoutId);
479
+ this.service.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
480
+ /**
481
+ * If Curtain movement time is short, the moving flag from backend is always false.
482
+ * The minimum time depends on the network control latency.
483
+ */
484
+ clearTimeout(this.setNewTargetTimer);
485
+ if (this.setNewTarget) {
486
+ this.setNewTargetTimer = setTimeout(() => {
487
+ this.platform.debug(`Curtain ${this.accessory.displayName} - setNewTarget ${this.setNewTarget} timeout`);
488
+ this.setNewTarget = false;
489
+ }, 10000);
566
490
  }
567
- this.AutoDisableFastScanTimeoutId = setTimeout(() => {
568
- this.stopFastScan();
569
- }, this.FastScanDuration);
491
+ this.doCurtainUpdate.next();
570
492
  }
571
493
  setMinMax() {
572
494
  if (this.device.curtain?.set_min) {