@switchbot/homebridge-switchbot 3.5.0-beta.8 → 3.5.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 (178) hide show
  1. package/.vscode/settings.json +4 -1
  2. package/CHANGELOG.md +4 -1
  3. package/config.schema.json +170 -26
  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 +439 -817
  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 +835 -865
  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 +287 -653
  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 +354 -732
  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 +268 -576
  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 +431 -851
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/device.d.ts +60 -0
  29. package/dist/device/device.d.ts.map +1 -0
  30. package/dist/device/device.js +739 -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 +698 -0
  35. package/dist/device/fan.js.map +1 -0
  36. package/dist/device/hub.d.ts +15 -60
  37. package/dist/device/hub.d.ts.map +1 -1
  38. package/dist/device/hub.js +257 -631
  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 +266 -629
  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 +215 -615
  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 +336 -645
  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 +290 -595
  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 +211 -608
  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 +205 -615
  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 +202 -563
  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 +125 -484
  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 +233 -549
  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 +170 -493
  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 +340 -468
  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 +105 -319
  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 +44 -285
  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 +92 -350
  102. package/dist/irdevice/fan.js.map +1 -1
  103. package/dist/irdevice/irdevice.d.ts +40 -0
  104. package/dist/irdevice/irdevice.d.ts.map +1 -0
  105. package/dist/irdevice/irdevice.js +369 -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 +118 -362
  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 +438 -570
  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 +91 -339
  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 +45 -285
  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 +47 -291
  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 +64 -17
  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 +77 -0
  136. package/dist/utils.d.ts.map +1 -1
  137. package/dist/utils.js +638 -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 +472 -888
  143. package/src/device/bot.ts +893 -968
  144. package/src/device/ceilinglight.ts +304 -709
  145. package/src/device/colorbulb.ts +370 -803
  146. package/src/device/contact.ts +301 -611
  147. package/src/device/curtain.ts +460 -908
  148. package/src/device/device.ts +755 -0
  149. package/src/device/fan.ts +749 -0
  150. package/src/device/hub.ts +294 -664
  151. package/src/device/humidifier.ts +299 -696
  152. package/src/device/iosensor.ts +251 -644
  153. package/src/device/lightstrip.ts +362 -712
  154. package/src/device/lock.ts +328 -653
  155. package/src/device/meter.ts +247 -637
  156. package/src/device/meterplus.ts +240 -644
  157. package/src/device/motion.ts +230 -598
  158. package/src/device/plug.ts +139 -525
  159. package/src/device/robotvacuumcleaner.ts +258 -593
  160. package/src/device/waterdetector.ts +191 -522
  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 +370 -527
  165. package/src/irdevice/airpurifier.ts +132 -356
  166. package/src/irdevice/camera.ts +58 -311
  167. package/src/irdevice/fan.ts +109 -379
  168. package/src/irdevice/irdevice.ts +382 -0
  169. package/src/irdevice/light.ts +157 -412
  170. package/src/irdevice/other.ts +507 -648
  171. package/src/irdevice/tv.ts +121 -375
  172. package/src/irdevice/vacuumcleaner.ts +59 -311
  173. package/src/irdevice/waterheater.ts +61 -320
  174. package/src/platform.ts +395 -259
  175. package/src/settings.ts +118 -609
  176. package/src/utils.ts +642 -1
  177. package/.github/npm-version-script.cjs +0 -81
  178. package/src/device/waterdetector.json +0 -11
@@ -1,113 +1,63 @@
1
+ /* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
+ *
3
+ * blindtilt.ts: @switchbot/homebridge-switchbot.
4
+ */
1
5
  import { request } from 'undici';
2
- import { sleep } from '../utils.js';
3
- import { MqttClient } from 'mqtt';
6
+ import { Devices } from '../settings.js';
4
7
  import { interval, Subject } from 'rxjs';
5
- import asyncmqtt from 'async-mqtt';
6
- import { SwitchBotPlatform } from '../platform.js';
8
+ import { deviceBase } from './device.js';
9
+ import { BlindTiltMappingMode } from '../utils.js';
7
10
  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
11
 
