@switchbot/homebridge-switchbot 3.5.0-beta.7 → 3.5.0-beta.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/.vscode/settings.json +4 -1
  2. package/CHANGELOG.md +4 -1
  3. package/config.schema.json +120 -17
  4. package/dist/device/blindtilt.d.ts +23 -96
  5. package/dist/device/blindtilt.d.ts.map +1 -1
  6. package/dist/device/blindtilt.js +425 -778
  7. package/dist/device/blindtilt.js.map +1 -1
  8. package/dist/device/bot.d.ts +26 -72
  9. package/dist/device/bot.d.ts.map +1 -1
  10. package/dist/device/bot.js +803 -837
  11. package/dist/device/bot.js.map +1 -1
  12. package/dist/device/ceilinglight.d.ts +14 -68
  13. package/dist/device/ceilinglight.d.ts.map +1 -1
  14. package/dist/device/ceilinglight.js +241 -606
  15. package/dist/device/ceilinglight.js.map +1 -1
  16. package/dist/device/colorbulb.d.ts +14 -75
  17. package/dist/device/colorbulb.d.ts.map +1 -1
  18. package/dist/device/colorbulb.js +283 -658
  19. package/dist/device/colorbulb.js.map +1 -1
  20. package/dist/device/contact.d.ts +15 -66
  21. package/dist/device/contact.d.ts.map +1 -1
  22. package/dist/device/contact.js +254 -545
  23. package/dist/device/contact.js.map +1 -1
  24. package/dist/device/curtain.d.ts +19 -88
  25. package/dist/device/curtain.d.ts.map +1 -1
  26. package/dist/device/curtain.js +412 -806
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/device.d.ts +59 -0
  29. package/dist/device/device.d.ts.map +1 -0
  30. package/dist/device/device.js +711 -0
  31. package/dist/device/device.js.map +1 -0
  32. package/dist/device/fan.d.ts +51 -0
  33. package/dist/device/fan.d.ts.map +1 -0
  34. package/dist/device/fan.js +540 -0
  35. package/dist/device/fan.js.map +1 -0
  36. package/dist/device/hub.d.ts +16 -60
  37. package/dist/device/hub.d.ts.map +1 -1
  38. package/dist/device/hub.js +261 -616
  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 +240 -594
  43. package/dist/device/humidifier.js.map +1 -1
  44. package/dist/device/iosensor.d.ts +11 -64
  45. package/dist/device/iosensor.d.ts.map +1 -1
  46. package/dist/device/iosensor.js +196 -600
  47. package/dist/device/iosensor.js.map +1 -1
  48. package/dist/device/lightstrip.d.ts +11 -69
  49. package/dist/device/lightstrip.d.ts.map +1 -1
  50. package/dist/device/lightstrip.js +281 -586
  51. package/dist/device/lightstrip.js.map +1 -1
  52. package/dist/device/lock.d.ts +16 -63
  53. package/dist/device/lock.d.ts.map +1 -1
  54. package/dist/device/lock.js +252 -560
  55. package/dist/device/lock.js.map +1 -1
  56. package/dist/device/meter.d.ts +14 -64
  57. package/dist/device/meter.d.ts.map +1 -1
  58. package/dist/device/meter.js +191 -593
  59. package/dist/device/meter.js.map +1 -1
  60. package/dist/device/meterplus.d.ts +14 -65
  61. package/dist/device/meterplus.d.ts.map +1 -1
  62. package/dist/device/meterplus.js +180 -593
  63. package/dist/device/meterplus.js.map +1 -1
  64. package/dist/device/motion.d.ts +13 -69
  65. package/dist/device/motion.d.ts.map +1 -1
  66. package/dist/device/motion.js +188 -532
  67. package/dist/device/motion.js.map +1 -1
  68. package/dist/device/plug.d.ts +9 -57
  69. package/dist/device/plug.d.ts.map +1 -1
  70. package/dist/device/plug.js +96 -458
  71. package/dist/device/plug.js.map +1 -1
  72. package/dist/device/robotvacuumcleaner.d.ts +12 -63
  73. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  74. package/dist/device/robotvacuumcleaner.js +202 -521
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +10 -63
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +146 -475
  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 +324 -452
  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 +93 -307
  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 +39 -281
  98. package/dist/irdevice/camera.js.map +1 -1
  99. package/dist/irdevice/fan.d.ts +10 -43
  100. package/dist/irdevice/fan.d.ts.map +1 -1
  101. package/dist/irdevice/fan.js +113 -341
  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 +330 -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 +87 -335
  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 +19 -6
  128. package/dist/platform.d.ts.map +1 -1
  129. package/dist/platform.js +310 -172
  130. package/dist/platform.js.map +1 -1
  131. package/dist/settings.d.ts +62 -19
  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 +19 -15
  141. package/src/custom.d.ts +2 -1
  142. package/src/device/blindtilt.ts +462 -817
  143. package/src/device/bot.ts +862 -931
  144. package/src/device/ceilinglight.ts +259 -633
  145. package/src/device/colorbulb.ts +300 -688
  146. package/src/device/contact.ts +288 -571
  147. package/src/device/curtain.ts +441 -838
  148. package/src/device/device.ts +734 -0
  149. package/src/device/fan.ts +596 -0
  150. package/src/device/hub.ts +299 -645
  151. package/src/device/humidifier.ts +274 -647
  152. package/src/device/iosensor.ts +233 -626
  153. package/src/device/lightstrip.ts +309 -620
  154. package/src/device/lock.ts +292 -601
  155. package/src/device/meter.ts +228 -619
  156. package/src/device/meterplus.ts +216 -619
  157. package/src/device/motion.ts +218 -559
  158. package/src/device/plug.ts +111 -490
  159. package/src/device/robotvacuumcleaner.ts +228 -550
  160. package/src/device/waterdetector.ts +169 -501
  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 +350 -477
  165. package/src/irdevice/airpurifier.ts +120 -330
  166. package/src/irdevice/camera.ts +53 -301
  167. package/src/irdevice/fan.ts +130 -360
  168. package/src/irdevice/irdevice.ts +346 -0
  169. package/src/irdevice/light.ts +157 -412
  170. package/src/irdevice/other.ts +507 -648
  171. package/src/irdevice/tv.ts +117 -367
  172. package/src/irdevice/vacuumcleaner.ts +59 -311
  173. package/src/irdevice/waterheater.ts +61 -320
  174. package/src/platform.ts +355 -219
  175. package/src/settings.ts +116 -611
  176. package/src/utils.ts +642 -1
  177. 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: Number(this.minStep(device)),
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: Number(this.minStep(device)),
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,21 +189,23 @@ 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.`);
192
+ if (device.webhook) {
193
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is listening webhook.`);
215
194
  this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
