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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/.vscode/settings.json +4 -1
  2. package/CHANGELOG.md +4 -1
  3. package/config.schema.json +164 -22
  4. package/dist/device/blindtilt.d.ts +21 -96
  5. package/dist/device/blindtilt.d.ts.map +1 -1
  6. package/dist/device/blindtilt.js +457 -866
  7. package/dist/device/blindtilt.js.map +1 -1
  8. package/dist/device/bot.d.ts +27 -72
  9. package/dist/device/bot.d.ts.map +1 -1
  10. package/dist/device/bot.js +851 -913
  11. package/dist/device/bot.js.map +1 -1
  12. package/dist/device/ceilinglight.d.ts +15 -69
  13. package/dist/device/ceilinglight.d.ts.map +1 -1
  14. package/dist/device/ceilinglight.js +316 -742
  15. package/dist/device/ceilinglight.js.map +1 -1
  16. package/dist/device/colorbulb.d.ts +15 -76
  17. package/dist/device/colorbulb.d.ts.map +1 -1
  18. package/dist/device/colorbulb.js +380 -833
  19. package/dist/device/colorbulb.js.map +1 -1
  20. package/dist/device/contact.d.ts +14 -66
  21. package/dist/device/contact.d.ts.map +1 -1
  22. package/dist/device/contact.js +267 -602
  23. package/dist/device/contact.js.map +1 -1
  24. package/dist/device/curtain.d.ts +18 -89
  25. package/dist/device/curtain.d.ts.map +1 -1
  26. package/dist/device/curtain.js +469 -897
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/device.d.ts +76 -0
  29. package/dist/device/device.d.ts.map +1 -0
  30. package/dist/device/device.js +846 -0
  31. package/dist/device/device.js.map +1 -0
  32. package/dist/device/fan.d.ts +63 -0
  33. package/dist/device/fan.d.ts.map +1 -0
  34. package/dist/device/fan.js +645 -0
  35. package/dist/device/fan.js.map +1 -0
  36. package/dist/device/hub.d.ts +19 -58
  37. package/dist/device/hub.d.ts.map +1 -1
  38. package/dist/device/hub.js +304 -640
  39. package/dist/device/hub.js.map +1 -1
  40. package/dist/device/humidifier.d.ts +11 -66
  41. package/dist/device/humidifier.d.ts.map +1 -1
  42. package/dist/device/humidifier.js +300 -710
  43. package/dist/device/humidifier.js.map +1 -1
  44. package/dist/device/iosensor.d.ts +12 -64
  45. package/dist/device/iosensor.d.ts.map +1 -1
  46. package/dist/device/iosensor.js +225 -643
  47. package/dist/device/iosensor.js.map +1 -1
  48. package/dist/device/lightstrip.d.ts +12 -70
  49. package/dist/device/lightstrip.d.ts.map +1 -1
  50. package/dist/device/lightstrip.js +371 -742
  51. package/dist/device/lightstrip.js.map +1 -1
  52. package/dist/device/lock.d.ts +17 -63
  53. package/dist/device/lock.d.ts.map +1 -1
  54. package/dist/device/lock.js +309 -642
  55. package/dist/device/lock.js.map +1 -1
  56. package/dist/device/meter.d.ts +15 -64
  57. package/dist/device/meter.d.ts.map +1 -1
  58. package/dist/device/meter.js +223 -638
  59. package/dist/device/meter.js.map +1 -1
  60. package/dist/device/meterplus.d.ts +15 -65
  61. package/dist/device/meterplus.d.ts.map +1 -1
  62. package/dist/device/meterplus.js +216 -644
  63. package/dist/device/meterplus.js.map +1 -1
  64. package/dist/device/motion.d.ts +12 -69
  65. package/dist/device/motion.d.ts.map +1 -1
  66. package/dist/device/motion.js +209 -588
  67. package/dist/device/motion.js.map +1 -1
  68. package/dist/device/plug.d.ts +10 -57
  69. package/dist/device/plug.d.ts.map +1 -1
  70. package/dist/device/plug.js +141 -532
  71. package/dist/device/plug.js.map +1 -1
  72. package/dist/device/robotvacuumcleaner.d.ts +13 -63
  73. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  74. package/dist/device/robotvacuumcleaner.js +252 -609
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +11 -63
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +179 -521
  79. package/dist/device/waterdetector.js.map +1 -1
  80. package/dist/homebridge-ui/public/index.html +22 -16
  81. package/dist/homebridge-ui/server.js +1 -1
  82. package/dist/homebridge-ui/server.js.map +1 -1
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +2 -2
  86. package/dist/index.js.map +1 -1
  87. package/dist/irdevice/airconditioner.d.ts +10 -50
  88. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  89. package/dist/irdevice/airconditioner.js +337 -482
  90. package/dist/irdevice/airconditioner.js.map +1 -1
  91. package/dist/irdevice/airpurifier.d.ts +8 -39
  92. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  93. package/dist/irdevice/airpurifier.js +108 -333
  94. package/dist/irdevice/airpurifier.js.map +1 -1
  95. package/dist/irdevice/camera.d.ts +7 -36
  96. package/dist/irdevice/camera.d.ts.map +1 -1
  97. package/dist/irdevice/camera.js +47 -299
  98. package/dist/irdevice/camera.js.map +1 -1
  99. package/dist/irdevice/fan.d.ts +7 -43
  100. package/dist/irdevice/fan.d.ts.map +1 -1
  101. package/dist/irdevice/fan.js +95 -364
  102. package/dist/irdevice/fan.js.map +1 -1
  103. package/dist/irdevice/irdevice.d.ts +46 -0
  104. package/dist/irdevice/irdevice.d.ts.map +1 -0
  105. package/dist/irdevice/irdevice.js +393 -0
  106. package/dist/irdevice/irdevice.js.map +1 -0
  107. package/dist/irdevice/light.d.ts +12 -45
  108. package/dist/irdevice/light.d.ts.map +1 -1
  109. package/dist/irdevice/light.js +121 -376
  110. package/dist/irdevice/light.js.map +1 -1
  111. package/dist/irdevice/other.d.ts +19 -48
  112. package/dist/irdevice/other.d.ts.map +1 -1
  113. package/dist/irdevice/other.js +441 -584
  114. package/dist/irdevice/other.js.map +1 -1
  115. package/dist/irdevice/tv.d.ts +8 -40
  116. package/dist/irdevice/tv.d.ts.map +1 -1
  117. package/dist/irdevice/tv.js +94 -353
  118. package/dist/irdevice/tv.js.map +1 -1
  119. package/dist/irdevice/vacuumcleaner.d.ts +7 -36
  120. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  121. package/dist/irdevice/vacuumcleaner.js +48 -299
  122. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  123. package/dist/irdevice/waterheater.d.ts +7 -36
  124. package/dist/irdevice/waterheater.d.ts.map +1 -1
  125. package/dist/irdevice/waterheater.js +50 -305
  126. package/dist/irdevice/waterheater.js.map +1 -1
  127. package/dist/platform.d.ts +22 -8
  128. package/dist/platform.d.ts.map +1 -1
  129. package/dist/platform.js +342 -191
  130. package/dist/platform.js.map +1 -1
  131. package/dist/settings.d.ts +66 -18
  132. package/dist/settings.d.ts.map +1 -1
  133. package/dist/settings.js +16 -552
  134. package/dist/settings.js.map +1 -1
  135. package/dist/utils.d.ts +95 -0
  136. package/dist/utils.d.ts.map +1 -1
  137. package/dist/utils.js +657 -1
  138. package/dist/utils.js.map +1 -1
  139. package/eslint.config.js +96 -0
  140. package/package.json +20 -16
  141. package/src/custom.d.ts +2 -1
  142. package/src/device/blindtilt.ts +488 -937
  143. package/src/device/bot.ts +907 -1016
  144. package/src/device/ceilinglight.ts +330 -798
  145. package/src/device/colorbulb.ts +394 -904
  146. package/src/device/contact.ts +298 -637
  147. package/src/device/curtain.ts +496 -954
  148. package/src/device/device.ts +872 -0
  149. package/src/device/fan.ts +692 -0
  150. package/src/device/hub.ts +338 -671
  151. package/src/device/humidifier.ts +330 -777
  152. package/src/device/iosensor.ts +258 -671
  153. package/src/device/lightstrip.ts +394 -809
  154. package/src/device/lock.ts +345 -700
  155. package/src/device/meter.ts +256 -666
  156. package/src/device/meterplus.ts +248 -672
  157. package/src/device/motion.ts +234 -622
  158. package/src/device/plug.ts +152 -572
  159. package/src/device/robotvacuumcleaner.ts +273 -653
  160. package/src/device/waterdetector.ts +198 -549
  161. package/src/homebridge-ui/public/index.html +22 -16
  162. package/src/homebridge-ui/server.ts +1 -1
  163. package/src/index.ts +4 -3
  164. package/src/irdevice/airconditioner.ts +368 -540
  165. package/src/irdevice/airpurifier.ts +134 -369
  166. package/src/irdevice/camera.ts +60 -324
  167. package/src/irdevice/fan.ts +111 -392
  168. package/src/irdevice/irdevice.ts +406 -0
  169. package/src/irdevice/light.ts +159 -425
  170. package/src/irdevice/other.ts +509 -661
  171. package/src/irdevice/tv.ts +123 -388
  172. package/src/irdevice/vacuumcleaner.ts +61 -324
  173. package/src/irdevice/waterheater.ts +63 -333
  174. package/src/platform.ts +395 -259
  175. package/src/settings.ts +120 -610
  176. package/src/utils.ts +661 -1
  177. package/src/device/waterdetector.json +0 -11
@@ -1,113 +1,61 @@
1
- import { request } from 'undici';
2
- import { sleep } from '../utils.js';
3
- import { MqttClient } from 'mqtt';
1
+ /* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
+ *
3
+ * blindtilt.ts: @switchbot/homebridge-switchbot.
4
+ */
4
5
  import { interval, Subject } from 'rxjs';