19
- export class BlindTilt {
20
- public readonly api: API;
21
- public readonly log: Logging;
22
- public readonly config!: SwitchBotPlatformConfig;
23
- protected readonly hap: HAP;
12
+ import type { SwitchBotPlatform } from '../platform.js';
13
+ import type { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
14
+ import type { device, devicesConfig, serviceData, deviceStatus } from '../settings.js';
15
+
16
+
17
+ export class BlindTilt extends deviceBase {
24
18
  // 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'];
19
+ private WindowCovering: {
20
+ Name: CharacteristicValue;
21
+ Service: Service;
22
+ PositionState: CharacteristicValue;
23
+ TargetPosition: CharacteristicValue;
24
+ CurrentPosition: CharacteristicValue;
25
+ TargetHorizontalTiltAngle: CharacteristicValue;
26
+ CurrentHorizontalTiltAngle: CharacteristicValue;
27
+ };
28
+
29
+ private Battery: {
30
+ Name: CharacteristicValue;
31
+ Service: Service;
32
+ BatteryLevel: CharacteristicValue;
33
+ StatusLowBattery: CharacteristicValue;
34
+ ChargingState?: CharacteristicValue;
35
+ };
36
+
37
+ private LightSensor?: {
38
+ Name: CharacteristicValue;
39
+ Service: Service;
40
+ CurrentAmbientLightLevel?: CharacteristicValue;
41
+ };
48
42
 
49
43
  // OpenAPI Others
50
- Mode!: string;
51
- setPositionMode?: string | number;
52
44
  mappingMode: BlindTiltMappingMode = BlindTiltMappingMode.OnlyUp;
53
45
 
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
46
  // Target
66
47
  setNewTarget!: boolean;
67
48
  setNewTargetTimer!: NodeJS.Timeout;
68
49
 
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
50
  // Updates
84
51
  blindTiltUpdateInProgress!: boolean;
85
52
  doBlindTiltUpdate!: Subject<void>;
86
53
 
87
- // Connection
88
- private readonly OpenAPI: boolean;
89
- private readonly BLE: boolean;
90
-
91
54
  constructor(
92
- private readonly platform: SwitchBotPlatform,
93
- private accessory: PlatformAccessory,
94
- public device: device & devicesConfig,
55
+ readonly platform: SwitchBotPlatform,
56
+ accessory: PlatformAccessory,
57
+ device: device & devicesConfig,
95
58
  ) {
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';
59
+ super(platform, accessory, device);
103
60
  // 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
61
  this.mappingMode = (device.blindTilt?.mode as BlindTiltMappingMode) ?? BlindTiltMappingMode.OnlyUp;
112
62
  this.debugLog(`Mapping mode: ${this.mappingMode}`);
113
63
 
@@ -116,57 +66,49 @@ export class BlindTilt {
116
66
  this.blindTiltUpdateInProgress = false;
117
67
  this.setNewTarget = false;
118
68
 
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)
69
+ // Initialize WindowCovering Service
70
+ accessory.context.WindowCovering = accessory.context.WindowCovering ?? {};
71
+ this.WindowCovering = {
72
+ Name: accessory.context.WindowCovering.Name ?? accessory.displayName,
73
+ Service: accessory.getService(this.hap.Service.WindowCovering) ?? accessory.addService(this.hap.Service.WindowCovering) as Service,
74
+ PositionState: accessory.context.PositionState ?? this.hap.Characteristic.PositionState.STOPPED,
75
+ TargetPosition: accessory.context.TargetPosition ?? 100,
76
+ CurrentPosition: accessory.context.CurrentPosition ?? 100,
77
+ TargetHorizontalTiltAngle: accessory.context.TargetHorizontalTiltAngle ?? 90,
78
+ CurrentHorizontalTiltAngle: accessory.context.CurrentHorizontalTiltAngle ?? 90,
79
+ };
80
+ accessory.context.WindowCovering = this.WindowCovering as object;
81
+
82
+ // Initialize WindowCovering Characteristics
83
+ this.WindowCovering.Service
84
+ .setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name)
85
+ .getCharacteristic(this.hap.Characteristic.TargetPosition)
147
86
  .setProps({
148
- minStep: this.minStep(device),
87
+ minStep: device.blindTilt?.set_minStep ?? 1,
149
88
  minValue: 0,
150
89
  maxValue: 100,
151
90
  validValueRanges: [0, 100],
152
91
  })
153
92
  .onGet(() => {
154
- return this.CurrentPosition;
155
- });
93
+ return this.WindowCovering.TargetPosition;
94
+ })
95
+ .onSet(this.TargetPositionSet.bind(this));
156
96
 
157
- this.windowCoveringService
158
- .getCharacteristic(this.hap.Characteristic.TargetPosition)
97
+ // Initialize WindowCovering CurrentPosition Characteristic
98
+ this.WindowCovering.Service
99
+ .getCharacteristic(this.hap.Characteristic.CurrentPosition)
159
100
  .setProps({
160
- minStep: this.minStep(device),
101
+ minStep: device.blindTilt?.set_minStep ?? 1,
161
102
  minValue: 0,
162
103
  maxValue: 100,
163
104
  validValueRanges: [0, 100],
164
- })
165
- .onSet(this.TargetPositionSet.bind(this));
105
+ }).onGet(() => {
106
+ return this.WindowCovering?.CurrentPosition ?? 0;
107
+ });
166
108
 
167
- this.CurrentHorizontalTiltAngle = 90;
168
- this.windowCoveringService
169
- .getCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle)
109
+ // Initialize WindowCovering TargetHorizontalTiltAngle Characteristic
110
+ this.WindowCovering.Service
111
+ .getCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle)
170
112
  .setProps({
171
113
  minStep: 180,
172
114
  minValue: -90,
@@ -174,31 +116,68 @@ export class BlindTilt {
174
116
  validValues: [-90, 90],
175
117
  })
176
118
  .onGet(() => {
177
- // this.debugLog(`requested CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
178
- return this.CurrentHorizontalTiltAngle;
179
- });
119
+ return this.WindowCovering.TargetHorizontalTiltAngle;
120
+ })
121
+ .onSet(this.TargetHorizontalTiltAngleSet.bind(this));
180
122
 