216
195
  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();*/
196
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
197
+ const { slidePosition, battery, lightLevel } = context;
198
+ const { CurrentPosition } = this.WindowCovering;
199
+ const { BatteryLevel } = this.Battery;
200
+ const { CurrentAmbientLightLevel } = this.LightSensor ?? {};
201
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} (slidePosition, battery, lightLevel) = `
202
+ + `Webhook:(${slidePosition}, ${battery}, ${lightLevel}), current:(${CurrentPosition}, ${BatteryLevel}, ${CurrentAmbientLightLevel})`);
203
+ this.WindowCovering.CurrentPosition = slidePosition;
204
+ this.Battery.BatteryLevel = battery;
205
+ if (!device.blindTilt?.hide_lightsensor) {
206
+ this.LightSensor!.CurrentAmbientLightLevel = lightLevel;
207
+ }
208
+ this.updateHomeKitCharacteristics();
228
209
  } catch (e: any) {
229
210
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
230
211
  + `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
@@ -233,13 +214,14 @@ export class BlindTilt {
233
214
  }
234
215
 
235
216
  // update slide progress
236
- interval(this.updateRate * 1000)
217
+ interval(this.deviceUpdateRate * 1000)
237
218
  //.pipe(skipWhile(() => this.blindTiltUpdateInProgress))
238
219
  .subscribe(async () => {
239
- if (this.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
220
+ if (this.WindowCovering.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
240
221
  return;
241
222
  }
242
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Refresh Status When Moving, PositionState: ${this.PositionState}`);
223
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} Refresh Status When Moving,`
224
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
243
225
  await this.refreshStatus();
244
226
  });
245
227
 
@@ -257,228 +239,247 @@ export class BlindTilt {
257
239
  await this.pushChanges();
258
240
  } catch (e: any) {
259
241
  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
- );
242
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed pushChanges with ${device.connectionType} Connection,` +
243
+ ` Error Message: ${JSON.stringify(e.message)}`);
264
244
  }
265
245
  this.blindTiltUpdateInProgress = false;
266
246
  });
267
247
  }
268
248
 
269
249
  /**
270
- * Parse the device status from the SwitchBot api
250
+ * Parse the device status from the SwitchBotBLE API
271
251
  */
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> {
252
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
288
253
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
289
254
  // CurrentPosition
290
- this.CurrentPosition = 100 - Number(this.BLE_CurrentPosition);
255
+ this.WindowCovering.CurrentPosition = 100 - Number(serviceData.position);
291
256
  await this.setMinMax();
292
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.CurrentPosition}`);
257
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.WindowCovering.CurrentPosition}`);
293
258
  if (this.setNewTarget) {
294
259
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
295
260
  }
296
261
 
297
- if (this.setNewTarget && this.BLE_InMotion) {
262
+ if (this.setNewTarget && serviceData.inMotion) {
298
263
  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}`);
264
+ if (Number(this.WindowCovering.TargetPosition) > this.WindowCovering.CurrentPosition) {
265
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
266
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
267
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
268
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} INCREASING`
269
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
270
+ } else if (Number(this.WindowCovering.TargetPosition) < this.WindowCovering.CurrentPosition) {
271
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
272
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
273
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
274
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} DECREASING`
275
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
309
276
  } 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}`);
277
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} Standby2,`
278
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
279
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
280
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
281
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} STOPPED`
282
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
314
283
  }
315
284
  } 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;
285
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
286
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
287
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
319
288
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
320
289
  }
321
- this.debugLog(
322
- `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
323
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
324
- );
290
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition},`
291
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`);
325
292
 