5
- import asyncmqtt from 'async-mqtt';
6
- import { SwitchBotPlatform } from '../platform.js';
6
+ import { deviceBase } from './device.js';
7
+ import { BlindTiltMappingMode } from '../utils.js';
7
8
  import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
8
- import { Service, PlatformAccessory, CharacteristicValue, Logging, API, HAP } from 'homebridge';
9
- import { device, devicesConfig, serviceData, deviceStatus, Devices, SwitchBotPlatformConfig } from '../settings.js';
10
-
11
- enum BlindTiltMappingMode {
12
- OnlyUp = 'only_up',
13
- OnlyDown = 'only_down',
14
- DownAndUp = 'down_and_up',
15
- UpAndDown = 'up_and_down',
16
- UseTiltForDirection = 'use_tilt_for_direction',
17
- }
18
9
 
19
- export class BlindTilt {
20
- public readonly api: API;
21
- public readonly log: Logging;
22
- public readonly config!: SwitchBotPlatformConfig;
23
- protected readonly hap: HAP;
10
+ import type { SwitchBotPlatform } from '../platform.js';
11
+ import type { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
12
+ import type { device, devicesConfig, serviceData, deviceStatus } from '../settings.js';
13
+
14
+
15
+ export class BlindTilt extends deviceBase {
24
16
  // Services
25
- batteryService!: Service;
26
- lightSensorService?: Service;
27
- windowCoveringService!: Service;
28
-
29
- // Characteristic Values
30
- BatteryLevel!: CharacteristicValue;
31
- PositionState!: CharacteristicValue;
32
- TargetPosition!: CharacteristicValue;
33
- CurrentPosition!: CharacteristicValue;
34
- StatusLowBattery!: CharacteristicValue;
35
- FirmwareRevision!: CharacteristicValue;
36
- CurrentAmbientLightLevel?: CharacteristicValue;
37
- TargetHorizontalTiltAngle!: CharacteristicValue;
38
- CurrentHorizontalTiltAngle!: CharacteristicValue;
39
-
40
- // OpenAPI Status
41
- OpenAPI_InMotion: deviceStatus['moving'];
42
- OpenAPI_BatteryLevel: serviceData['battery'];
43
- OpenAPI_Direction: deviceStatus['direction'];
44
- OpenAPI_Calibration: serviceData['calibration'];
45
- OpenAPI_CurrentPosition: serviceData['position'];
46
- OpenAPI_FirmwareRevision: deviceStatus['version'];
47
- OpenAPI_CurrentAmbientLightLevel: deviceStatus['brightness'];
17
+ private WindowCovering: {
18
+ Name: CharacteristicValue;
19
+ Service: Service;
20
+ PositionState: CharacteristicValue;
21
+ TargetPosition: CharacteristicValue;
22
+ CurrentPosition: CharacteristicValue;
23
+ TargetHorizontalTiltAngle: CharacteristicValue;
24
+ CurrentHorizontalTiltAngle: CharacteristicValue;
25
+ };
26
+
27
+ private Battery: {
28
+ Name: CharacteristicValue;
29
+ Service: Service;
30
+ BatteryLevel: CharacteristicValue;
31
+ StatusLowBattery: CharacteristicValue;
32
+ ChargingState?: CharacteristicValue;
33
+ };
34
+
35
+ private LightSensor?: {
36
+ Name: CharacteristicValue;
37
+ Service: Service;
38
+ CurrentAmbientLightLevel?: CharacteristicValue;
39
+ };
48
40
 
49
41
  // OpenAPI Others
50
- Mode!: string;
51
- setPositionMode?: string | number;
52
42
  mappingMode: BlindTiltMappingMode = BlindTiltMappingMode.OnlyUp;
53
43
 
54
- // BLE Status
55
- BLE_InMotion: serviceData['inMotion'];
56
- BLE_BatteryLevel: serviceData['battery'];
57
- BLE_Calibration: serviceData['calibration'];
58
- BLE_CurrentPosition: serviceData['position'];
59
- BLE_CurrentAmbientLightLevel: serviceData['lightLevel'];
60
-
61
- // BLE Others
62
- BLE_IsConnected?: boolean;
63
- spaceBetweenLevels!: number;
64
-
65
44
  // Target
66
45
  setNewTarget!: boolean;
67
46
  setNewTargetTimer!: NodeJS.Timeout;
68
47
 
69
- //MQTT stuff
70
- mqttClient: MqttClient | null = null;
71
-
72
- // Config
73
- set_minStep!: number;
74
- updateRate!: number;
75
- set_minLux!: number;
76
- set_maxLux!: number;
77
- scanDuration!: number;
78
- deviceLogging!: string;
79
- deviceRefreshRate!: number;
80
- setCloseMode!: string;
81
- setOpenMode!: string;
82
-
83
48
  // Updates
84
49
  blindTiltUpdateInProgress!: boolean;
85
50
  doBlindTiltUpdate!: Subject<void>;
86
51
 
87
- // Connection
88
- private readonly OpenAPI: boolean;
89
- private readonly BLE: boolean;
90
-
91
52
  constructor(
92
- private readonly platform: SwitchBotPlatform,
93
- private accessory: PlatformAccessory,
94
- public device: device & devicesConfig,
53
+ readonly platform: SwitchBotPlatform,
54
+ accessory: PlatformAccessory,
55
+ device: device & devicesConfig,
95
56
  ) {
96
- this.api = this.platform.api;
97
- this.log = this.platform.log;
98
- this.config = this.platform.config;
99
- this.hap = this.api.hap;
100
- // Connection
101
- this.BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI';
102
- this.OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI';
57
+ super(platform, accessory, device);
103
58
  // default placeholders
104
- this.deviceLogs(device);
105
- this.refreshRate(device);
106
- this.scan(device);
107
- this.setupMqtt(device);
108
- this.deviceContext();
109
- this.deviceConfig(device);
110
-
111
59
  this.mappingMode = (device.blindTilt?.mode as BlindTiltMappingMode) ?? BlindTiltMappingMode.OnlyUp;
112
60
  this.debugLog(`Mapping mode: ${this.mappingMode}`);
113
61
 
@@ -116,57 +64,49 @@ export class BlindTilt {
116
64
  this.blindTiltUpdateInProgress = false;
117
65
  this.setNewTarget = false;
118
66
 
119
- // Retrieve initial values and updateHomekit
120
- this.refreshStatus();
121
-
122
- // set accessory information
123
- accessory
124
- .getService(this.hap.Service.AccessoryInformation)!
125
- .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
126
- .setCharacteristic(this.hap.Characteristic.Model, 'W2701600')
127
- .setCharacteristic(this.hap.Characteristic.SerialNumber, device.deviceId)
128
- .setCharacteristic(this.hap.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision);
129
-
130
- // get the WindowCovering service if it exists, otherwise create a new WindowCovering service
131
- // you can create multiple services for each accessory
132
- const windowCoveringService = `${device.deviceName} ${device.deviceType}`;
133
- (this.windowCoveringService =
134
- accessory.getService(this.hap.Service.WindowCovering)
135
- || accessory.addService(this.hap.Service.WindowCovering)), windowCoveringService;
136
-
137
- this.windowCoveringService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
138
- if (!this.windowCoveringService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
139
- this.windowCoveringService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
140
- }
141
-
142
- // create handlers for required characteristics
143
- this.windowCoveringService.setCharacteristic(this.hap.Characteristic.PositionState, this.PositionState);
144
-
145
- this.windowCoveringService
146
- .getCharacteristic(this.hap.Characteristic.CurrentPosition)
67
+ // Initialize WindowCovering Service
68
+ accessory.context.WindowCovering = accessory.context.WindowCovering ?? {};
69
+ this.WindowCovering = {
70
+ Name: accessory.context.WindowCovering.Name ?? accessory.displayName,
71
+ Service: accessory.getService(this.hap.Service.WindowCovering) ?? accessory.addService(this.hap.Service.WindowCovering) as Service,
72
+ PositionState: accessory.context.PositionState ?? this.hap.Characteristic.PositionState.STOPPED,
73
+ TargetPosition: accessory.context.TargetPosition ?? 100,
74
+ CurrentPosition: accessory.context.CurrentPosition ?? 100,
75
+ TargetHorizontalTiltAngle: accessory.context.TargetHorizontalTiltAngle ?? 90,
76
+ CurrentHorizontalTiltAngle: accessory.context.CurrentHorizontalTiltAngle ?? 90,
77
+ };
78
+ accessory.context.WindowCovering = this.WindowCovering as object;
79
+
80
+ // Initialize WindowCovering Characteristics
81
+ this.WindowCovering.Service
82
+ .setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name)
83
+ .getCharacteristic(this.hap.Characteristic.TargetPosition)
147
84
  .setProps({
148
- minStep: this.minStep(device),
85
+ minStep: device.blindTilt?.set_minStep ?? 1,
149
86
  minValue: 0,
150
87
  maxValue: 100,
151
88
  validValueRanges: [0, 100],
152
89
  })
153
90
  .onGet(() => {
154
- return this.CurrentPosition;
155
- });
91
+ return this.WindowCovering.TargetPosition;
92
+ })
93
+ .onSet(this.TargetPositionSet.bind(this));
156
94
 
157
- this.windowCoveringService
158
- .getCharacteristic(this.hap.Characteristic.TargetPosition)
95
+ // Initialize WindowCovering CurrentPosition Characteristic
96
+ this.WindowCovering.Service
97
+ .getCharacteristic(this.hap.Characteristic.CurrentPosition)
159
98
  .setProps({
160
- minStep: this.minStep(device),
99
+ minStep: device.blindTilt?.set_minStep ?? 1,
161
100
  minValue: 0,
162
101
  maxValue: 100,
163
102
  validValueRanges: [0, 100],
164
- })
165
- .onSet(this.TargetPositionSet.bind(this));
103
+ }).onGet(() => {
104
+ return this.WindowCovering?.CurrentPosition ?? 0;
105
+ });
166
106
 