181
- this.TargetHorizontalTiltAngle = 90;
182
- this.windowCoveringService
183
- .getCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle)
123
+ // Initialize WindowCovering CurrentHorizontalTiltAngle Characteristic
124
+ this.WindowCovering.Service
125
+ .getCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle)
184
126
  .setProps({
185
127
  minStep: 180,
186
128
  minValue: -90,
187
129
  maxValue: 90,
188
130
  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;
131
+ }).onGet(() => {
132
+ return this.WindowCovering.CurrentHorizontalTiltAngle ?? 0;
133
+ });
196
134
 
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`);
135
+ // Initialize Battery Service
136
+ accessory.context.Battery = accessory.context.Battery ?? {};
137
+ this.Battery = {
138
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
139
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
140
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
141
+ StatusLowBattery: this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
142
+ ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGING,
143
+ };
144
+ accessory.context.Battery = this.Battery as object;
145
+
146
+ // Initialize Battery Name Characteristic
147
+ this.Battery.Service
148
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
149
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
150
+
151
+ // Initialize LightSensor Service
152
+ if (device.blindTilt?.hide_lightsensor) {
153
+ if (this.LightSensor?.Service) {
154
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} Removing Light Sensor Service`);
155
+ this.LightSensor.Service = accessory.getService(this.hap.Service.LightSensor) as Service;
156
+ accessory.removeService(this.LightSensor.Service);
157
+ accessory.context.LightSensor = {};
158
+ }
159
+ } else {
160
+ accessory.context.LightSensor = accessory.context.LightSensor ?? {};
161
+ this.LightSensor = {
162
+ Name: accessory.context.LightSensor.Name ?? `${accessory.displayName} Light Sensor`,
163
+ Service: accessory.getService(this.hap.Service.LightSensor) ?? accessory.addService(this.hap.Service.LightSensor) as Service,
164
+ CurrentAmbientLightLevel: accessory.context.CurrentAmbientLightLevel ?? 0.0001,
165
+ };
166
+ accessory.context.LightSensor = this.LightSensor as object;
167
+
168
+ // Initialize LightSensor Characteristics
169
+ this.LightSensor.Service
170
+ .setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name)
171
+ .setCharacteristic(this.hap.Characteristic.StatusActive, true)
172
+ .getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel)
173
+ .onGet(() => {
174
+ return this.LightSensor?.CurrentAmbientLightLevel ?? 0.0001;
175
+ });
200
176
  }
201
177
 
178
+ // Retrieve initial values and updateHomekit
179
+ this.refreshStatus();
180
+
202
181
  // Update Homekit
203
182
  this.updateHomeKitCharacteristics();
204
183
 
@@ -210,36 +189,16 @@ export class BlindTilt {
210
189
  });
211
190
 
212
191
  //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
- }
192
+ this.registerWebhook(accessory, device);
234
193
 
235
194
  // update slide progress
236
- interval(this.updateRate * 1000)
237
- //.pipe(skipWhile(() => this.blindTiltUpdateInProgress))
195
+ interval(this.deviceUpdateRate * 1000)
238
196
  .subscribe(async () => {
239
- if (this.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
197
+ if (this.WindowCovering.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
240
198
  return;
241
199
  }
242
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Refresh Status When Moving, PositionState: ${this.PositionState}`);
200
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} Refresh Status When Moving,`
201
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
243
202
  await this.refreshStatus();
244
203
  });
245
204
 
@@ -250,235 +209,241 @@ export class BlindTilt {
250
209
  tap(() => {
251
210
  this.blindTiltUpdateInProgress = true;
252
211
  }),
253
- debounceTime(this.platform.config.options!.pushRate! * 1000),
212
+ debounceTime(this.devicePushRate * 1000),
254
213
  )
255
214
  .subscribe(async () => {
256
215
  try {
257
216
  await this.pushChanges();
258
217
  } catch (e: any) {
259
218
  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
- );
219
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed pushChanges with ${device.connectionType} Connection,`
220
+ + ` Error Message: ${JSON.stringify(e.message)}`);
264
221
  }
265
222
  this.blindTiltUpdateInProgress = false;
266
223
  });
267
224
  }
268
225
 
269
226
  /**
270
- * Parse the device status from the SwitchBot api
227
+ * Parse the device status from the SwitchBotBLE API
271
228
  */
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> {
229
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
288
230
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
289
231
  // CurrentPosition
290
- this.CurrentPosition = 100 - Number(this.BLE_CurrentPosition);
232
+ this.WindowCovering.CurrentPosition = 100 - Number(serviceData.position);
291
233
  await this.setMinMax();
292
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.CurrentPosition}`);
234
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.WindowCovering.CurrentPosition}`);
293
235
  if (this.setNewTarget) {
294
236
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
295
237
  }
296
238
 
297
- if (this.setNewTarget && this.BLE_InMotion) {
239
+ if (this.setNewTarget && serviceData.inMotion) {
298
240
  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}`);
241
+ if (Number(this.WindowCovering.TargetPosition) > this.WindowCovering.CurrentPosition) {
242
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
243
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
244
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
245
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} INCREASING`
246
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
247
+ } else if (Number(this.WindowCovering.TargetPosition) < this.WindowCovering.CurrentPosition) {
248
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
249
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
250
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
251
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} DECREASING`
252
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
309
253
  } 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}`);
254
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} Standby2,`
255
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
256
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
257
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
258
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} STOPPED`
259
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
314
260
  }
315
261
  } 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;
262
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
263
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
264
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
319
265
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
320
266
  }
321
- this.debugLog(
322
- `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
323
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
324
- );
267
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition},`
268
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`);
325
269
 
326
270
  if (!this.device.blindTilt?.hide_lightsensor) {
327
- this.set_minLux = this.minLux();
328
- this.set_maxLux = this.maxLux();
329
- this.spaceBetweenLevels = 9;
271
+ const set_minLux = this.device.blindTilt?.set_minLux ?? 1;
272
+ const set_maxLux = this.device.blindTilt?.set_maxLux ?? 6001;
273
+ const spaceBetweenLevels = 9;
274
+
275
+ if (this.LightSensor?.CurrentAmbientLightLevel === 0) {
276
+ this.LightSensor!.CurrentAmbientLightLevel = 0.0001;
277
+ }
330
278
 
331
279
  // Brightness
332
- switch (this.BLE_CurrentAmbientLightLevel) {
280
+ switch (serviceData.lightLevel) {
333
281
  case 1:
334
- this.CurrentAmbientLightLevel = this.set_minLux;
335
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
282
+ this.LightSensor!.CurrentAmbientLightLevel = set_minLux;
283
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
336
284
  break;
337
285
  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
- );
286
+ this.LightSensor!.CurrentAmbientLightLevel = (set_maxLux - set_minLux) / spaceBetweenLevels;
287
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel},`
288
+ + ` Calculation: ${(set_maxLux - set_minLux) / spaceBetweenLevels}`);
343
289
  break;
344
290
  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}`);