326
293
  if (!this.device.blindTilt?.hide_lightsensor) {
327
- this.set_minLux = this.minLux();
328
- this.set_maxLux = this.maxLux();
329
- this.spaceBetweenLevels = 9;
294
+ const set_minLux = await this.minLux();
295
+ const set_maxLux = await this.maxLux();
296
+ const spaceBetweenLevels = 9;
297
+
298
+ if (this.LightSensor?.CurrentAmbientLightLevel === 0) {
299
+ this.LightSensor!.CurrentAmbientLightLevel = 0.0001;
300
+ }
330
301
 
331
302
  // Brightness
332
- switch (this.BLE_CurrentAmbientLightLevel) {
303
+ switch (serviceData.lightLevel) {
333
304
  case 1:
334
- this.CurrentAmbientLightLevel = this.set_minLux;
335
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
305
+ this.LightSensor!.CurrentAmbientLightLevel = set_minLux;
306
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
336
307
  break;
337
308
  case 2:
338
- this.CurrentAmbientLightLevel = (this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels;
309
+ this.LightSensor!.CurrentAmbientLightLevel = (set_maxLux - set_minLux) / spaceBetweenLevels;
339
310
  this.debugLog(
340
- `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel},` +
341
- ` Calculation: ${(this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels}`,
311
+ `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel},` +
312
+ ` Calculation: ${(set_maxLux - set_minLux) / spaceBetweenLevels}`,
342
313
  );
343
314
  break;
344
315
  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}`);
316
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 2;
317
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
347
318
  break;
348
319
  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}`);
320
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 3;
321
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
351
322
  break;
352
323
  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}`);
324
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 4;
325
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
355
326
  break;
356
327
  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}`);
328
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 5;
329
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
359
330
  break;
360
331
  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}`);
332
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 6;
333
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
363
334
  break;
364
335
  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}`);
336
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 7;
337
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
367
338
  break;
368
339
  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}`);
340
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 8;
341
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
371
342
  break;
372
343
  case 10:
373
344
  default:
374
- this.CurrentAmbientLightLevel = this.set_maxLux;
345
+ this.LightSensor!.CurrentAmbientLightLevel = set_maxLux;
375
346
  this.debugLog();
376
347
  }
377
348
  this.debugLog(
378
- `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel},` +
379
- ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
349
+ `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel},` +
350
+ ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`,
380
351
  );
381
352
  }
382
353
  // Battery
383
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
384
- if (this.BatteryLevel < 10) {
385
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
354
+ this.Battery.BatteryLevel = Number(serviceData.battery);
355
+ if (this.Battery.BatteryLevel < 10) {
356
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
386
357
  } else {
387
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
358
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
388
359
  }
389
360
  this.debugLog(
390
- `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` + ` StatusLowBattery: ${this.StatusLowBattery}`,
361
+ `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
362
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`,
391
363
  );
392
364
  }
393
365
 
394
- async openAPIparseStatus(): Promise<void> {
366
+
367
+ /**
368
+ * Parse the device status from the SwitchBot OpenAPI
369
+ */
370
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
395
371
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
396
372
 
397
- const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(this.OpenAPI_CurrentPosition),
398
- String(this.OpenAPI_Direction));
399
- this.debugLog(` device: ${this.OpenAPI_CurrentPosition} => HK: ${homekitPosition}`);
373
+ const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(deviceStatus.body.slidePosition),
374
+ String(deviceStatus.body.direction));
375
+ this.debugLog(` device: ${deviceStatus.body.slidePosition} => HK: ${homekitPosition}`);
400
376
 
401
- this.CurrentPosition = homekitPosition;
377
+ this.WindowCovering!.CurrentPosition = homekitPosition;
402
378
  // CurrentPosition
403
379
  await this.setMinMax();
404
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
380
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
405
381
 
406
382
  if (homekitTiltAngle) {
407
- this.CurrentHorizontalTiltAngle = homekitTiltAngle!;
408
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
383
+ this.WindowCovering.CurrentHorizontalTiltAngle = homekitTiltAngle!;
384
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
385
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
409
386
  }
410
387
 
411
388
  if (this.setNewTarget) {
412
389
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
413
390
  }
414
391
 