167
- this.CurrentHorizontalTiltAngle = 90;
168
- this.windowCoveringService
169
- .getCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle)
107
+ // Initialize WindowCovering TargetHorizontalTiltAngle Characteristic
108
+ this.WindowCovering.Service
109
+ .getCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle)
170
110
  .setProps({
171
111
  minStep: 180,
172
112
  minValue: -90,
@@ -174,31 +114,68 @@ export class BlindTilt {
174
114
  validValues: [-90, 90],
175
115
  })
176
116
  .onGet(() => {
177
- // this.debugLog(`requested CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
178
- return this.CurrentHorizontalTiltAngle;
179
- });
117
+ return this.WindowCovering.TargetHorizontalTiltAngle;
118
+ })
119
+ .onSet(this.TargetHorizontalTiltAngleSet.bind(this));
180
120
 
181
- this.TargetHorizontalTiltAngle = 90;
182
- this.windowCoveringService
183
- .getCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle)
121
+ // Initialize WindowCovering CurrentHorizontalTiltAngle Characteristic
122
+ this.WindowCovering.Service
123
+ .getCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle)
184
124
  .setProps({
185
125
  minStep: 180,
186
126
  minValue: -90,
187
127
  maxValue: 90,
188
128
  validValues: [-90, 90],
189
- })
190
- .onSet(this.TargetHorizontalTiltAngleSet.bind(this));
191
-
192
- // Battery Service
193
- const batteryService = `${accessory.displayName} Battery`;
194
- (this.batteryService = this.accessory.getService(this.hap.Service.Battery)
195
- || accessory.addService(this.hap.Service.Battery)), batteryService;
129
+ }).onGet(() => {
130
+ return this.WindowCovering.CurrentHorizontalTiltAngle ?? 0;
131
+ });
196
132
 
197
- this.batteryService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Battery`);
198
- if (!this.batteryService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
199
- this.batteryService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Battery`);
133
+ // Initialize Battery Service
134
+ accessory.context.Battery = accessory.context.Battery ?? {};
135
+ this.Battery = {
136
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
137
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
138
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
139
+ StatusLowBattery: this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
140
+ ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGING,
141
+ };
142
+ accessory.context.Battery = this.Battery as object;
143
+
144
+ // Initialize Battery Name Characteristic
145
+ this.Battery.Service
146
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
147
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
148
+
149
+ // Initialize LightSensor Service
150
+ if (device.blindTilt?.hide_lightsensor) {
151
+ if (this.LightSensor?.Service) {
152
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} Removing Light Sensor Service`);
153
+ this.LightSensor.Service = accessory.getService(this.hap.Service.LightSensor) as Service;
154
+ accessory.removeService(this.LightSensor.Service);
155
+ accessory.context.LightSensor = {};
156
+ }
157
+ } else {
158
+ accessory.context.LightSensor = accessory.context.LightSensor ?? {};
159
+ this.LightSensor = {
160
+ Name: accessory.context.LightSensor.Name ?? `${accessory.displayName} Light Sensor`,
161
+ Service: accessory.getService(this.hap.Service.LightSensor) ?? accessory.addService(this.hap.Service.LightSensor) as Service,
162
+ CurrentAmbientLightLevel: accessory.context.CurrentAmbientLightLevel ?? 0.0001,
163
+ };
164
+ accessory.context.LightSensor = this.LightSensor as object;
165
+
166
+ // Initialize LightSensor Characteristics
167
+ this.LightSensor.Service
168
+ .setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name)
169
+ .setCharacteristic(this.hap.Characteristic.StatusActive, true)
170
+ .getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel)
171
+ .onGet(() => {
172
+ return this.LightSensor?.CurrentAmbientLightLevel ?? 0.0001;
173
+ });
200
174
  }
201
175
 
176
+ // Retrieve initial values and updateHomekit
177
+ this.refreshStatus();
178
+
202
179
  // Update Homekit
203
180
  this.updateHomeKitCharacteristics();
204
181
 
@@ -210,36 +187,16 @@ export class BlindTilt {
210
187
  });
211
188
 
212
189
  //regisiter webhook event handler
213
- if (this.device.webhook) {
214
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
215
- this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
216
- try {
217
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
218
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Please Submit Logs: ` + 'https://tinyurl.com/SwitchBotBug');
219
- /*const { temperature, humidity } = context;
220
- const { CurrentTemperature, CurrentRelativeHumidity } = this;
221
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
222
- '(temperature, humidity) = ' +
223
- `Webhook:(${temperature}, ${humidity}), ` +
224
- `current:(${CurrentTemperature}, ${CurrentRelativeHumidity})`);
225
- this.CurrentRelativeHumidity = humidity;
226
- this.CurrentTemperature = temperature;
227
- this.updateHomeKitCharacteristics();*/
228
- } catch (e: any) {
229
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
230
- + `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
231
- }
232
- };
233
- }
190
+ this.registerWebhook(accessory, device);
234
191
 
235
192
  // update slide progress
236
- interval(this.updateRate * 1000)
237
- //.pipe(skipWhile(() => this.blindTiltUpdateInProgress))
193
+ interval(this.deviceUpdateRate * 1000)
238
194
  .subscribe(async () => {
239
- if (this.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
195
+ if (this.WindowCovering.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
240
196
  return;
241
197
  }
242
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Refresh Status When Moving, PositionState: ${this.PositionState}`);
198
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} Refresh Status When Moving,`
199
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
243
200
  await this.refreshStatus();
244
201
  });
245
202
 
@@ -250,235 +207,241 @@ export class BlindTilt {
250
207
  tap(() => {
251
208
  this.blindTiltUpdateInProgress = true;
252
209
  }),
253
- debounceTime(this.platform.config.options!.pushRate! * 1000),
210
+ debounceTime(this.devicePushRate * 1000),
254
211
  )
255
212
  .subscribe(async () => {
256
213
  try {
257
214
  await this.pushChanges();
258
215
  } catch (e: any) {
259
216
  this.apiError(e);
260
- this.errorLog(
261
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,` +
262
- ` Error Message: ${JSON.stringify(e.message)}`,
263
- );
217
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed pushChanges with ${device.connectionType} Connection,`
218
+ + ` Error Message: ${JSON.stringify(e.message)}`);
264
219
  }
265
220
  this.blindTiltUpdateInProgress = false;
266
221
  });
267
222
  }
268
223
 
269
224
  /**
270
- * Parse the device status from the SwitchBot api
225
+ * Parse the device status from the SwitchBotBLE API
271
226
  */
272
- async parseStatus(): Promise<void> {
273
- if (!this.device.enableCloudService && this.OpenAPI) {
274
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`);
275
- } else if (this.BLE) {
276
- await this.BLEparseStatus();
277
- } else if (this.OpenAPI && this.platform.config.credentials?.token) {
278
- await this.openAPIparseStatus();
279
- } else {
280
- await this.offlineOff();
281
- this.debugWarnLog(
282
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`,
283
- );
284
- }
285
- }
286
-
287
- async BLEparseStatus(): Promise<void> {
227
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
288
228
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
289
229
  // CurrentPosition
290
- this.CurrentPosition = 100 - Number(this.BLE_CurrentPosition);
230
+ this.WindowCovering.CurrentPosition = 100 - Number(serviceData.position);
291
231
  await this.setMinMax();
292
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.CurrentPosition}`);
232
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.WindowCovering.CurrentPosition}`);
293
233
  if (this.setNewTarget) {
294
234
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
295
235
  }
296
236
 
297
- if (this.setNewTarget && this.BLE_InMotion) {
237
+ if (this.setNewTarget && serviceData.inMotion) {
298
238
  await this.setMinMax();
299
- if (Number(this.TargetPosition) > this.CurrentPosition) {
300
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition}`);
301
- this.PositionState = this.hap.Characteristic.PositionState.INCREASING;
302
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
303
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} INCREASING PositionState: ${this.PositionState}`);
304
- } else if (Number(this.TargetPosition) < this.CurrentPosition) {
305
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.CurrentPosition}`);
306
- this.PositionState = this.hap.Characteristic.PositionState.DECREASING;
307
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
308
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} DECREASING PositionState: ${this.PositionState}`);
239
+ if (Number(this.WindowCovering.TargetPosition) > this.WindowCovering.CurrentPosition) {
240
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
241
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
242
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
243
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} INCREASING`
244
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
245
+ } else if (Number(this.WindowCovering.TargetPosition) < this.WindowCovering.CurrentPosition) {
246
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
247
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
248
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
249
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} DECREASING`
250
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
309
251
  } else {
310
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} Standby2, CurrentPosition: ${this.CurrentPosition}`);
311
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
312
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
313
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`);
252
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} Standby2,`
253
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
254
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
255
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
256
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} STOPPED`
257
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
314
258
  }
315
259
  } else {
316
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby, CurrentPosition: ${this.CurrentPosition}`);
317
- this.TargetPosition = this.CurrentPosition;
318
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
260
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
261
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
262
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
319
263
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
320
264
  }
321
- this.debugLog(
322
- `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
323
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
324
- );
265
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition},`
266
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`);
325
267
 
326
268
  if (!this.device.blindTilt?.hide_lightsensor) {
327
- this.set_minLux = this.minLux();
328
- this.set_maxLux = this.maxLux();
329
- this.spaceBetweenLevels = 9;
269
+ const set_minLux = this.device.blindTilt?.set_minLux ?? 1;
270
+ const set_maxLux = this.device.blindTilt?.set_maxLux ?? 6001;
271
+ const spaceBetweenLevels = 9;
272
+
273
+ if (this.LightSensor?.CurrentAmbientLightLevel === 0) {
274
+ this.LightSensor!.CurrentAmbientLightLevel = 0.0001;
275
+ }
330
276
 
331
277
  // Brightness
332
- switch (this.BLE_CurrentAmbientLightLevel) {
278
+ switch (serviceData.lightLevel) {
333
279
  case 1:
334
- this.CurrentAmbientLightLevel = this.set_minLux;
335
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
280
+ this.LightSensor!.CurrentAmbientLightLevel = set_minLux;
281
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
336
282
  break;
337
283
  case 2:
338
- this.CurrentAmbientLightLevel = (this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels;
339
- this.debugLog(
340
- `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel},` +
341
- ` Calculation: ${(this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels}`,
342
- );
284
+ this.LightSensor!.CurrentAmbientLightLevel = (set_maxLux - set_minLux) / spaceBetweenLevels;
285
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel},`
286
+ + ` Calculation: ${(set_maxLux - set_minLux) / spaceBetweenLevels}`);
343
287
  break;