291
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 2;
292
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
347
293
  break;
348
294
  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}`);
295
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 3;
296
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
351
297
  break;
352
298
  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}`);
299
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 4;
300
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
355
301
  break;
356
302
  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}`);
303
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 5;
304
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
359
305
  break;
360
306
  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}`);
307
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 6;
308
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
363
309
  break;
364
310
  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}`);
311
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 7;
312
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
367
313
  break;
368
314
  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}`);
315
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 8;
316
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
371
317
  break;
372
318
  case 10:
373
319
  default:
374
- this.CurrentAmbientLightLevel = this.set_maxLux;
320
+ this.LightSensor!.CurrentAmbientLightLevel = set_maxLux;
375
321
  this.debugLog();
376
322
  }
377
- this.debugLog(
378
- `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel},` +
379
- ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
380
- );
323
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel},`
324
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
381
325
  }
382
326
  // Battery
383
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
384
- if (this.BatteryLevel < 10) {
385
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
327
+ this.Battery.BatteryLevel = Number(serviceData.battery);
328
+ if (this.Battery.BatteryLevel < 10) {
329
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
386
330
  } else {
387
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
331
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
388
332
  }
389
- this.debugLog(
390
- `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` + ` StatusLowBattery: ${this.StatusLowBattery}`,
391
- );
333
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
334
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
392
335
  }
393
336
 
394
- async openAPIparseStatus(): Promise<void> {
337
+
338
+ /**
339
+ * Parse the device status from the SwitchBot OpenAPI
340
+ */
341
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
395
342
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
396
343
 
397
- const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(this.OpenAPI_CurrentPosition),
398
- String(this.OpenAPI_Direction));
399
- this.debugLog(` device: ${this.OpenAPI_CurrentPosition} => HK: ${homekitPosition}`);
344
+ const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(deviceStatus.body.slidePosition),
345
+ String(deviceStatus.body.direction));
346
+ this.debugLog(` device: ${deviceStatus.body.slidePosition} => HK: ${homekitPosition}`);
400
347
 
401
- this.CurrentPosition = homekitPosition;
348
+ this.WindowCovering!.CurrentPosition = homekitPosition;
402
349
  // CurrentPosition
403
350
  await this.setMinMax();
404
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
351
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
405
352
 
406
353
  if (homekitTiltAngle) {
407
- this.CurrentHorizontalTiltAngle = homekitTiltAngle!;
408
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
354
+ this.WindowCovering.CurrentHorizontalTiltAngle = homekitTiltAngle!;
355
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
356
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
409
357
  }
410
358
 
411
359
  if (this.setNewTarget) {
412
360
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
413
361
  }
414
362
 
415
- if (this.setNewTarget && this.OpenAPI_InMotion) {
363
+ if (this.setNewTarget && deviceStatus.body.moving) {
416
364
  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}`);
365
+ if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
366
+ || (homekitTiltAngle && this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle)) {
367
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition} `);
368
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
369
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
370
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} INCREASING`
371
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
372
+ } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
373
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition} `);
374
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
375
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
376
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} DECREASING`
377
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
427
378
  } 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}`);
379
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} Standby because reached position,`
380
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
381
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
382
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
383
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} STOPPED`
384
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
434
385
  }
435
386
  } 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;
387
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,`
388
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
389
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
440
390
  if (homekitTiltAngle) {
441
- this.TargetHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
391
+ this.WindowCovering.TargetHorizontalTiltAngle = this.WindowCovering.CurrentHorizontalTiltAngle;
442
392
  }
443
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
393
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
444
394
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
445
395
  }
446
- this.debugLog(
447
- `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
448
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
449
- );
450
-
396
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition},`
397
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`);
451
398
  if (!this.device.blindTilt?.hide_lightsensor) {
452
- this.set_minLux = this.minLux();
453
- this.set_maxLux = this.maxLux();
399
+ const set_minLux = this.device.blindTilt?.set_minLux ?? 1;
400
+ const set_maxLux = this.device.blindTilt?.set_maxLux ?? 6001;
454
401
  // Brightness
455
- switch (this.OpenAPI_CurrentAmbientLightLevel) {
402
+ switch (deviceStatus.body.brightness) {
456
403
  case 'dim':
457
- this.CurrentAmbientLightLevel = this.set_minLux;
404
+ this.LightSensor!.CurrentAmbientLightLevel = set_minLux;
458
405
  break;
459
406
  case 'bright':
460
407
  default:
461
- this.CurrentAmbientLightLevel = this.set_maxLux;
408
+ this.LightSensor!.CurrentAmbientLightLevel = set_maxLux;
462
409
  }
463
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
410
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
411
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
464
412
  }
465
413
 
466
414
  // BatteryLevel
467
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
468
- if (this.BatteryLevel < 10) {
469
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
415
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
416
+ if (this.Battery.BatteryLevel < 10) {
417
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
470
418
  } else {
471
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
472
- }
473
- if (Number.isNaN(this.BatteryLevel)) {
474
- this.BatteryLevel = 100;
419
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
420
+ }
421
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
422
+ this.Battery.BatteryLevel = 100;
423
+ }
424
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
425
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
426
+
427
+ // Firmware Version
428
+ const version = deviceStatus.body.version?.toString();
429
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
430
+ let deviceVersion: string;
431
+ if (version?.includes('.') === false) {
432
+ const replace = version?.replace(/^V|-.*$/g, '');
433
+ const match = replace?.match(/.{1,1}/g);
434
+ const blindTiltVersion = match?.join('.') ?? '0.0.0';
435
+ deviceVersion = blindTiltVersion;
436
+ } else {
437
+ deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
475
438
  }
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;
439
+ this.accessory
440
+ .getService(this.hap.Service.AccessoryInformation)!
441
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
442
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
443
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
444
+ .updateValue(deviceVersion);
445
+ this.accessory.context.deviceVersion = deviceVersion;
446
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
482
447
  }
483
448
 
484
449
  async refreshStatus(): Promise<void> {
@@ -490,10 +455,8 @@ export class BlindTilt {
490
455
  await this.openAPIRefreshStatus();
491
456
  } else {
492
457
  await this.offlineOff();
493
- this.debugWarnLog(
494
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` +
495
- ` ${this.device.connectionType}, refreshStatus will not happen.`,
496
- );
458
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
459
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
497
460
  }