415
- if (this.setNewTarget && this.OpenAPI_InMotion) {
392
+ if (this.setNewTarget && deviceStatus.body.moving) {
416
393
  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}`);
394
+ if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
395
+ || (homekitTiltAngle && this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle)) {
396
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition} `);
397
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
398
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
399
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} INCREASING`
400
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
401
+ } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
402
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition} `);
403
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
404
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
405
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} DECREASING`
406
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
427
407
  } else {
428
408
  this.debugLog(
429
- `${this.device.deviceType}: ${this.CurrentPosition} Standby because reached position,` + ` CurrentPosition: ${this.CurrentPosition}`,
409
+ `${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} Standby because reached position,`
410
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
430
411
  );
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}`);
412
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
413
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
414
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} STOPPED`
415
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
434
416
  }
435
417
  } else {
436
418
  this.debugLog(
437
- `${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,` + ` CurrentPosition: ${this.CurrentPosition}`,
419
+ `${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,`
420
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
438
421
  );
439
- this.TargetPosition = this.CurrentPosition;
422
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
440
423
  if (homekitTiltAngle) {
441
- this.TargetHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
424
+ this.WindowCovering.TargetHorizontalTiltAngle = this.WindowCovering.CurrentHorizontalTiltAngle;
442
425
  }
443
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
426
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
444
427
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
445
428
  }
446
429
  this.debugLog(
447
- `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
448
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
430
+ `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition},` +
431
+ ` TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`,
449
432
  );
450
433
 
451
434
  if (!this.device.blindTilt?.hide_lightsensor) {
452
- this.set_minLux = this.minLux();
453
- this.set_maxLux = this.maxLux();
435
+ const set_minLux = await this.minLux();
436
+ const set_maxLux = await this.maxLux();
454
437
  // Brightness
455
- switch (this.OpenAPI_CurrentAmbientLightLevel) {
438
+ switch (deviceStatus.body.brightness) {
456
439
  case 'dim':
457
- this.CurrentAmbientLightLevel = this.set_minLux;
440
+ this.LightSensor!.CurrentAmbientLightLevel = set_minLux;
458
441
  break;
459
442
  case 'bright':
460
443
  default:
461
- this.CurrentAmbientLightLevel = this.set_maxLux;
444
+ this.LightSensor!.CurrentAmbientLightLevel = set_maxLux;
462
445
  }
463
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
446
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
447
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
464
448
  }
465
449
 
466
450
  // BatteryLevel
467
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
468
- if (this.BatteryLevel < 10) {
469
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
451
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
452
+ if (this.Battery.BatteryLevel < 10) {
453
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
470
454
  } else {
471
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
472
- }
473
- if (Number.isNaN(this.BatteryLevel)) {
474
- this.BatteryLevel = 100;
455
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
456
+ }
457
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
458
+ this.Battery.BatteryLevel = 100;
459
+ }
460
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
461
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
462
+
463
+ // Firmware Version
464
+ const version = deviceStatus.body.version?.toString();
465
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
466
+ let deviceVersion: string;
467
+ if (version?.includes('.') === false) {
468
+ const replace = version?.replace(/^V|-.*$/g, '');
469
+ const match = replace?.match(/.{1,1}/g);
470
+ const blindTiltVersion = match?.join('.') ?? '0.0.0';
471
+ deviceVersion = blindTiltVersion;
472
+ } else {
473
+ deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
475
474
  }
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;
475
+ this.accessory
476
+ .getService(this.hap.Service.AccessoryInformation)!
477
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
478
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
479
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
480
+ .updateValue(deviceVersion);
481
+ this.accessory.context.deviceVersion = deviceVersion;
482
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
482
483
  }
483
484
 
484
485
  async refreshStatus(): Promise<void> {
@@ -510,21 +511,13 @@ export class BlindTilt {
510
511
  // Start to monitor advertisement packets
511
512
  (async () => {
512
513
  // Start to monitor advertisement packets
513
- await switchbot.startScan({
514
- model: 'x',
515
- id: this.device.bleMac,
516
- });
514
+ await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
517
515
  // Set an event handler
518
516
  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') {
517
+ if (this.device.bleMac === ad.address && ad.model === this.device.bleModel) {
518
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
519
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
522
520
  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
521
  } else {
529
522
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
530
523
  }
@@ -534,83 +527,27 @@ export class BlindTilt {
534
527
  // Stop to monitor
535
528
  await switchbot.stopScan();
536
529
  // Update HomeKit
537
- await this.BLEparseStatus();
530
+ await this.BLEparseStatus(switchbot.onadvertisement.serviceData);
538
531
  await this.updateHomeKitCharacteristics();
539
532
  })();
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 {
533
+ if (switchbot === undefined) {
590
534
  await this.BLERefreshConnection(switchbot);
591
- }*/
535
+ }
592
536
  }
593
537
 
594
538
  async openAPIRefreshStatus(): Promise<void> {
595
539
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
596
540
  try {
597
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
598
- headers: this.platform.generateHeaders(),
599
- });
541
+ const { body, statusCode } = await this.platform.retryRequest(this.deviceMaxRetries, this.deviceDelayBetweenRetries,
542
+ `${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders() });
600
543
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
601
544
  const deviceStatus: any = await body.json();
602
545
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
603
546
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
604
547
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
605
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
548
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
606
549
  + `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();
550
+ this.openAPIparseStatus(deviceStatus);
614
551
  this.updateHomeKitCharacteristics();
615
552
  } else {
616
553
  this.statusCode(statusCode);
@@ -649,7 +586,7 @@ export class BlindTilt {
649
586
 
650
587
  async BLEpushChanges(): Promise<void> {
651
588
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
652
- if (this.TargetPosition !== this.CurrentPosition) {
589
+ if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition) {
653
590
  const switchbot = await this.platform.connectBLE();
654
591
  // Convert to BLE Address
655
592
  this.device.bleMac = this.device
@@ -657,26 +594,24 @@ export class BlindTilt {
657
594
  .join(':')
658
595
  .toLowerCase();
659
596
  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}`);
597
+ const { setPositionMode, Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
598
+ this.debugLog(`${this.accessory.displayName} Mode: ${Mode}`);
666
599
  if (switchbot !== false) {
667
600
  switchbot
668
601
  .discover({ model: 'c', quick: true, id: this.device.bleMac })
669
602
  .then(async (device_list: any) => {
670
- this.infoLog(`${this.accessory.displayName} Target Position: ${this.TargetPosition}`);
671
- return await this.retry({
672
- max: this.maxRetry(),
603
+ this.infoLog(`${this.accessory.displayName} Target Position: ${this.WindowCovering.TargetPosition}`);
604
+ return await this.retryBLE({
605
+ max: await this.maxRetryBLE(),
673
606
  fn: async () => {
674
- return await device_list[0].runToPos(100 - Number(this.TargetPosition), adjustedMode);
607
+ return await device_list[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), setPositionMode);
675
608
  },
676
609
  });
677
610
  })
678
611
  .then(() => {
679
612
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
613
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
614
+ + `Target Position: ${this.WindowCovering.TargetPosition} sent over BLE, sent successfully`);
680
615
  })
681
616
  .catch(async (e: any) => {
682
617
  this.apiError(e);
@@ -693,48 +628,35 @@ export class BlindTilt {
693
628
  } else {
694
629
  this.debugLog(
695
630
  `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` +
696
- ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
631
+ ` CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition ${this.WindowCovering.TargetPosition}`,
697
632
  );
698
633
  }
699
634
  }
700
635
 
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;
718
- }
719
- }
720
-
721
636
  async openAPIpushChanges(): Promise<void> {
722
637
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
723
638
  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}`);
639
+ this.mappingMode === BlindTiltMappingMode.UseTiltForDirection
640
+ && this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle;
641
+ if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition
642
+ || hasDifferentAndRelevantHorizontalTiltAngle || this.device.disableCaching) {
643
+ const [direction, position] = this.mapHomekitValuesToDeviceValues(Number(this.WindowCovering.TargetPosition),
644
+ Number(this.WindowCovering.TargetHorizontalTiltAngle));
645
+ const { Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
646
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
647
+ + ` Pushing ${this.WindowCovering.TargetPosition} (device = ${direction};${position})`);
648
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Mode: ${Mode}`);
729
649
  let bodyChange = '';
730
650
  if (position === 100) {
731
651
  bodyChange = JSON.stringify({
732
652
  command: 'fullyOpen',
653
+ parameter: 'default',
733
654
  commandType: 'command',
734
655
  });
735
656
  } else if (position === 0) {
736
657
  bodyChange = JSON.stringify({
737
658
  command: direction === 'up' ? 'closeUp' : 'closeDown',
659
+ parameter: 'default',
738
660
  commandType: 'command',
739
661
  });
740
662
  } else {
@@ -757,8 +679,10 @@ export class BlindTilt {
757
679
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
758
680
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
759
681
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
760
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
682
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
761
683
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
684
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
685
+ + `request to SwitchBot API, body: ${JSON.stringify(JSON.parse(bodyChange))} sent successfully`);
762
686
  } else {
763
687
  this.statusCode(statusCode);
764
688
  this.statusCode(deviceStatus.statusCode);
@@ -766,15 +690,16 @@ export class BlindTilt {
766
690
  } catch (e: any) {
767
691
  this.apiError(e);
768
692
  this.errorLog(
769
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` +
770
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
693
+ `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
694
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
771
695
  );
772
696
  }
773
697
  } else {
774
698
  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}`,
699
+ `${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.`
700
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition ${this.WindowCovering.TargetPosition}`
701
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle},`
702
+ + ` TargetPosition ${this.WindowCovering.TargetHorizontalTiltAngle}`,
778
703
  );
779
704
  }
780
705
  }
@@ -783,16 +708,16 @@ export class BlindTilt {
783
708
  * Handle requests to set the value of the "Target Horizontal Tilt" characteristic
784
709
  */
785
710
  async TargetHorizontalTiltAngleSet(value: CharacteristicValue): Promise<void> {
786
- if (this.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
711
+ if (this.WindowCovering.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
787
712
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetHorizontalTiltAngle: ${value}`);
788
713
  } else {
789
714
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetHorizontalTiltAngle: ${value}`);
790
715
  }
791
716
 
792
717
  //value = value < 0 ? -90 : 90;
793
- this.TargetHorizontalTiltAngle = value;
718
+ this.WindowCovering.TargetHorizontalTiltAngle = value;
794
719
  if (this.device.mqttURL) {
795
- this.mqttPublish('TargetHorizontalTiltAngle', this.TargetHorizontalTiltAngle);
720
+ this.mqttPublish('TargetHorizontalTiltAngle', this.WindowCovering.TargetHorizontalTiltAngle.toString());
796
721
  }
797
722
 
798
723
  this.startUpdatingBlindTiltIfNeeded();
@@ -802,15 +727,15 @@ export class BlindTilt {
802
727
  * Handle requests to set the value of the "Target Position" characteristic
803
728
  */
804
729
  async TargetPositionSet(value: CharacteristicValue): Promise<void> {
805
- if (this.TargetPosition === this.accessory.context.TargetPosition) {
730
+ if (this.WindowCovering.TargetPosition === this.accessory.context.TargetPosition) {
806
731
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetPosition: ${value}`);
807
732
  } else {
808
733
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
809
734
  }
810
735
 
811
- this.TargetPosition = value;
736
+ this.WindowCovering.TargetPosition = value;
812
737
  if (this.device.mqttURL) {
813
- this.mqttPublish('TargetPosition', this.TargetPosition);
738
+ this.mqttPublish('TargetPosition', this.WindowCovering.TargetPosition.toString());
814
739
  }
815
740
  this.startUpdatingBlindTiltIfNeeded();
816
741
  }
@@ -818,39 +743,43 @@ export class BlindTilt {
818
743
  async startUpdatingBlindTiltIfNeeded(): Promise<void> {
819
744
  await this.setMinMax();
820
745
  this.debugLog('setMinMax');
821
- if (this.TargetPosition > this.CurrentPosition || this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle) {
822
- this.PositionState = this.hap.Characteristic.PositionState.INCREASING;
746
+ if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
747
+ || this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle) {
748
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
823
749
  this.setNewTarget = true;
824
750
  this.debugLog(
825
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
751
+ `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
752
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
826
753
  );
827
- } else if (this.TargetPosition < this.CurrentPosition) {
828
- this.PositionState = this.hap.Characteristic.PositionState.DECREASING;
754
+ } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
755
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
829
756
  this.setNewTarget = true;
830
757
  this.debugLog(
831
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
758
+ `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
759
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
832
760
  );
833
761
  } else {
834
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
762
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
835
763
  this.setNewTarget = false;
836
764
  this.debugLog(
837
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
765
+ `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
766
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
838
767
  );
839
768
  }
840
- this.windowCoveringService.setCharacteristic(this.hap.Characteristic.PositionState, this.PositionState);
841
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
769
+ this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.PositionState, this.WindowCovering.PositionState);
770
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
842
771
 
843
772
  /**
844
773
  * If Blind Tilt movement time is short, the moving flag from backend is always false.
845
774
  * The minimum time depends on the network control latency.
846
775
  */
847
776
  clearTimeout(this.setNewTargetTimer);
848
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.updateRate}`);
777
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.deviceUpdateRate}`);
849
778
  if (this.setNewTarget) {
850
779
  this.setNewTargetTimer = setTimeout(() => {
851
780
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} setNewTarget ${this.setNewTarget} timeout`);
852
781
  this.setNewTarget = false;
853
- }, this.updateRate * 1000);
782
+ }, this.deviceUpdateRate * 1000);
854
783
  }
855
784
  this.doBlindTiltUpdate.next();
856
785
  }
@@ -859,152 +788,108 @@ export class BlindTilt {
859
788
  await this.setMinMax();
860
789
  // CurrentHorizontalTiltAngle
861
790
  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}`);
791
+ if (this.WindowCovering.CurrentHorizontalTiltAngle === undefined || Number.isNaN(this.WindowCovering.CurrentHorizontalTiltAngle)) {
792
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
793
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
864
794
  } else {
865
795
  if (this.device.mqttURL) {
866
- this.mqttPublish('CurrentHorizontalTiltAngle', this.CurrentHorizontalTiltAngle);
796
+ this.mqttPublish('CurrentHorizontalTiltAngle', this.WindowCovering.CurrentHorizontalTiltAngle.toString());
867
797
  }
868
- this.accessory.context.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
869
- this.windowCoveringService.updateCharacteristic(
798
+ this.accessory.context.CurrentHorizontalTiltAngle = this.WindowCovering.CurrentHorizontalTiltAngle;
799
+ this.WindowCovering.Service.updateCharacteristic(
870
800
  this.hap.Characteristic.CurrentHorizontalTiltAngle,
871
- Number(this.CurrentHorizontalTiltAngle),
801
+ Number(this.WindowCovering.CurrentHorizontalTiltAngle),
872
802
  );
873
803
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}
874
- updateCharacteristic CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
804
+ updateCharacteristic CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
875
805
  }
876
806
  }
877
807
  // CurrentPosition
878
- if (this.CurrentPosition === undefined || Number.isNaN(this.CurrentPosition)) {
879
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
808
+ if (this.WindowCovering.CurrentPosition === undefined || Number.isNaN(this.WindowCovering.CurrentPosition)) {
809
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
880
810
  } else {
881
811
  if (this.device.mqttURL) {
882
- this.mqttPublish('CurrentPosition', this.CurrentPosition);
812
+ this.mqttPublish('CurrentPosition', this.WindowCovering.CurrentPosition.toString());
883
813
  }
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}`);
814
+ this.accessory.context.CurrentPosition = this.WindowCovering.CurrentPosition;
815
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, Number(this.WindowCovering.CurrentPosition));
816
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
817
+ + ` updateCharacteristic CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
887
818
  }
888
819
  // PositionState
889
- if (this.PositionState === undefined) {
890
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.PositionState}`);
820
+ if (this.WindowCovering.PositionState === undefined) {
821
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.WindowCovering.PositionState}`);
891
822
  } else {
892
823
  if (this.device.mqttURL) {
893
- this.mqttPublish('PositionState', this.PositionState);
824
+ this.mqttPublish('PositionState', this.WindowCovering.PositionState.toString());
894
825
  }
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}`);
826
+ this.accessory.context.PositionState = this.WindowCovering.PositionState;
827
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, Number(this.WindowCovering.PositionState));
828
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
829
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
898
830
  }
899
831
  // TargetPosition
900
- if (this.TargetPosition === undefined || Number.isNaN(this.TargetPosition)) {
901
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.TargetPosition}`);
832
+ if (this.WindowCovering.TargetPosition === undefined || Number.isNaN(this.WindowCovering.TargetPosition)) {
833
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.WindowCovering.TargetPosition}`);
902
834
  } else {
903
835
  if (this.device.mqttURL) {
904
- this.mqttPublish('TargetPosition', this.TargetPosition);
836
+ this.mqttPublish('TargetPosition', this.WindowCovering.TargetPosition.toString());
905
837
  }
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}`);
838
+ this.accessory.context.TargetPosition = this.WindowCovering.TargetPosition;
839
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, Number(this.WindowCovering.TargetPosition));
840
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
841
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}`);
909
842
  }
910
843
  // CurrentAmbientLightLevel
911
844
  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}`);