344
288
  case 3:
345
- this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 2;
346
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
289
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 2;
290
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
347
291
  break;
348
292
  case 4:
349
- this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 3;
350
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
293
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 3;
294
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
351
295
  break;
352
296
  case 5:
353
- this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 4;
354
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
297
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 4;
298
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
355
299
  break;
356
300
  case 6:
357
- this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 5;
358
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
301
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 5;
302
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
359
303
  break;
360
304
  case 7:
361
- this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 6;
362
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
305
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 6;
306
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
363
307
  break;
364
308
  case 8:
365
- this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 7;
366
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
309
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 7;
310
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
367
311
  break;
368
312
  case 9:
369
- this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 8;
370
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
313
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 8;
314
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
371
315
  break;
372
316
  case 10:
373
317
  default:
374
- this.CurrentAmbientLightLevel = this.set_maxLux;
318
+ this.LightSensor!.CurrentAmbientLightLevel = set_maxLux;
375
319
  this.debugLog();
376
320
  }
377
- this.debugLog(
378
- `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel},` +
379
- ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
380
- );
321
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel},`
322
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
381
323
  }
382
324
  // Battery
383
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
384
- if (this.BatteryLevel < 10) {
385
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
325
+ this.Battery.BatteryLevel = Number(serviceData.battery);
326
+ if (this.Battery.BatteryLevel < 10) {
327
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
386
328
  } else {
387
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
329
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
388
330
  }
389
- this.debugLog(
390
- `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` + ` StatusLowBattery: ${this.StatusLowBattery}`,
391
- );
331
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
332
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
392
333
  }
393
334
 
394
- async openAPIparseStatus(): Promise<void> {
335
+
336
+ /**
337
+ * Parse the device status from the SwitchBot OpenAPI
338
+ */
339
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
395
340
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
396
341
 
397
- const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(this.OpenAPI_CurrentPosition),
398
- String(this.OpenAPI_Direction));
399
- this.debugLog(` device: ${this.OpenAPI_CurrentPosition} => HK: ${homekitPosition}`);
342
+ const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(deviceStatus.body.slidePosition),
343
+ String(deviceStatus.body.direction));
344
+ this.debugLog(` device: ${deviceStatus.body.slidePosition} => HK: ${homekitPosition}`);
400
345
 
401
- this.CurrentPosition = homekitPosition;
346
+ this.WindowCovering!.CurrentPosition = homekitPosition;
402
347
  // CurrentPosition
403
348
  await this.setMinMax();
404
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
349
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
405
350
 
406
351
  if (homekitTiltAngle) {
407
- this.CurrentHorizontalTiltAngle = homekitTiltAngle!;
408
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
352
+ this.WindowCovering.CurrentHorizontalTiltAngle = homekitTiltAngle!;
353
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
354
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
409
355
  }
410
356
 
411
357
  if (this.setNewTarget) {
412
358
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
413
359
  }
414
360
 
415
- if (this.setNewTarget && this.OpenAPI_InMotion) {
361
+ if (this.setNewTarget && deviceStatus.body.moving) {
416
362
  await this.setMinMax();
417
- if (this.TargetPosition > this.CurrentPosition || (homekitTiltAngle && this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle)) {
418
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition} `);
419
- this.PositionState = this.hap.Characteristic.PositionState.INCREASING;
420
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
421
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} INCREASING PositionState: ${this.PositionState}`);
422
- } else if (this.TargetPosition < this.CurrentPosition) {
423
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.CurrentPosition} `);
424
- this.PositionState = this.hap.Characteristic.PositionState.DECREASING;
425
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
426
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} DECREASING PositionState: ${this.PositionState}`);
363
+ if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
364
+ || (homekitTiltAngle && this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle)) {
365
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition} `);
366
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
367
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
368
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} INCREASING`
369
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
370
+ } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
371
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition} `);
372
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
373
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
374
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} DECREASING`
375
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
427
376
  } else {
428
- this.debugLog(
429
- `${this.device.deviceType}: ${this.CurrentPosition} Standby because reached position,` + ` CurrentPosition: ${this.CurrentPosition}`,
430
- );
431
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
432
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
433
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`);
377
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} Standby because reached position,`
378
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
379
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
380
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
381
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} STOPPED`
382
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
434
383
  }
435
384
  } else {
436
- this.debugLog(
437
- `${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,` + ` CurrentPosition: ${this.CurrentPosition}`,
438
- );
439
- this.TargetPosition = this.CurrentPosition;
385
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,`
386
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
387
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
440
388
  if (homekitTiltAngle) {
441
- this.TargetHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
389
+ this.WindowCovering.TargetHorizontalTiltAngle = this.WindowCovering.CurrentHorizontalTiltAngle;
442
390
  }
443
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
391
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
444
392
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
445
393
  }
446
- this.debugLog(
447
- `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
448
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
449
- );
450
-
394
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition},`
395
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`);
451
396
  if (!this.device.blindTilt?.hide_lightsensor) {
452
- this.set_minLux = this.minLux();
453
- this.set_maxLux = this.maxLux();
397
+ const set_minLux = this.device.blindTilt?.set_minLux ?? 1;
398
+ const set_maxLux = this.device.blindTilt?.set_maxLux ?? 6001;
454
399
  // Brightness
455
- switch (this.OpenAPI_CurrentAmbientLightLevel) {
400
+ switch (deviceStatus.body.brightness) {
456
401
  case 'dim':
457
- this.CurrentAmbientLightLevel = this.set_minLux;
402
+ this.LightSensor!.CurrentAmbientLightLevel = set_minLux;
458
403
  break;
459
404
  case 'bright':
460
405
  default:
461
- this.CurrentAmbientLightLevel = this.set_maxLux;
406
+ this.LightSensor!.CurrentAmbientLightLevel = set_maxLux;
462
407
  }
463
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
408
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
409
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
464
410
  }
465
411
 
466
412
  // BatteryLevel
467
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
468
- if (this.BatteryLevel < 10) {
469
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
413
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
414
+ if (this.Battery.BatteryLevel < 10) {
415
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
470
416
  } else {
471
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
472
- }
473
- if (Number.isNaN(this.BatteryLevel)) {
474
- this.BatteryLevel = 100;
417
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
418
+ }
419
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
420
+ this.Battery.BatteryLevel = 100;
421
+ }
422
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
423
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
424
+
425
+ // Firmware Version
426
+ const version = deviceStatus.body.version?.toString();
427
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
428
+ let deviceVersion: string;
429
+ if (version?.includes('.') === false) {
430
+ const replace = version?.replace(/^V|-.*$/g, '');
431
+ const match = replace?.match(/.{1,1}/g);
432
+ const blindTiltVersion = match?.join('.') ?? '0.0.0';
433
+ deviceVersion = blindTiltVersion;
434
+ } else {
435
+ deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
475
436
  }
476
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},`
477
- + ` StatusLowBattery: ${this.StatusLowBattery}`);
478
-
479
- // FirmwareRevision
480
- this.FirmwareRevision = this.OpenAPI_FirmwareRevision!;
481
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
437
+ this.accessory
438
+ .getService(this.hap.Service.AccessoryInformation)!
439
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
440
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
441
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
442
+ .updateValue(deviceVersion);
443
+ this.accessory.context.deviceVersion = deviceVersion;
444
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
482
445
  }
483
446
 
484
447
  async refreshStatus(): Promise<void> {
@@ -490,138 +453,78 @@ export class BlindTilt {
490
453
  await this.openAPIRefreshStatus();
491
454
  } else {
492
455
  await this.offlineOff();
493
- this.debugWarnLog(
494
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` +
495
- ` ${this.device.connectionType}, refreshStatus will not happen.`,
496
- );
456
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
457
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
497
458
  }
498
459
  }
499
460
 