498
461
  }
499
462
 
@@ -510,21 +473,13 @@ export class BlindTilt {
510
473
  // Start to monitor advertisement packets
511
474
  (async () => {
512
475
  // Start to monitor advertisement packets
513
- await switchbot.startScan({
514
- model: 'x',
515
- id: this.device.bleMac,
516
- });
476
+ await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
517
477
  // Set an event handler
518
478
  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') {
479
+ if (this.device.bleMac === ad.address && ad.model === this.device.bleModel) {
480
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
481
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
522
482
  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;
528
483
  } else {
529
484
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
530
485
  }
@@ -534,83 +489,27 @@ export class BlindTilt {
534
489
  // Stop to monitor
535
490
  await switchbot.stopScan();
536
491
  // Update HomeKit
537
- await this.BLEparseStatus();
492
+ await this.BLEparseStatus(switchbot.onadvertisement.serviceData);
538
493
  await this.updateHomeKitCharacteristics();
539
494
  })();
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
- );
587
- await this.BLERefreshConnection(switchbot);
588
- });
589
- } else {
495
+ if (switchbot === undefined) {
590
496
  await this.BLERefreshConnection(switchbot);
591
- }*/
497
+ }
592
498
  }
593
499
 
594
500
  async openAPIRefreshStatus(): Promise<void> {
595
501
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
596
502
  try {
597
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
598
- headers: this.platform.generateHeaders(),
599
- });
503
+ const { body, statusCode } = await this.platform.retryRequest(this.deviceMaxRetries, this.deviceDelayBetweenRetries,
504
+ `${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders() });
600
505
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
601
506
  const deviceStatus: any = await body.json();
602
507
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
603
508
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
604
509
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
605
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
510
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
606
511
  + `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();
512
+ this.openAPIparseStatus(deviceStatus);
614
513
  this.updateHomeKitCharacteristics();
615
514
  } else {
616
515
  this.statusCode(statusCode);
@@ -618,10 +517,35 @@ export class BlindTilt {
618
517
  }
619
518
  } catch (e: any) {
620
519
  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
- );
520
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
521
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
522
+ }
523
+ }
524
+
525
+ async registerWebhook(accessory: PlatformAccessory, device: device & devicesConfig) {
526
+ if (device.webhook) {
527
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is listening webhook.`);
528
+ this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
529
+ try {
530
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
531
+ const { slidePosition, battery, lightLevel } = context;
532
+ const { CurrentPosition } = this.WindowCovering;
533
+ const { BatteryLevel } = this.Battery;
534
+ const { CurrentAmbientLightLevel } = this.LightSensor ?? {};
535
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} (slidePosition, battery, lightLevel) = Webhook:(${slidePosition}, ${battery},`
536
+ + ` ${lightLevel}), current:(${CurrentPosition}, ${BatteryLevel}, ${CurrentAmbientLightLevel})`);
537
+ this.WindowCovering.CurrentPosition = slidePosition;
538
+ this.Battery.BatteryLevel = battery;
539
+ if (!device.blindTilt?.hide_lightsensor) {
540
+ this.LightSensor!.CurrentAmbientLightLevel = lightLevel;
541
+ }
542
+ this.updateHomeKitCharacteristics();
543
+ } catch (e: any) {
544
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
545
+ }
546
+ };
547
+ } else {
548
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is not listening webhook.`);
625
549
  }
626
550
  }
627
551
 
@@ -634,9 +558,8 @@ export class BlindTilt {
634
558
  await this.openAPIpushChanges();
635
559
  } else {
636
560
  await this.offlineOff();
637
- this.debugWarnLog(
638
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, pushChanges will not happen.`,
639
- );
561
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
562
+ + ` ${this.device.connectionType}, pushChanges will not happen.`);
640
563
  }
641
564
  // Refresh the status from the API
642
565
  interval(15000)