845
+ if (this.LightSensor!.CurrentAmbientLightLevel === undefined || Number.isNaN(this.LightSensor!.CurrentAmbientLightLevel)) {
846
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
847
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
914
848
  } else {
915
849
  if (this.device.mqttURL) {
916
- this.mqttPublish('CurrentAmbientLightLevel', this.CurrentAmbientLightLevel);
850
+ this.mqttPublish('CurrentAmbientLightLevel', this.LightSensor!.CurrentAmbientLightLevel.toString());
917
851
  }
918
- this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel;
919
- this.lightSensorService?.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
852
+ this.accessory.context.CurrentAmbientLightLevel = this.LightSensor!.CurrentAmbientLightLevel;
853
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.LightSensor!.CurrentAmbientLightLevel);
920
854
  this.debugLog(
921
855
  `${this.device.deviceType}: ${this.accessory.displayName}` +
922
- ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
856
+ ` updateCharacteristic CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`,
923
857
  );
924
858
  }
925
859
  }
926
860
  // BatteryLevel
927
- if (this.BatteryLevel === undefined) {
928
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
861
+ if (this.Battery.BatteryLevel === undefined) {
862
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
929
863
  } else {
930
864
  if (this.device.mqttURL) {
931
- this.mqttPublish('BatteryLevel', this.BatteryLevel);
865
+ this.mqttPublish('BatteryLevel', this.Battery.BatteryLevel.toString());
932
866
  }
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}`);
867
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
868
+ this.Battery?.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
869
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
936
870
  }
937
871
  // StatusLowBattery
938
- if (this.StatusLowBattery === undefined) {
939
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
872
+ if (this.Battery.StatusLowBattery === undefined) {
873
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
940
874
  } else {
941
875
  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}`);