500
461
  async BLERefreshStatus(): Promise<void> {
501
462
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
502
- const switchbot = await this.platform.connectBLE();
503
- // Convert to BLE Address
504
- this.device.bleMac = this.device
505
- .deviceId!.match(/.{1,2}/g)!
506
- .join(':')
507
- .toLowerCase();
508
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
509
- this.getCustomBLEAddress(switchbot);
463
+ const switchbot = await this.switchbotBLE();
464
+
465
+ if (switchbot === undefined) {
466
+ await this.BLERefreshConnection(switchbot);
467
+ } else {
510
468
  // Start to monitor advertisement packets
511
- (async () => {
469
+ (async () => {
512
470
  // Start to monitor advertisement packets
513
- await switchbot.startScan({
514
- model: 'x',
515
- id: this.device.bleMac,
516
- });
517
- // Set an event handler
518
- switchbot.onadvertisement = (ad: any) => {
519
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
520
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
521
- if (this.device.bleMac === ad.address && ad.model === 'x') {
522
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
523
- this.BLE_Calibration = ad.serviceData.calibration;
524
- this.BLE_BatteryLevel = ad.serviceData.battery;
525
- this.BLE_InMotion = ad.serviceData.inMotion;
526
- this.BLE_CurrentPosition = ad.serviceData.position;
527
- this.BLE_CurrentAmbientLightLevel = ad.serviceData.lightLevel;
471
+ const serviceData: serviceData = await this.monitorAdvertisementPackets(switchbot);
472
+ // Update HomeKit
473
+ if (serviceData.model !== '' && serviceData.modelName !== '') {
474
+ await this.BLEparseStatus(serviceData);
475
+ await this.updateHomeKitCharacteristics();
528
476
  } else {
529
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
530
- }
531
- };
532
- // Wait 10 seconds
533
- await switchbot.wait(this.scanDuration * 1000);
534
- // Stop to monitor
535
- await switchbot.stopScan();
536
- // Update HomeKit
537
- await this.BLEparseStatus();
538
- await this.updateHomeKitCharacteristics();
539
- })();
540
- /*if (switchbot !== false) {
541
- switchbot
542
- .startScan({
543
- model: 'c',
544
- id: this.device.bleMac,
545
- })
546
- .then(async () => {
547
- // Set an event handler
548
- switchbot.onadvertisement = async (ad: ad) => {
549
- this.debugLog(
550
- `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` +
551
- ` BLE Address Found: ${ad.address}`,
552
- );
553
- this.BLE_Calibration = ad.serviceData.calibration;
554
- this.BLE_BatteryLevel = ad.serviceData.battery;
555
- this.BLE_InMotion = ad.serviceData.inMotion;
556
- this.BLE_CurrentPosition = ad.serviceData.position;
557
- this.BLE_CurrentAmbientLightLevel = ad.serviceData.lightLevel;
558
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
559
- this.debugLog(
560
- `${this.device.deviceType}: ${this.accessory.displayName} calibration: ${ad.serviceData.calibration}, ` +
561
- `position: ${ad.serviceData.position}, lightLevel: ${ad.serviceData.lightLevel}, battery: ${ad.serviceData.battery}, ` +
562
- `inMotion: ${ad.serviceData.inMotion}`,
563
- );
564
-
565
- if (ad.serviceData) {
566
- this.BLE_IsConnected = true;
567
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
568
- await this.stopScanning(switchbot);
569
- } else {
570
- this.BLE_IsConnected = false;
571
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
572
- }
573
- };
574
- // Wait
575
- return await sleep(this.scanDuration * 1000);
576
- })
577
- .then(async () => {
578
- // Stop to monitor
579
- await this.stopScanning(switchbot);
580
- })
581
- .catch(async (e: any) => {
582
- this.apiError(e);
583
- this.errorLog(
584
- `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` +
585
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
586
- );
477
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed to get serviceData, serviceData: ${serviceData}`);
587
478
  await this.BLERefreshConnection(switchbot);
588
- });
589
- } else {
590
- await this.BLERefreshConnection(switchbot);
591
- }*/
479
+ }
480
+ })();
481
+ }
592
482
  }
593
483
 
594
484
  async openAPIRefreshStatus(): Promise<void> {
595
485
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
596
486
  try {
597
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
598
- headers: this.platform.generateHeaders(),
599
- });
600
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
487
+ const { body, statusCode } = await this.deviceRefreshStatus();
601
488
  const deviceStatus: any = await body.json();
602
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
603
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
489
+ await this.refreshStatusCodes(statusCode, deviceStatus);;
604
490
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
605
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
606
- + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
607
- this.OpenAPI_CurrentPosition = deviceStatus.body.slidePosition;
608
- this.OpenAPI_Direction = deviceStatus.body.direction;
609
- this.OpenAPI_InMotion = deviceStatus.body.moving;
610
- this.OpenAPI_CurrentAmbientLightLevel = deviceStatus.body.brightness;
611
- this.OpenAPI_BatteryLevel = deviceStatus.body.battery;
612
- this.OpenAPI_FirmwareRevision = deviceStatus.body.version;
613
- this.openAPIparseStatus();
614
- this.updateHomeKitCharacteristics();
491
+ await this.successfulRefreshStatus(statusCode, deviceStatus);
492
+ await this.openAPIparseStatus(deviceStatus);
493
+ await this.updateHomeKitCharacteristics();
615
494
  } else {
616
- this.statusCode(statusCode);
617
- this.statusCode(deviceStatus.statusCode);
495
+ await this.statusCodes(statusCode, deviceStatus);
618
496
  }
619
497
  } catch (e: any) {
620
498
  this.apiError(e);
621
- this.errorLog(
622
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` +
623
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
624
- );
499
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
500
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
501
+ }
502
+ }
503
+
504
+ async registerWebhook(accessory: PlatformAccessory, device: device & devicesConfig) {
505
+ if (device.webhook) {
506
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is listening webhook.`);
507
+ this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
508
+ try {
509
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
510
+ const { slidePosition, battery, lightLevel } = context;
511
+ const { CurrentPosition } = this.WindowCovering;
512
+ const { BatteryLevel } = this.Battery;
513
+ const { CurrentAmbientLightLevel } = this.LightSensor ?? {};
514
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} (slidePosition, battery, lightLevel) = Webhook:(${slidePosition}, ${battery},`
515
+ + ` ${lightLevel}), current:(${CurrentPosition}, ${BatteryLevel}, ${CurrentAmbientLightLevel})`);
516
+ this.WindowCovering.CurrentPosition = slidePosition;
517
+ this.Battery.BatteryLevel = battery;
518
+ if (!device.blindTilt?.hide_lightsensor) {
519
+ this.LightSensor!.CurrentAmbientLightLevel = lightLevel;
520
+ }
521
+ this.updateHomeKitCharacteristics();
522
+ } catch (e: any) {
523
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
524
+ }
525
+ };
526
+ } else {
527
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is not listening webhook.`);
625
528
  }
626
529
  }
627
530
 
@@ -634,9 +537,8 @@ export class BlindTilt {
634
537
  await this.openAPIpushChanges();
635
538
  } else {
636
539
  await this.offlineOff();
637
- this.debugWarnLog(
638
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`,
639
- );
540
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
541
+ + ` ${this.device.connectionType}, pushChanges will not happen.`);
640
542
  }
641
543
  // Refresh the status from the API
642
544
  interval(15000)
@@ -649,41 +551,33 @@ export class BlindTilt {
649
551
 
650
552
  async BLEpushChanges(): Promise<void> {
651
553
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
652
- if (this.TargetPosition !== this.CurrentPosition) {
554
+ if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition) {
653
555
  const switchbot = await this.platform.connectBLE();
654
556
  // Convert to BLE Address
655
- this.device.bleMac = this.device
656
- .deviceId!.match(/.{1,2}/g)!
657
- .join(':')
658
- .toLowerCase();
659
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
660
- this.SilentPerformance();
661
- const adjustedMode = this.setPositionMode || null;
662
- if (adjustedMode === null) {
663
- this.Mode = 'Default Mode';
664
- }
665
- this.debugLog(`${this.accessory.displayName} Mode: ${this.Mode}`);
557
+ await this.convertBLEAddress();
558
+ const { setPositionMode, Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
559
+ this.debugLog(`${this.accessory.displayName} Mode: ${Mode}`);
666
560
  if (switchbot !== false) {
667
561
  switchbot
668
- .discover({ model: 'c', quick: true, id: this.device.bleMac })
562
+ .discover({ model: this.device.bleModel, quick: true, id: this.device.bleMac })
669
563
  .then(async (device_list: any) => {
670
- this.infoLog(`${this.accessory.displayName} Target Position: ${this.TargetPosition}`);
671
- return await this.retry({
672
- max: this.maxRetry(),
564
+ this.infoLog(`${this.accessory.displayName} Target Position: ${this.WindowCovering.TargetPosition}`);
565
+ return await this.retryBLE({
566
+ max: await this.maxRetryBLE(),
673
567
  fn: async () => {
674
- return await device_list[0].runToPos(100 - Number(this.TargetPosition), adjustedMode);
568
+ return await device_list[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), setPositionMode);
675
569
  },
676
570
  });
677
571
  })
678
572
  .then(() => {
679
573
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
574
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
575
+ + `Target Position: ${this.WindowCovering.TargetPosition} sent over BLE, sent successfully`);
680
576
  })
681
577
  .catch(async (e: any) => {
682
578
  this.apiError(e);
683
- this.errorLog(
684
- `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` +
685
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
686
- );
579
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
580
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
687
581
  await this.BLEPushConnection();
688
582
  });
689
583
  } else {
@@ -691,50 +585,35 @@ export class BlindTilt {
691
585
  await this.BLEPushConnection();
692
586
  }
693
587
  } else {
694
- this.debugLog(
695
- `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` +
696
- ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
697
- );
698
- }
699
- }
700
-
701
- async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
702
- return fn().catch(async (e: any) => {
703
- if (max === 0) {
704
- throw e;
705
- }
706
- this.infoLog(e);
707
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Retrying`);
708
- await sleep(1000);
709
- return this.retry({ max: max - 1, fn });
710
- });
711
- }
712
-
713
- maxRetry(): number {
714
- if (this.device.maxRetry) {
715
- return this.device.maxRetry;
716
- } else {
717
- return 5;
588
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.`
589
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition ${this.WindowCovering.TargetPosition}`);
718
590
  }
719
591
  }
720
592
 