@@ -649,7 +572,7 @@ export class BlindTilt {
649
572
 
650
573
  async BLEpushChanges(): Promise<void> {
651
574
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
652
- if (this.TargetPosition !== this.CurrentPosition) {
575
+ if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition) {
653
576
  const switchbot = await this.platform.connectBLE();
654
577
  // Convert to BLE Address
655
578
  this.device.bleMac = this.device
@@ -657,33 +580,29 @@ export class BlindTilt {
657
580
  .join(':')
658
581
  .toLowerCase();
659
582
  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}`);
583
+ const { setPositionMode, Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
584
+ this.debugLog(`${this.accessory.displayName} Mode: ${Mode}`);
666
585
  if (switchbot !== false) {
667
586
  switchbot
668
587
  .discover({ model: 'c', quick: true, id: this.device.bleMac })
669
588
  .then(async (device_list: any) => {
670
- this.infoLog(`${this.accessory.displayName} Target Position: ${this.TargetPosition}`);
671
- return await this.retry({
672
- max: this.maxRetry(),
589
+ this.infoLog(`${this.accessory.displayName} Target Position: ${this.WindowCovering.TargetPosition}`);
590
+ return await this.retryBLE({
591
+ max: await this.maxRetryBLE(),
673
592
  fn: async () => {
674
- return await device_list[0].runToPos(100 - Number(this.TargetPosition), adjustedMode);
593
+ return await device_list[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), setPositionMode);
675
594
  },
676
595
  });
677
596
  })
678
597
  .then(() => {
679
598
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
599
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
600
+ + `Target Position: ${this.WindowCovering.TargetPosition} sent over BLE, sent successfully`);
680
601
  })
681
602
  .catch(async (e: any) => {
682
603
  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
- );
604
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
605
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
687
606
  await this.BLEPushConnection();
688
607
  });
689
608
  } else {
@@ -691,50 +610,35 @@ export class BlindTilt {
691
610
  await this.BLEPushConnection();
692
611
  }
693
612
  } 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;
613
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.`
614
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition ${this.WindowCovering.TargetPosition}`);
718
615
  }
719
616
  }
720
617
 
721
618
  async openAPIpushChanges(): Promise<void> {
722
619
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
723
620
  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}`);
621
+ this.mappingMode === BlindTiltMappingMode.UseTiltForDirection
622
+ && this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle;
623
+ if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition
624
+ || hasDifferentAndRelevantHorizontalTiltAngle || this.device.disableCaching) {
625
+ const [direction, position] = this.mapHomekitValuesToDeviceValues(Number(this.WindowCovering.TargetPosition),
626
+ Number(this.WindowCovering.TargetHorizontalTiltAngle));
627
+ const { Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
628
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
629
+ + ` Pushing ${this.WindowCovering.TargetPosition} (device = ${direction};${position})`);
630
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Mode: ${Mode}`);
729
631
  let bodyChange = '';
730
632
  if (position === 100) {
731
633
  bodyChange = JSON.stringify({
732
634
  command: 'fullyOpen',
635
+ parameter: 'default',
733
636
  commandType: 'command',
734
637
  });
735
638
  } else if (position === 0) {
736
639
  bodyChange = JSON.stringify({
737
640
  command: direction === 'up' ? 'closeUp' : 'closeDown',
641
+ parameter: 'default',
738
642
  commandType: 'command',
739
643
  });
740
644
  } else {
@@ -757,25 +661,24 @@ export class BlindTilt {
757
661
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
758
662
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
759
663
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
760
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
664
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
761
665
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
666
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
667
+ + `request to SwitchBot API, body: ${JSON.stringify(JSON.parse(bodyChange))} sent successfully`);
762
668
  } else {
763
669
  this.statusCode(statusCode);
764
670
  this.statusCode(deviceStatus.statusCode);
765
671
  }
766
672
  } catch (e: any) {
767
673
  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
- );
674
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
675
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
772
676
  }
773
677
  } 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
- );
678
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.`
679
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition ${this.WindowCovering.TargetPosition}`
680
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle},`
681
+ + ` TargetPosition ${this.WindowCovering.TargetHorizontalTiltAngle}`);
779
682
  }
780
683
  }
781
684
 
@@ -783,16 +686,16 @@ export class BlindTilt {
783
686
  * Handle requests to set the value of the "Target Horizontal Tilt" characteristic
784
687
  */
785
688
  async TargetHorizontalTiltAngleSet(value: CharacteristicValue): Promise<void> {
786
- if (this.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
689
+ if (this.WindowCovering.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
787
690
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetHorizontalTiltAngle: ${value}`);
788
691
  } else {
789
692
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetHorizontalTiltAngle: ${value}`);
790
693
  }
791
694
 
792
695
  //value = value < 0 ? -90 : 90;
793
- this.TargetHorizontalTiltAngle = value;
696
+ this.WindowCovering.TargetHorizontalTiltAngle = value;
794
697
  if (this.device.mqttURL) {
795
- this.mqttPublish('TargetHorizontalTiltAngle', this.TargetHorizontalTiltAngle);
698
+ this.mqttPublish('TargetHorizontalTiltAngle', this.WindowCovering.TargetHorizontalTiltAngle.toString());
796
699
  }
797
700
 
798
701
  this.startUpdatingBlindTiltIfNeeded();
@@ -802,15 +705,15 @@ export class BlindTilt {
802
705
  * Handle requests to set the value of the "Target Position" characteristic
803
706
  */
804
707
  async TargetPositionSet(value: CharacteristicValue): Promise<void> {
805
- if (this.TargetPosition === this.accessory.context.TargetPosition) {
708
+ if (this.WindowCovering.TargetPosition === this.accessory.context.TargetPosition) {
806
709
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetPosition: ${value}`);
807
710
  } else {
808
711
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
809
712
  }
810
713
 
811
- this.TargetPosition = value;
714
+ this.WindowCovering.TargetPosition = value;
812
715
  if (this.device.mqttURL) {
813
- this.mqttPublish('TargetPosition', this.TargetPosition);
716
+ this.mqttPublish('TargetPosition', this.WindowCovering.TargetPosition.toString());
814
717
  }
815
718
  this.startUpdatingBlindTiltIfNeeded();
816
719
  }
@@ -818,39 +721,37 @@ export class BlindTilt {
818
721
  async startUpdatingBlindTiltIfNeeded(): Promise<void> {
819
722
  await this.setMinMax();
820
723
  this.debugLog('setMinMax');
821
- if (this.TargetPosition > this.CurrentPosition || this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle) {
822
- this.PositionState = this.hap.Characteristic.PositionState.INCREASING;
724
+ if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
725
+ || this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle) {
726
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
823
727
  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;
728
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
729
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
730
+ } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
731
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
829
732
  this.setNewTarget = true;
830
- this.debugLog(
831
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
832
- );
733
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
734
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
833
735
  } else {
834
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
736
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
835
737
  this.setNewTarget = false;
836
- this.debugLog(
837
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
838
- );
738
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
739
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
839
740
  }
840
- this.windowCoveringService.setCharacteristic(this.hap.Characteristic.PositionState, this.PositionState);
841
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
741
+ this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.PositionState, this.WindowCovering.PositionState);
742
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
842
743
 
843
744
  /**
844
745
  * If Blind Tilt movement time is short, the moving flag from backend is always false.
845
746
  * The minimum time depends on the network control latency.
846
747
  */
847
748
  clearTimeout(this.setNewTargetTimer);
848
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.updateRate}`);
749
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.deviceUpdateRate}`);
849
750
  if (this.setNewTarget) {
850
751
  this.setNewTargetTimer = setTimeout(() => {
851
752
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} setNewTarget ${this.setNewTarget} timeout`);
852
753
  this.setNewTarget = false;
853
- }, this.updateRate * 1000);
754
+ }, this.deviceUpdateRate * 1000);
854
755
  }