876
+ this.mqttPublish('StatusLowBattery', this.Battery.StatusLowBattery.toString());
979
877
  }
878
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
879
+ this.Battery?.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
880
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
881
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
980
882
  }
981
- }
982
-
983
- async stopScanning(switchbot: any) {
984
- switchbot.stopScan();
985
- if (this.BLE_IsConnected) {
986
- await this.BLEparseStatus();
987
- await this.updateHomeKitCharacteristics();
883
+ if (this.Battery.ChargingState === undefined) {
884
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ChargingState: ${this.Battery.ChargingState}`);
988
885
  } 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
- })();
886
+ if (this.device.mqttURL) {
887
+ this.mqttPublish('ChargingState', this.Battery.ChargingState.toString());
888
+ }
889
+ this.accessory.context.ChargingState = this.Battery.ChargingState;
890
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, this.Battery.ChargingState);
891
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
892
+ + ` ChargingState: ${this.Battery.ChargingState}`);
1008
893
  }
1009
894
  }
1010
895
 
@@ -1024,218 +909,104 @@ export class BlindTilt {
1024
909
  }
1025
910
  }
1026
911
 
1027
- async SilentPerformance() {
1028
- if (Number(this.TargetPosition) > 50) {
912
+ async setPerformance() {
913
+ let setPositionMode: number;
914
+ let Mode: string;
915
+ if (Number(this.WindowCovering.TargetPosition) > 50) {
1029
916
  if (this.device.blindTilt?.setOpenMode === '1') {
1030
- this.setPositionMode = 1;
1031
- this.Mode = 'Silent Mode';
917
+ setPositionMode = 1;
918
+ Mode = 'Silent Mode';
919
+ } else if (this.device.blindTilt?.setOpenMode === '0') {
920
+ setPositionMode = 0;
921
+ Mode = 'Performance Mode';
1032
922
  } else {
1033
- this.setPositionMode = 0;
1034
- this.Mode = 'Performance Mode';
923
+ setPositionMode = 0;
924
+ Mode = 'Default Mode';
1035
925
  }
1036
926
  } else {
1037
927
  if (this.device.blindTilt?.setCloseMode === '1') {
1038
- this.setPositionMode = 1;
1039
- this.Mode = 'Silent Mode';
928
+ setPositionMode = 1;
929
+ Mode = 'Silent Mode';
930
+ } else if (this.device.blindTilt?.setOpenMode === '0') {
931
+ setPositionMode = 0;
932
+ Mode = 'Performance Mode';
1040
933
  } else {
1041
- this.setPositionMode = 0;
1042
- this.Mode = 'Performance Mode';
934
+ setPositionMode = 0;
935
+ Mode = 'Default Mode';
1043
936
  }
1044
937
  }
938
+ return { setPositionMode, Mode };
1045
939
  }
1046
940
 
1047
941
  async setMinMax(): Promise<void> {
1048
942
  if (this.device.blindTilt?.set_min) {
1049
- if (Number(this.CurrentPosition) <= this.device.blindTilt?.set_min) {
1050
- this.CurrentPosition = 0;
943
+ if (Number(this.WindowCovering.CurrentPosition) <= this.device.blindTilt?.set_min) {
944
+ this.WindowCovering.CurrentPosition = 0;
1051
945
  }
1052
946
  }
1053
947
  if (this.device.blindTilt?.set_max) {
1054
- if (Number(this.CurrentPosition) >= this.device.blindTilt?.set_max) {
1055
- this.CurrentPosition = 100;
948
+ if (Number(this.WindowCovering.CurrentPosition) >= this.device.blindTilt?.set_max) {
949
+ this.WindowCovering.CurrentPosition = 100;
1056
950
  }
1057
951
  }
1058
952
 
1059
953
  if (this.mappingMode === BlindTiltMappingMode.UseTiltForDirection) {
1060
- this.CurrentHorizontalTiltAngle = Number(this.CurrentHorizontalTiltAngle) < 0 ? -90 : 90;
954
+ this.WindowCovering.CurrentHorizontalTiltAngle = Number(this.WindowCovering.CurrentHorizontalTiltAngle) < 0 ? -90 : 90;
1061
955
  }
1062
956
  }
1063
957
 
1064
- minStep(device: device & devicesConfig): number {
958
+ async minStep(device: device & devicesConfig): Promise<number> {
959
+ let set_minStep: number;
1065
960
  if (device.blindTilt?.set_minStep) {
1066
- this.set_minStep = device.blindTilt?.set_minStep;
961
+ set_minStep = device.blindTilt?.set_minStep;
1067
962
  } else {
1068
- this.set_minStep = 1;
963
+ set_minStep = 1;
1069
964
  }
1070
- return this.set_minStep;
965
+ return set_minStep;
1071
966
  }
1072
967
 
1073
- minLux(): number {
968
+ async minLux(): Promise<number> {
969
+ let set_minLux: number;
1074
970
  if (this.device.blindTilt?.set_minLux) {
1075
- this.set_minLux = this.device.blindTilt?.set_minLux;
971
+ set_minLux = this.device.blindTilt?.set_minLux;
1076
972
  } else {
1077
- this.set_minLux = 1;
973
+ set_minLux = 1;
1078
974
  }
1079
- return this.set_minLux;
975
+ return set_minLux;
1080
976
  }
1081
977
 
1082
- maxLux(): number {
978
+ async maxLux(): Promise<number> {
979
+ let set_maxLux: number;
1083
980
  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
- }
981
+ set_maxLux = this.device.blindTilt?.set_maxLux;
1107
982
  } 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
- );
983
+ set_maxLux = 6001;
1194
984
  }
985
+ return set_maxLux;
1195
986
  }
1196
987
 
1197
988
  async offlineOff(): Promise<void> {
1198
989
  if (this.device.offline) {
1199
- await this.deviceContext();
1200
- await this.updateHomeKitCharacteristics();
990
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
991
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
992
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
993
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle, 90);
994
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle, 90);
1201
995
  }
1202
996
  }
1203
997
 
1204
998
  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);
999
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
1000
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e);
1001
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
1002
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle, e);
1003
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle, e);
1004
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
1005
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
1006
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, e);
1208
1007
  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;
1008
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, e);
1009
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.StatusActive, e);
1239
1010
  }
1240
1011
  }
1241
1012
 
@@ -1358,130 +1129,4 @@ export class BlindTilt {
1358
1129
  }
1359
1130
  }
1360
1131
  }
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
1132
  }