721
593
  async openAPIpushChanges(): Promise<void> {
722
594
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
723
595
  const hasDifferentAndRelevantHorizontalTiltAngle =
724
- this.mappingMode === BlindTiltMappingMode.UseTiltForDirection && this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle;
725
- if (this.TargetPosition !== this.CurrentPosition || hasDifferentAndRelevantHorizontalTiltAngle || this.device.disableCaching) {
726
- const [direction, position] = this.mapHomekitValuesToDeviceValues(Number(this.TargetPosition), Number(this.TargetHorizontalTiltAngle));
727
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Pushing ${this.TargetPosition} (device = ${direction};${position})`);
728
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Mode: ${this.Mode}`);
596
+ this.mappingMode === BlindTiltMappingMode.UseTiltForDirection
597
+ && this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle;
598
+ if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition
599
+ || hasDifferentAndRelevantHorizontalTiltAngle || this.device.disableCaching) {
600
+ const [direction, position] = this.mapHomekitValuesToDeviceValues(Number(this.WindowCovering.TargetPosition),
601
+ Number(this.WindowCovering.TargetHorizontalTiltAngle));
602
+ const { Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
603
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
604
+ + ` Pushing ${this.WindowCovering.TargetPosition} (device = ${direction};${position})`);
605
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Mode: ${Mode}`);
729
606
  let bodyChange = '';
730
607
  if (position === 100) {
731
608
  bodyChange = JSON.stringify({
732
609
  command: 'fullyOpen',
610
+ parameter: 'default',
733
611
  commandType: 'command',
734
612
  });
735
613
  } else if (position === 0) {
736
614
  bodyChange = JSON.stringify({
737
615
  command: direction === 'up' ? 'closeUp' : 'closeDown',
616
+ parameter: 'default',
738
617
  commandType: 'command',
739
618
  });
740
619
  } else {
@@ -746,36 +625,26 @@ export class BlindTilt {
746
625
  }
747
626
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${bodyChange},`);
748
627
  try {
749
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/commands`, {
750
- body: bodyChange,
751
- method: 'POST',
752
- headers: this.platform.generateHeaders(),
753
- });
754
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
628
+ const { body, statusCode } = await this.pushChangeRequest(bodyChange);
755
629
  const deviceStatus: any = await body.json();
756
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
757
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
758
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
630
+ await this.pushStatusCodes(statusCode, deviceStatus);
759
631
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
760
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
761
- + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
632
+ await this.successfulPushChange(statusCode, deviceStatus, bodyChange);
633
+ await this.updateHomeKitCharacteristics();
762
634
  } else {
763
- this.statusCode(statusCode);
764
- this.statusCode(deviceStatus.statusCode);
635
+ await this.statusCode(statusCode);
636
+ await this.statusCode(deviceStatus.statusCode);
765
637
  }
766
638
  } catch (e: any) {
767
639
  this.apiError(e);
768
- this.errorLog(
769
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` +
770
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
771
- );
640
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
641
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
772
642
  }
773
643
  } else {
774
- this.debugLog(
775
- `${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.` +
776
- ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}` +
777
- ` CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}, TargetPosition ${this.TargetHorizontalTiltAngle}`,
778
- );
644
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.`
645
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition ${this.WindowCovering.TargetPosition}`
646
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle},`
647
+ + ` TargetPosition ${this.WindowCovering.TargetHorizontalTiltAngle}`);
779
648
  }
780
649
  }
781
650
 
@@ -783,16 +652,16 @@ export class BlindTilt {
783
652
  * Handle requests to set the value of the "Target Horizontal Tilt" characteristic
784
653
  */
785
654
  async TargetHorizontalTiltAngleSet(value: CharacteristicValue): Promise<void> {
786
- if (this.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
655
+ if (this.WindowCovering.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
787
656
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetHorizontalTiltAngle: ${value}`);
788
657
  } else {
789
658
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetHorizontalTiltAngle: ${value}`);
790
659
  }
791
660
 
792
661
  //value = value < 0 ? -90 : 90;
793
- this.TargetHorizontalTiltAngle = value;
662
+ this.WindowCovering.TargetHorizontalTiltAngle = value;
794
663
  if (this.device.mqttURL) {
795
- this.mqttPublish('TargetHorizontalTiltAngle', this.TargetHorizontalTiltAngle);
664
+ this.mqttPublish('TargetHorizontalTiltAngle', this.WindowCovering.TargetHorizontalTiltAngle.toString());
796
665
  }
797
666
 
798
667
  this.startUpdatingBlindTiltIfNeeded();
@@ -802,15 +671,15 @@ export class BlindTilt {
802
671
  * Handle requests to set the value of the "Target Position" characteristic
803
672
  */
804
673
  async TargetPositionSet(value: CharacteristicValue): Promise<void> {
805
- if (this.TargetPosition === this.accessory.context.TargetPosition) {
674
+ if (this.WindowCovering.TargetPosition === this.accessory.context.TargetPosition) {
806
675
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetPosition: ${value}`);
807
676
  } else {
808
677
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
809
678
  }
810
679
 
811
- this.TargetPosition = value;
680
+ this.WindowCovering.TargetPosition = value;
812
681
  if (this.device.mqttURL) {
813
- this.mqttPublish('TargetPosition', this.TargetPosition);
682
+ this.mqttPublish('TargetPosition', this.WindowCovering.TargetPosition.toString());
814
683
  }
815
684
  this.startUpdatingBlindTiltIfNeeded();
816
685
  }
@@ -818,39 +687,37 @@ export class BlindTilt {
818
687
  async startUpdatingBlindTiltIfNeeded(): Promise<void> {
819
688
  await this.setMinMax();
820
689
  this.debugLog('setMinMax');
821
- if (this.TargetPosition > this.CurrentPosition || this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle) {
822
- this.PositionState = this.hap.Characteristic.PositionState.INCREASING;
690
+ if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
691
+ || this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle) {
692
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
823
693
  this.setNewTarget = true;
824
- this.debugLog(
825
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
826
- );
827
- } else if (this.TargetPosition < this.CurrentPosition) {
828
- this.PositionState = this.hap.Characteristic.PositionState.DECREASING;
694
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
695
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
696
+ } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
697
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
829
698
  this.setNewTarget = true;
830
- this.debugLog(
831
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
832
- );
699
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
700
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
833
701
  } else {
834
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
702
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
835
703
  this.setNewTarget = false;
836
- this.debugLog(
837
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
838
- );
704
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
705
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
839
706
  }
840
- this.windowCoveringService.setCharacteristic(this.hap.Characteristic.PositionState, this.PositionState);
841
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
707
+ this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.PositionState, this.WindowCovering.PositionState);
708
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
842
709
 
843
710
  /**
844
711
  * If Blind Tilt movement time is short, the moving flag from backend is always false.
845
712
  * The minimum time depends on the network control latency.
846
713
  */
847
714
  clearTimeout(this.setNewTargetTimer);
848
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.updateRate}`);
715
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.deviceUpdateRate}`);
849
716
  if (this.setNewTarget) {
850
717
  this.setNewTargetTimer = setTimeout(() => {
851
718
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} setNewTarget ${this.setNewTarget} timeout`);
852
719
  this.setNewTarget = false;
853
- }, this.updateRate * 1000);
720
+ }, this.deviceUpdateRate * 1000);
854
721
  }
855
722
  this.doBlindTiltUpdate.next();
856
723
  }
@@ -859,152 +726,105 @@ export class BlindTilt {
859
726
  await this.setMinMax();
860
727
  // CurrentHorizontalTiltAngle
861
728
  if (this.mappingMode === BlindTiltMappingMode.UseTiltForDirection) {
862
- if (this.CurrentHorizontalTiltAngle === undefined || Number.isNaN(this.CurrentHorizontalTiltAngle)) {
863
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
729
+ if (this.WindowCovering.CurrentHorizontalTiltAngle === undefined || Number.isNaN(this.WindowCovering.CurrentHorizontalTiltAngle)) {
730
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
731
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
864
732
  } else {
865
733
  if (this.device.mqttURL) {
866
- this.mqttPublish('CurrentHorizontalTiltAngle', this.CurrentHorizontalTiltAngle);
734
+ this.mqttPublish('CurrentHorizontalTiltAngle', this.WindowCovering.CurrentHorizontalTiltAngle.toString());
867
735
  }
868
- this.accessory.context.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
869
- this.windowCoveringService.updateCharacteristic(
736
+ this.accessory.context.CurrentHorizontalTiltAngle = this.WindowCovering.CurrentHorizontalTiltAngle;
737
+ this.WindowCovering.Service.updateCharacteristic(
870
738
  this.hap.Characteristic.CurrentHorizontalTiltAngle,
871
- Number(this.CurrentHorizontalTiltAngle),
872
- );
739
+ Number(this.WindowCovering.CurrentHorizontalTiltAngle));
873
740
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}
874
- updateCharacteristic CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
741
+ updateCharacteristic CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
875
742
  }
876
743
  }
877
744
  // CurrentPosition
878
- if (this.CurrentPosition === undefined || Number.isNaN(this.CurrentPosition)) {
879
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
745
+ if (this.WindowCovering.CurrentPosition === undefined || Number.isNaN(this.WindowCovering.CurrentPosition)) {
746
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
880
747
  } else {
881
748
  if (this.device.mqttURL) {
882
- this.mqttPublish('CurrentPosition', this.CurrentPosition);
749
+ this.mqttPublish('CurrentPosition', this.WindowCovering.CurrentPosition.toString());
883
750
  }
884
- this.accessory.context.CurrentPosition = this.CurrentPosition;
885
- this.windowCoveringService.updateCharacteristic(this.hap.Characteristic.CurrentPosition, Number(this.CurrentPosition));
886
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentPosition: ${this.CurrentPosition}`);
751
+ this.accessory.context.CurrentPosition = this.WindowCovering.CurrentPosition;
752
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, Number(this.WindowCovering.CurrentPosition));
753
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
754
+ + ` updateCharacteristic CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
887
755
  }
888
756
  // PositionState
889
- if (this.PositionState === undefined) {
890
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.PositionState}`);
757
+ if (this.WindowCovering.PositionState === undefined) {
758
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.WindowCovering.PositionState}`);
891
759
  } else {
892
760
  if (this.device.mqttURL) {
893
- this.mqttPublish('PositionState', this.PositionState);
761
+ this.mqttPublish('PositionState', this.WindowCovering.PositionState.toString());
894
762
  }
895
- this.accessory.context.PositionState = this.PositionState;
896
- this.windowCoveringService.updateCharacteristic(this.hap.Characteristic.PositionState, Number(this.PositionState));
897
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic PositionState: ${this.PositionState}`);
763
+ this.accessory.context.PositionState = this.WindowCovering.PositionState;
764
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, Number(this.WindowCovering.PositionState));
765
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
766
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
898
767
  }
899
768
  // TargetPosition
900
- if (this.TargetPosition === undefined || Number.isNaN(this.TargetPosition)) {
901
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.TargetPosition}`);
769
+ if (this.WindowCovering.TargetPosition === undefined || Number.isNaN(this.WindowCovering.TargetPosition)) {
770
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.WindowCovering.TargetPosition}`);
902
771
  } else {
903
772
  if (this.device.mqttURL) {
904
- this.mqttPublish('TargetPosition', this.TargetPosition);
773
+ this.mqttPublish('TargetPosition', this.WindowCovering.TargetPosition.toString());
905
774
  }
906
- this.accessory.context.TargetPosition = this.TargetPosition;
907
- this.windowCoveringService.updateCharacteristic(this.hap.Characteristic.TargetPosition, Number(this.TargetPosition));
908
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: ${this.TargetPosition}`);
775
+ this.accessory.context.TargetPosition = this.WindowCovering.TargetPosition;
776
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, Number(this.WindowCovering.TargetPosition));
777
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
778
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}`);
909
779
  }
910
780
  // CurrentAmbientLightLevel
911
781
  if (!this.device.blindTilt?.hide_lightsensor) {
912
- if (this.CurrentAmbientLightLevel === undefined || Number.isNaN(this.CurrentAmbientLightLevel)) {
913
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
782
+ if (this.LightSensor!.CurrentAmbientLightLevel === undefined || Number.isNaN(this.LightSensor!.CurrentAmbientLightLevel)) {
783
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
784
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
914
785
  } else {
915
786
  if (this.device.mqttURL) {
916
- this.mqttPublish('CurrentAmbientLightLevel', this.CurrentAmbientLightLevel);
787
+ this.mqttPublish('CurrentAmbientLightLevel', this.LightSensor!.CurrentAmbientLightLevel.toString());
917
788
  }
918
- this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel;
919
- this.lightSensorService?.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
920
- this.debugLog(
921
- `${this.device.deviceType}: ${this.accessory.displayName}` +
922
- ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
923
- );
789
+ this.accessory.context.CurrentAmbientLightLevel = this.LightSensor!.CurrentAmbientLightLevel;
790
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.LightSensor!.CurrentAmbientLightLevel);
791
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
792
+ + ` updateCharacteristic CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
924
793
  }