855
756
  this.doBlindTiltUpdate.next();
856
757
  }
@@ -859,152 +760,105 @@ export class BlindTilt {
859
760
  await this.setMinMax();
860
761
  // CurrentHorizontalTiltAngle
861
762
  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}`);
763
+ if (this.WindowCovering.CurrentHorizontalTiltAngle === undefined || Number.isNaN(this.WindowCovering.CurrentHorizontalTiltAngle)) {
764
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
765
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
864
766
  } else {
865
767
  if (this.device.mqttURL) {
866
- this.mqttPublish('CurrentHorizontalTiltAngle', this.CurrentHorizontalTiltAngle);
768
+ this.mqttPublish('CurrentHorizontalTiltAngle', this.WindowCovering.CurrentHorizontalTiltAngle.toString());
867
769
  }
868
- this.accessory.context.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
869
- this.windowCoveringService.updateCharacteristic(
770
+ this.accessory.context.CurrentHorizontalTiltAngle = this.WindowCovering.CurrentHorizontalTiltAngle;
771
+ this.WindowCovering.Service.updateCharacteristic(
870
772
  this.hap.Characteristic.CurrentHorizontalTiltAngle,
871
- Number(this.CurrentHorizontalTiltAngle),
872
- );
773
+ Number(this.WindowCovering.CurrentHorizontalTiltAngle));
873
774
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}
874
- updateCharacteristic CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
775
+ updateCharacteristic CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
875
776
  }
876
777
  }
877
778
  // CurrentPosition
878
- if (this.CurrentPosition === undefined || Number.isNaN(this.CurrentPosition)) {
879
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
779
+ if (this.WindowCovering.CurrentPosition === undefined || Number.isNaN(this.WindowCovering.CurrentPosition)) {
780
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
880
781
  } else {
881
782
  if (this.device.mqttURL) {
882
- this.mqttPublish('CurrentPosition', this.CurrentPosition);
783
+ this.mqttPublish('CurrentPosition', this.WindowCovering.CurrentPosition.toString());
883
784
  }
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}`);
785
+ this.accessory.context.CurrentPosition = this.WindowCovering.CurrentPosition;
786
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, Number(this.WindowCovering.CurrentPosition));
787
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
788
+ + ` updateCharacteristic CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
887
789
  }
888
790
  // PositionState
889
- if (this.PositionState === undefined) {
890
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.PositionState}`);
791
+ if (this.WindowCovering.PositionState === undefined) {
792
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.WindowCovering.PositionState}`);
891
793
  } else {
892
794
  if (this.device.mqttURL) {
893
- this.mqttPublish('PositionState', this.PositionState);
795
+ this.mqttPublish('PositionState', this.WindowCovering.PositionState.toString());
894
796
  }
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}`);
797
+ this.accessory.context.PositionState = this.WindowCovering.PositionState;
798
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, Number(this.WindowCovering.PositionState));
799
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
800
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
898
801
  }
899
802
  // TargetPosition
900
- if (this.TargetPosition === undefined || Number.isNaN(this.TargetPosition)) {
901
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.TargetPosition}`);
803
+ if (this.WindowCovering.TargetPosition === undefined || Number.isNaN(this.WindowCovering.TargetPosition)) {
804
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.WindowCovering.TargetPosition}`);
902
805
  } else {
903
806
  if (this.device.mqttURL) {
904
- this.mqttPublish('TargetPosition', this.TargetPosition);
807
+ this.mqttPublish('TargetPosition', this.WindowCovering.TargetPosition.toString());
905
808
  }
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}`);
809
+ this.accessory.context.TargetPosition = this.WindowCovering.TargetPosition;
810
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, Number(this.WindowCovering.TargetPosition));
811
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
812
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}`);
909
813
  }
910
814
  // CurrentAmbientLightLevel
911
815
  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}`);
816
+ if (this.LightSensor!.CurrentAmbientLightLevel === undefined || Number.isNaN(this.LightSensor!.CurrentAmbientLightLevel)) {
817
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
818
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
914
819
  } else {
915
820
  if (this.device.mqttURL) {
916
- this.mqttPublish('CurrentAmbientLightLevel', this.CurrentAmbientLightLevel);
821
+ this.mqttPublish('CurrentAmbientLightLevel', this.LightSensor!.CurrentAmbientLightLevel.toString());
917
822
  }
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
- );
823
+ this.accessory.context.CurrentAmbientLightLevel = this.LightSensor!.CurrentAmbientLightLevel;
824
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.LightSensor!.CurrentAmbientLightLevel);
825
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
826
+ + ` updateCharacteristic CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
924
827
  }
925
828
  }
926
829
  // BatteryLevel
927
- if (this.BatteryLevel === undefined) {
928
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
830
+ if (this.Battery.BatteryLevel === undefined) {
831
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
929
832
  } else {
930
833
  if (this.device.mqttURL) {
931
- this.mqttPublish('BatteryLevel', this.BatteryLevel);
834
+ this.mqttPublish('BatteryLevel', this.Battery.BatteryLevel.toString());
932
835
  }
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}`);
836
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
837
+ this.Battery?.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
838
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
936
839
  }
937
840
  // StatusLowBattery
938
- if (this.StatusLowBattery === undefined) {
939
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
841
+ if (this.Battery.StatusLowBattery === undefined) {
842
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
940
843
  } else {
941
844
  if (this.device.mqttURL) {
942
- this.mqttPublish('StatusLowBattery', this.StatusLowBattery);
943
- }
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}`);
947
- }
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}`);
845
+ this.mqttPublish('StatusLowBattery', this.Battery.StatusLowBattery.toString());
979
846
  }
847
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
848
+ this.Battery?.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
849
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
850
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
980
851
  }
981
- }
982
-
983
- async stopScanning(switchbot: any) {
984
- switchbot.stopScan();
985
- if (this.BLE_IsConnected) {
986
- await this.BLEparseStatus();
987
- await this.updateHomeKitCharacteristics();
852
+ if (this.Battery.ChargingState === undefined) {
853
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ChargingState: ${this.Battery.ChargingState}`);
988
854
  } 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
- })();
855
+ if (this.device.mqttURL) {
856
+ this.mqttPublish('ChargingState', this.Battery.ChargingState.toString());
857
+ }
858
+ this.accessory.context.ChargingState = this.Battery.ChargingState;
859
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, this.Battery.ChargingState);
860
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
861
+ + ` ChargingState: ${this.Battery.ChargingState}`);
1008
862
  }
1009
863
  }
1010
864
 
@@ -1024,218 +878,74 @@ export class BlindTilt {
1024
878
  }
1025
879
  }
1026
880
 
1027
- async SilentPerformance() {
1028
- if (Number(this.TargetPosition) > 50) {
881
+ async setPerformance() {
882
+ let setPositionMode: number;
883
+ let Mode: string;
884
+ if (Number(this.WindowCovering.TargetPosition) > 50) {
1029
885
  if (this.device.blindTilt?.setOpenMode === '1') {
1030
- this.setPositionMode = 1;
1031
- this.Mode = 'Silent Mode';
886
+ setPositionMode = 1;
887
+ Mode = 'Silent Mode';
888
+ } else if (this.device.blindTilt?.setOpenMode === '0') {
889
+ setPositionMode = 0;
890
+ Mode = 'Performance Mode';
1032
891
  } else {
1033
- this.setPositionMode = 0;
1034
- this.Mode = 'Performance Mode';
892
+ setPositionMode = 0;
893
+ Mode = 'Default Mode';
1035
894
  }
1036
895
  } else {
1037
896
  if (this.device.blindTilt?.setCloseMode === '1') {
1038
- this.setPositionMode = 1;
1039
- this.Mode = 'Silent Mode';
897
+ setPositionMode = 1;
898
+ Mode = 'Silent Mode';
899
+ } else if (this.device.blindTilt?.setOpenMode === '0') {
900
+ setPositionMode = 0;
901
+ Mode = 'Performance Mode';
1040
902
  } else {
1041
- this.setPositionMode = 0;
1042
- this.Mode = 'Performance Mode';
903
+ setPositionMode = 0;
904
+ Mode = 'Default Mode';
1043
905
  }
1044
906
  }
907
+ return { setPositionMode, Mode };
1045
908
  }
1046
909
 
1047
910
  async setMinMax(): Promise<void> {
1048
911
  if (this.device.blindTilt?.set_min) {
1049
- if (Number(this.CurrentPosition) <= this.device.blindTilt?.set_min) {
1050
- this.CurrentPosition = 0;
912
+ if (Number(this.WindowCovering.CurrentPosition) <= this.device.blindTilt?.set_min) {
913
+ this.WindowCovering.CurrentPosition = 0;
1051
914
  }
1052
915
  }
1053
916
  if (this.device.blindTilt?.set_max) {
1054
- if (Number(this.CurrentPosition) >= this.device.blindTilt?.set_max) {
1055
- this.CurrentPosition = 100;
917
+ if (Number(this.WindowCovering.CurrentPosition) >= this.device.blindTilt?.set_max) {
918
+ this.WindowCovering.CurrentPosition = 100;
1056
919
  }
1057
920
  }
1058
921
 
1059
922
  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
- );
923
+ this.WindowCovering.CurrentHorizontalTiltAngle = Number(this.WindowCovering.CurrentHorizontalTiltAngle) < 0 ? -90 : 90;
1194
924
  }
1195
925
  }
1196
926
 
1197
927
  async offlineOff(): Promise<void> {
1198
928
  if (this.device.offline) {
1199
- await this.deviceContext();
1200
- await this.updateHomeKitCharacteristics();
929
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
930
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
931
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
932
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle, 90);
933
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle, 90);
1201
934
  }
1202
935
  }
1203
936
 
1204
937
  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;
938
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
939
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e);
940
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
941
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle, e);
942
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle, e);
943
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
944
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
945
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, e);
946
+ if (!this.device.blindTilt?.hide_lightsensor) {
947
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, e);
948
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.StatusActive, e);
1239
949
  }
1240
950
  }
1241
951
 
@@ -1358,130 +1068,4 @@ export class BlindTilt {
1358
1068
  }
1359
1069
  }
1360
1070
  }
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
1071
  }