925
794
  }
926
795
  // BatteryLevel
927
- if (this.BatteryLevel === undefined) {
928
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
796
+ if (this.Battery.BatteryLevel === undefined) {
797
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
929
798
  } else {
930
799
  if (this.device.mqttURL) {
931
- this.mqttPublish('BatteryLevel', this.BatteryLevel);
800
+ this.mqttPublish('BatteryLevel', this.Battery.BatteryLevel.toString());
932
801
  }
933
- this.accessory.context.BatteryLevel = this.BatteryLevel;
934
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.BatteryLevel);
935
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
802
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
803
+ this.Battery?.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
804
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
936
805
  }
937
806
  // StatusLowBattery
938
- if (this.StatusLowBattery === undefined) {
939
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
807
+ if (this.Battery.StatusLowBattery === undefined) {
808
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
940
809
  } else {
941
810
  if (this.device.mqttURL) {
942
- this.mqttPublish('StatusLowBattery', this.StatusLowBattery);
811
+ this.mqttPublish('StatusLowBattery', this.Battery.StatusLowBattery.toString());
943
812
  }
944
- this.accessory.context.StatusLowBattery = this.StatusLowBattery;
945
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.StatusLowBattery);
946
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
813
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
814
+ this.Battery?.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
815
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
816
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
947
817
  }
948
- }
949
-
950
- /*
951
- * Publish MQTT message for topics of
952
- * 'homebridge-switchbot/blindtilt/xx:xx:xx:xx:xx:xx'
953
- */
954
- mqttPublish(topic: string, message: any) {
955
- const mac = this.device.deviceId
956
- ?.toLowerCase()
957
- .match(/[\s\S]{1,2}/g)
958
- ?.join(':');
959
- const options = this.device.mqttPubOptions || {};
960
- this.mqttClient?.publish(`homebridge-switchbot/blindtilt/${mac}/${topic}`, `${message}`, options);
961
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT message: ${topic}/${message} options:${JSON.stringify(options)}`);
962
- }
963
-
964
- /*
965
- * Setup MQTT hadler if URL is specified.
966
- */
967
- async setupMqtt(device: device & devicesConfig): Promise<void> {
968
- if (device.mqttURL) {
969
- try {
970
- const { connectAsync } = asyncmqtt;
971
- this.mqttClient = await connectAsync(device.mqttURL, device.mqttOptions || {});
972
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT connection has been established successfully.`);
973
- this.mqttClient.on('error', (e: Error) => {
974
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to publish MQTT messages. ${e}`);
975
- });
976
- } catch (e) {
977
- this.mqttClient = null;
978
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to establish MQTT connection. ${e}`);
979
- }
980
- }
981
- }
982
-
983
- async stopScanning(switchbot: any) {
984
- switchbot.stopScan();
985
- if (this.BLE_IsConnected) {
986
- await this.BLEparseStatus();
987
- await this.updateHomeKitCharacteristics();
818
+ if (this.Battery.ChargingState === undefined) {
819
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ChargingState: ${this.Battery.ChargingState}`);
988
820
  } else {
989
- await this.BLERefreshConnection(switchbot);
990
- }
991
- }
992
-
993
- async getCustomBLEAddress(switchbot: any) {
994
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
995
- (async () => {
996
- // Start to monitor advertisement packets
997
- await switchbot.startScan({
998
- model: 'c',
999
- });
1000
- // Set an event handler
1001
- switchbot.onadvertisement = (ad: any) => {
1002
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
1003
- };
1004
- await sleep(10000);
1005
- // Stop to monitor
1006
- switchbot.stopScan();
1007
- })();
821
+ if (this.device.mqttURL) {
822
+ this.mqttPublish('ChargingState', this.Battery.ChargingState.toString());
823
+ }
824
+ this.accessory.context.ChargingState = this.Battery.ChargingState;
825
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, this.Battery.ChargingState);
826
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
827
+ + ` ChargingState: ${this.Battery.ChargingState}`);
1008
828
  }
1009
829
  }
1010
830
 
@@ -1024,218 +844,74 @@ export class BlindTilt {
1024
844
  }
1025
845
  }
1026
846
 
1027
- async SilentPerformance() {
1028
- if (Number(this.TargetPosition) > 50) {
847
+ async setPerformance() {
848
+ let setPositionMode: number;
849
+ let Mode: string;
850
+ if (Number(this.WindowCovering.TargetPosition) > 50) {
1029
851
  if (this.device.blindTilt?.setOpenMode === '1') {
1030
- this.setPositionMode = 1;
1031
- this.Mode = 'Silent Mode';
852
+ setPositionMode = 1;
853
+ Mode = 'Silent Mode';
854
+ } else if (this.device.blindTilt?.setOpenMode === '0') {
855
+ setPositionMode = 0;
856
+ Mode = 'Performance Mode';
1032
857
  } else {
1033
- this.setPositionMode = 0;
1034
- this.Mode = 'Performance Mode';
858
+ setPositionMode = 0;
859
+ Mode = 'Default Mode';
1035
860
  }
1036
861
  } else {
1037
862
  if (this.device.blindTilt?.setCloseMode === '1') {
1038
- this.setPositionMode = 1;
1039
- this.Mode = 'Silent Mode';
863
+ setPositionMode = 1;
864
+ Mode = 'Silent Mode';
865
+ } else if (this.device.blindTilt?.setOpenMode === '0') {
866
+ setPositionMode = 0;
867
+ Mode = 'Performance Mode';
1040
868
  } else {
1041
- this.setPositionMode = 0;
1042
- this.Mode = 'Performance Mode';
869
+ setPositionMode = 0;
870
+ Mode = 'Default Mode';
1043
871
  }
1044
872
  }
873
+ return { setPositionMode, Mode };
1045
874
  }
1046
875
 
1047
876
  async setMinMax(): Promise<void> {
1048
877
  if (this.device.blindTilt?.set_min) {
1049
- if (Number(this.CurrentPosition) <= this.device.blindTilt?.set_min) {
1050
- this.CurrentPosition = 0;
878
+ if (Number(this.WindowCovering.CurrentPosition) <= this.device.blindTilt?.set_min) {
879
+ this.WindowCovering.CurrentPosition = 0;
1051
880
  }
1052
881
  }
1053
882
  if (this.device.blindTilt?.set_max) {
1054
- if (Number(this.CurrentPosition) >= this.device.blindTilt?.set_max) {
1055
- this.CurrentPosition = 100;
883
+ if (Number(this.WindowCovering.CurrentPosition) >= this.device.blindTilt?.set_max) {
884
+ this.WindowCovering.CurrentPosition = 100;
1056
885
  }
1057
886
  }
1058
887
 
1059
888
  if (this.mappingMode === BlindTiltMappingMode.UseTiltForDirection) {
1060
- this.CurrentHorizontalTiltAngle = Number(this.CurrentHorizontalTiltAngle) < 0 ? -90 : 90;
1061
- }
1062
- }
1063
-
1064
- minStep(device: device & devicesConfig): number {
1065
- if (device.blindTilt?.set_minStep) {
1066
- this.set_minStep = device.blindTilt?.set_minStep;
1067
- } else {
1068
- this.set_minStep = 1;
1069
- }
1070
- return this.set_minStep;
1071
- }
1072
-
1073
- minLux(): number {
1074
- if (this.device.blindTilt?.set_minLux) {
1075
- this.set_minLux = this.device.blindTilt?.set_minLux;
1076
- } else {
1077
- this.set_minLux = 1;
1078
- }
1079
- return this.set_minLux;
1080
- }
1081
-
1082
- maxLux(): number {
1083
- if (this.device.blindTilt?.set_maxLux) {
1084
- this.set_maxLux = this.device.blindTilt?.set_maxLux;
1085
- } else {
1086
- this.set_maxLux = 6001;
1087
- }
1088
- return this.set_maxLux;
1089
- }
1090
-
1091
- async scan(device: device & devicesConfig): Promise<void> {
1092
- if (device.scanDuration) {
1093
- if (this.updateRate > device.scanDuration) {
1094
- this.scanDuration = this.updateRate;
1095
- if (this.BLE) {
1096
- this.warnLog(
1097
- `${this.device.deviceType}: ` +
1098
- `${this.accessory.displayName} scanDuration is less than updateRate, overriding scanDuration with updateRate`,
1099
- );
1100
- }
1101
- } else {
1102
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
1103
- }
1104
- if (this.BLE) {
1105
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
1106
- }
1107
- } else {
1108
- if (this.updateRate > 1) {
1109
- this.scanDuration = this.updateRate;
1110
- } else {
1111
- this.scanDuration = this.accessory.context.scanDuration = 1;
1112
- }
1113
- if (this.BLE) {
1114
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
1115
- }
1116
- }
1117
- }
1118
-
1119
- async statusCode(statusCode: number): Promise<void> {
1120
- switch (statusCode) {
1121
- case 151:
1122
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
1123
- break;
1124
- case 152:
1125
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
1126
- break;
1127
- case 160:
1128
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
1129
- break;
1130
- case 161:
1131
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
1132
- this.offlineOff();
1133
- break;
1134
- case 171:
1135
- this.errorLog(
1136
- `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` +
1137
- `Hub: ${this.device.hubDeviceId}`,
1138
- );
1139
- this.offlineOff();
1140
- break;
1141
- case 190:
1142
- this.errorLog(
1143
- `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
1144
- ` Or command format is invalid, statusCode: ${statusCode}`,
1145
- );
1146
- break;
1147
- case 100:
1148
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
1149
- break;
1150
- case 200:
1151
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
1152
- break;
1153
- case 400:
1154
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bad Request, The client has issued an invalid request. `
1155
- + `This is commonly used to specify validation errors in a request payload, statusCode: ${statusCode}`);
1156
- break;
1157
- case 401:
1158
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unauthorized, Authorization for the API is required, `
1159
- + `but the request has not been authenticated, statusCode: ${statusCode}`);
1160
- break;
1161
- case 403:
1162
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Forbidden, The request has been authenticated but does not `
1163
- + `have appropriate permissions, or a requested resource is not found, statusCode: ${statusCode}`);
1164
- break;
1165
- case 404:
1166
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Found, Specifies the requested path does not exist, `
1167
- + `statusCode: ${statusCode}`);
1168
- break;
1169
- case 406:
1170
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Acceptable, The client has requested a MIME type via `
1171
- + `the Accept header for a value not supported by the server, statusCode: ${statusCode}`);
1172
- break;
1173
- case 415:
1174
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unsupported Media Type, The client has defined a contentType `
1175
- + `header that is not supported by the server, statusCode: ${statusCode}`);
1176
- break;
1177
- case 422:
1178
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unprocessable Entity, The client has made a valid request, `
1179
- + `but the server cannot process it. This is often used for APIs for which certain limits have been exceeded, statusCode: ${statusCode}`);
1180
- break;
1181
- case 429:
1182
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Too Many Requests, The client has exceeded the number of `
1183
- + `requests allowed for a given time window, statusCode: ${statusCode}`);
1184
- break;
1185
- case 500:
1186
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Internal Server Error, An unexpected error on the SmartThings `
1187
- + `servers has occurred. These errors should be rare, statusCode: ${statusCode}`);
1188
- break;
1189
- default:
1190
- this.infoLog(
1191
- `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` +
1192
- `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`,
1193
- );
889
+ this.WindowCovering.CurrentHorizontalTiltAngle = Number(this.WindowCovering.CurrentHorizontalTiltAngle) < 0 ? -90 : 90;
1194
890
  }
1195
891
  }
1196
892
 
1197
893
  async offlineOff(): Promise<void> {
1198
894
  if (this.device.offline) {
1199
- await this.deviceContext();
1200
- await this.updateHomeKitCharacteristics();
895
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
896
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
897
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
898
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle, 90);
899
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle, 90);
1201
900
  }
1202
901
  }
1203
902
 
1204
903
  async apiError(e: any): Promise<void> {
1205
- this.windowCoveringService.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
1206
- this.windowCoveringService.updateCharacteristic(this.hap.Characteristic.PositionState, e);
1207
- this.windowCoveringService.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
1208
- if (!this.device.curtain?.hide_lightsensor) {
1209
- this.lightSensorService?.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, e);
1210
- }
1211
- if (this.BLE) {
1212
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
1213
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
1214
- }
1215
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
1216
- }
1217
-
1218
- async deviceContext() {
1219
- if (this.CurrentPosition === undefined) {
1220
- this.CurrentPosition = 0;
1221
- } else {
1222
- this.CurrentPosition = this.accessory.context.CurrentPosition;
1223
- }
1224
-
1225
- if (this.TargetPosition === undefined) {
1226
- this.TargetPosition = 0;
1227
- } else {
1228
- this.TargetPosition = this.accessory.context.TargetPosition;
1229
- }
1230
-
1231
- if (this.PositionState === undefined) {
1232
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
1233
- } else {
1234
- this.PositionState = this.accessory.context.PositionState;
1235
- }
1236
- if (this.FirmwareRevision === undefined) {
1237
- this.FirmwareRevision = this.platform.version;
1238
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
904
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
905
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e);
906
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
907
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle, e);
908
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle, e);
909
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
910
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
911
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, e);
912
+ if (!this.device.blindTilt?.hide_lightsensor) {
913
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, e);
914
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.StatusActive, e);
1239
915
  }
1240
916
  }
1241
917
 
@@ -1253,7 +929,8 @@ export class BlindTilt {
1253
929
 
1254
930
  // homekit position 0 => closed
1255
931
  // homekit position 100 => open
1256
- deviceDirection;
932
+ const direction = deviceDirection === 'up' ? 'up' : 'down';
933
+ this.debugLog(`Mapping device values to homekit values, devicePostion: ${devicePosition}, deviceDirection: ${direction}`);
1257
934
  switch (this.mappingMode) {
1258
935
  case BlindTiltMappingMode.OnlyUp:
1259
936
  // we only close upwards, so we see anything that is tilted downwards(<50) as open
@@ -1358,130 +1035,4 @@ export class BlindTilt {
1358
1035
  }
1359
1036
  }
1360
1037
  }
1361
-
1362
- async refreshRate(device: device & devicesConfig): Promise<void> {
1363
- // refreshRate
1364
- if (device.refreshRate) {
1365
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
1366
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
1367
- } else if (this.platform.config.options!.refreshRate) {
1368
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
1369
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
1370
- }
1371
- // updateRate
1372
- if (device?.blindTilt?.updateRate) {
1373
- this.updateRate = device?.blindTilt?.updateRate;
1374
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Blind Tilt updateRate: ${this.updateRate}`);
1375
- } else {
1376
- this.updateRate = 2;
1377
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default Blind Tilt updateRate: ${this.updateRate}`);
1378
- }
1379
- }
1380
-
1381
- async deviceConfig(device: device & devicesConfig): Promise<void> {
1382
- let config = {};
1383
- if (device.blindTilt) {
1384
- config = device.blindTilt;
1385
- }
1386
- if (device.connectionType !== undefined) {
1387
- config['connectionType'] = device.connectionType;
1388
- }
1389
- if (device.external !== undefined) {
1390
- config['external'] = device.external;
1391
- }
1392
- if (device.mqttURL !== undefined) {
1393
- config['mqttURL'] = device.mqttURL;
1394
- }
1395
- if (device.logging !== undefined) {
1396
- config['logging'] = device.logging;
1397
- }
1398
- if (device.refreshRate !== undefined) {
1399
- config['refreshRate'] = device.refreshRate;
1400
- }
1401
- if (device.scanDuration !== undefined) {
1402
- config['scanDuration'] = device.scanDuration;
1403
- }
1404
- if (device.maxRetry !== undefined) {
1405
- config['maxRetry'] = device.maxRetry;
1406
- }
1407
- if (device.webhook !== undefined) {
1408
- config['webhook'] = device.webhook;
1409
- }
1410
- if (device.blindTilt?.mode === undefined) {
1411
- config['mode'] = BlindTiltMappingMode.OnlyUp;
1412
- } else {
1413
- config['mode'] = device.blindTilt?.mode;
1414
- }
1415
-
1416
- if (Object.entries(config).length !== 0) {
1417
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
1418
- }
1419
- }
1420
-
1421
- async deviceLogs(device: device & devicesConfig): Promise<void> {
1422
- if (this.platform.debugMode) {
1423
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
1424
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
1425
- } else if (device.logging) {
1426
- this.deviceLogging = this.accessory.context.logging = device.logging;
1427
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
1428
- } else if (this.platform.config.options?.logging) {
1429
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
1430
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
1431
- } else {
1432
- this.deviceLogging = this.accessory.context.logging = 'standard';
1433
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
1434
- }
1435
- }
1436
-
1437
- /**
1438
- * Logging for Device
1439
- */
1440
- infoLog(...log: any[]): void {
1441
- if (this.enablingDeviceLogging()) {
1442
- this.platform.log.info(String(...log));
1443
- }
1444
- }
1445
-
1446
- warnLog(...log: any[]): void {
1447
- if (this.enablingDeviceLogging()) {
1448
- this.platform.log.warn(String(...log));
1449
- }
1450
- }
1451
-
1452
- debugWarnLog(...log: any[]): void {
1453
- if (this.enablingDeviceLogging()) {
1454
- if (this.deviceLogging?.includes('debug')) {
1455
- this.platform.log.warn('[DEBUG]', String(...log));
1456
- }
1457
- }
1458
- }
1459
-
1460
- errorLog(...log: any[]): void {
1461
- if (this.enablingDeviceLogging()) {
1462
- this.platform.log.error(String(...log));
1463
- }
1464
- }
1465
-
1466
- debugErrorLog(...log: any[]): void {
1467
- if (this.enablingDeviceLogging()) {
1468
- if (this.deviceLogging?.includes('debug')) {
1469
- this.platform.log.error('[DEBUG]', String(...log));
1470
- }
1471
- }
1472
- }
1473
-
1474
- debugLog(...log: any[]): void {
1475
- if (this.enablingDeviceLogging()) {
1476
- if (this.deviceLogging === 'debug') {
1477
- this.platform.log.info('[DEBUG]', String(...log));
1478
- } else {
1479
- this.platform.log.debug(String(...log));
1480
- }
1481
- }
1482
- }
1483
-
1484
- enablingDeviceLogging(): boolean {
1485
- return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
1486
- }
1487
1038
  }