@switchbot/homebridge-switchbot 3.5.0-beta.6 → 3.5.0-beta.60

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 +408 -779
  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 +696 -822
  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 +237 -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 +279 -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 +242 -544
  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 +402 -805
  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 +684 -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 +535 -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 +246 -613
  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 +232 -593
  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 +185 -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 +277 -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 +241 -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 +181 -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 +170 -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 +178 -531
  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 +92 -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 +197 -521
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +10 -65
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +139 -495
  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 +9 -49
  88. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  89. package/dist/irdevice/airconditioner.js +309 -419
  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 +72 -304
  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 +34 -278
  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 +100 -338
  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 +87 -357
  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 +352 -546
  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 +82 -321
  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 +41 -284
  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 +42 -287
  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 -169
  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 +442 -814
  143. package/src/device/bot.ts +754 -915
  144. package/src/device/ceilinglight.ts +255 -633
  145. package/src/device/colorbulb.ts +294 -685
  146. package/src/device/contact.ts +277 -571
  147. package/src/device/curtain.ts +431 -835
  148. package/src/device/device.ts +709 -0
  149. package/src/device/fan.ts +591 -0
  150. package/src/device/hub.ts +286 -644
  151. package/src/device/humidifier.ts +266 -646
  152. package/src/device/iosensor.ts +220 -625
  153. package/src/device/lightstrip.ts +305 -620
  154. package/src/device/lock.ts +280 -600
  155. package/src/device/meter.ts +216 -617
  156. package/src/device/meterplus.ts +205 -619
  157. package/src/device/motion.ts +206 -556
  158. package/src/device/plug.ts +107 -490
  159. package/src/device/robotvacuumcleaner.ts +223 -550
  160. package/src/device/waterdetector.ts +160 -519
  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 +333 -447
  165. package/src/irdevice/airpurifier.ts +92 -322
  166. package/src/irdevice/camera.ts +45 -294
  167. package/src/irdevice/fan.ts +115 -353
  168. package/src/irdevice/irdevice.ts +346 -0
  169. package/src/irdevice/light.ts +110 -385
  170. package/src/irdevice/other.ts +399 -616
  171. package/src/irdevice/tv.ts +103 -340
  172. package/src/irdevice/vacuumcleaner.ts +52 -306
  173. package/src/irdevice/waterheater.ts +53 -311
  174. package/src/platform.ts +355 -216
  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,47 @@ 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
+ this.WindowCovering = {
71
+ Name: accessory.context.WindowCoveringName ?? accessory.displayName,
72
+ Service: accessory.getService(this.hap.Service.WindowCovering) ?? accessory.addService(this.hap.Service.WindowCovering) as Service,
73
+ PositionState: accessory.context.PositionState ?? this.hap.Characteristic.PositionState.STOPPED,
74
+ TargetPosition: accessory.context.TargetPosition ?? 100,
75
+ CurrentPosition: accessory.context.CurrentPosition ?? 100,
76
+ TargetHorizontalTiltAngle: accessory.context.TargetHorizontalTiltAngle ?? 90,
77
+ CurrentHorizontalTiltAngle: accessory.context.CurrentHorizontalTiltAngle ?? 90,
78
+ };
79
+
80
+ // Initialize WindowCovering Characteristics
81
+ this.WindowCovering.Service
82
+ .setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name)
83
+ .getCharacteristic(this.hap.Characteristic.TargetPosition)
147
84
  .setProps({
148
- minStep: this.minStep(device),
85
+ minStep: Number(this.minStep(device)),
149
86
  minValue: 0,
150
87
  maxValue: 100,
151
88
  validValueRanges: [0, 100],
152
89
  })
153
90
  .onGet(() => {
154
- return this.CurrentPosition;
155
- });
91
+ return this.WindowCovering.TargetPosition;
92
+ })
93
+ .onSet(this.TargetPositionSet.bind(this));
156
94
 
157
- this.windowCoveringService
158
- .getCharacteristic(this.hap.Characteristic.TargetPosition)
95
+ // Initialize WindowCovering CurrentPosition Characteristic
96
+ this.WindowCovering.Service
97
+ .getCharacteristic(this.hap.Characteristic.CurrentPosition)
159
98
  .setProps({
160
- minStep: this.minStep(device),
99
+ minStep: Number(this.minStep(device)),
161
100
  minValue: 0,
162
101
  maxValue: 100,
163
102
  validValueRanges: [0, 100],
164
- })
165
- .onSet(this.TargetPositionSet.bind(this));
103
+ }).onGet(() => {
104
+ return this.WindowCovering?.CurrentPosition ?? 0;
105
+ });
166
106
 
167
- this.CurrentHorizontalTiltAngle = 90;
168
- this.windowCoveringService
169
- .getCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle)
107
+ // Initialize WindowCovering TargetHorizontalTiltAngle Characteristic
108
+ this.WindowCovering.Service
109
+ .getCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle)
170
110
  .setProps({
171
111
  minStep: 180,
172
112
  minValue: -90,
@@ -174,31 +114,64 @@ export class BlindTilt {
174
114
  validValues: [-90, 90],
175
115
  })
176
116
  .onGet(() => {
177
- // this.debugLog(`requested CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
178
- return this.CurrentHorizontalTiltAngle;
179
- });
117
+ return this.WindowCovering.TargetHorizontalTiltAngle;
118
+ })
119
+ .onSet(this.TargetHorizontalTiltAngleSet.bind(this));
120
+ accessory.context.WindowCoveringName = this.WindowCovering.Name;
180
121
 
181
- this.TargetHorizontalTiltAngle = 90;
182
- this.windowCoveringService
183
- .getCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle)
122
+ // Initialize WindowCovering CurrentHorizontalTiltAngle Characteristic
123
+ this.WindowCovering.Service
124
+ .getCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle)
184
125
  .setProps({
185
126
  minStep: 180,
186
127
  minValue: -90,
187
128
  maxValue: 90,
188
129
  validValues: [-90, 90],
189
- })
190
- .onSet(this.TargetHorizontalTiltAngleSet.bind(this));
130
+ }).onGet(() => {
131
+ return this.WindowCovering.CurrentHorizontalTiltAngle ?? 0;
132
+ });
191
133
 
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;
134
+ // Initialize Battery Service
135
+ this.Battery = {
136
+ Name: accessory.context.BatteryName ?? `${accessory.displayName} Battery`,
137
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
138
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
139
+ StatusLowBattery: this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
140
+ ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGING,
141
+ };
142
+
143
+ // Initialize Battery Name Characteristic
144
+ this.Battery.Service
145
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
146
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
147
+ accessory.context.BatteryName = this.Battery.Name;
148
+
149
+ // Initialize LightSensor Service
150
+ if (device.blindTilt?.hide_lightsensor) {
151
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} Removing Light Sensor Service`);
152
+ this.LightSensor!.Service = accessory.getService(this.hap.Service.LightSensor) as Service;
153
+ accessory.removeService(this.LightSensor!.Service);
154
+ } else {
155
+ this.LightSensor = {
156
+ Name: accessory.context.LightSensorName ?? `${accessory.displayName} Light Sensor`,
157
+ Service: accessory.getService(this.hap.Service.LightSensor) ?? accessory.addService(this.hap.Service.LightSensor) as Service,
158
+ CurrentAmbientLightLevel: accessory.context.CurrentAmbientLightLevel ?? 0.0001,
159
+ };
196
160
 
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`);
161
+ // Initialize LightSensor Characteristics
162
+ this.LightSensor.Service
163
+ .setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name)
164
+ .setCharacteristic(this.hap.Characteristic.StatusActive, true)
165
+ .getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel)
166
+ .onGet(() => {
167
+ return this.LightSensor?.CurrentAmbientLightLevel ?? 0.0001;
168
+ });
169
+ accessory.context.LightSensorName = this.LightSensor.Name;
200
170
  }
201
171
 
172
+ // Retrieve initial values and updateHomekit
173
+ this.refreshStatus();
174
+
202
175
  // Update Homekit
203
176
  this.updateHomeKitCharacteristics();
204
177
 
@@ -210,21 +183,23 @@ export class BlindTilt {
210
183
  });
211
184
 
212
185
  //regisiter webhook event handler
213
- if (this.device.webhook) {
214
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
186
+ if (device.webhook) {
187
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is listening webhook.`);
215
188
  this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
216
189
  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();*/
190
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
191
+ const { slidePosition, battery, lightLevel } = context;
192
+ const { CurrentPosition } = this.WindowCovering;
193
+ const { BatteryLevel } = this.Battery;
194
+ const { CurrentAmbientLightLevel } = this.LightSensor ?? {};
195
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} (slidePosition, battery, lightLevel) = `
196
+ + `Webhook:(${slidePosition}, ${battery}, ${lightLevel}), current:(${CurrentPosition}, ${BatteryLevel}, ${CurrentAmbientLightLevel})`);
197
+ this.WindowCovering.CurrentPosition = slidePosition;
198
+ this.Battery.BatteryLevel = battery;
199
+ if (!device.blindTilt?.hide_lightsensor) {
200
+ this.LightSensor!.CurrentAmbientLightLevel = lightLevel;
201
+ }
202
+ this.updateHomeKitCharacteristics();
228
203
  } catch (e: any) {
229
204
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
230
205
  + `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
@@ -233,13 +208,14 @@ export class BlindTilt {
233
208
  }
234
209
 
235
210
  // update slide progress
236
- interval(this.updateRate * 1000)
211
+ interval(this.deviceUpdateRate * 1000)
237
212
  //.pipe(skipWhile(() => this.blindTiltUpdateInProgress))
238
213
  .subscribe(async () => {
239
- if (this.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
214
+ if (this.WindowCovering.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
240
215
  return;
241
216
  }
242
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Refresh Status When Moving, PositionState: ${this.PositionState}`);
217
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} Refresh Status When Moving,`
218
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
243
219
  await this.refreshStatus();
244
220
  });
245
221
 
@@ -257,228 +233,238 @@ export class BlindTilt {
257
233
  await this.pushChanges();
258
234
  } catch (e: any) {
259
235
  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
- );
236
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed pushChanges with ${device.connectionType} Connection,` +
237
+ ` Error Message: ${JSON.stringify(e.message)}`);
264
238
  }
265
239
  this.blindTiltUpdateInProgress = false;
266
240
  });
267
241
  }
268
242
 
269
243
  /**
270
- * Parse the device status from the SwitchBot api
244
+ * Parse the device status from the SwitchBotBLE API
271
245
  */
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> {
246
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
288
247
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
289
248
  // CurrentPosition
290
- this.CurrentPosition = 100 - Number(this.BLE_CurrentPosition);
249
+ this.WindowCovering.CurrentPosition = 100 - Number(serviceData.position);
291
250
  await this.setMinMax();
292
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.CurrentPosition}`);
251
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.WindowCovering.CurrentPosition}`);
293
252
  if (this.setNewTarget) {
294
253
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
295
254
  }
296
255
 
297
- if (this.setNewTarget && this.BLE_InMotion) {
256
+ if (this.setNewTarget && serviceData.inMotion) {
298
257
  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}`);
258
+ if (Number(this.WindowCovering.TargetPosition) > this.WindowCovering.CurrentPosition) {
259
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
260
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
261
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
262
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} INCREASING`
263
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
264
+ } else if (Number(this.WindowCovering.TargetPosition) < this.WindowCovering.CurrentPosition) {
265
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
266
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
267
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
268
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} DECREASING`
269
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
309
270
  } 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}`);
271
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} Standby2,`
272
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
273
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
274
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
275
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} STOPPED`
276
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
314
277
  }
315
278
  } 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;
279
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
280
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
281
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
319
282
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
320
283
  }
321
- this.debugLog(
322
- `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
323
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
324
- );
284
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition},`
285
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`);
325
286
 
326
287
  if (!this.device.blindTilt?.hide_lightsensor) {
327
- this.set_minLux = this.minLux();
328
- this.set_maxLux = this.maxLux();
329
- this.spaceBetweenLevels = 9;
288
+ const set_minLux = await this.minLux();
289
+ const set_maxLux = await this.maxLux();
290
+ const spaceBetweenLevels = 9;
291
+
292
+ if (this.LightSensor?.CurrentAmbientLightLevel === 0) {
293
+ this.LightSensor!.CurrentAmbientLightLevel = 0.0001;
294
+ }
330
295
 
331
296
  // Brightness
332
- switch (this.BLE_CurrentAmbientLightLevel) {
297
+ switch (serviceData.lightLevel) {
333
298
  case 1:
334
- this.CurrentAmbientLightLevel = this.set_minLux;
335
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel}`);
299
+ this.LightSensor!.CurrentAmbientLightLevel = set_minLux;
300
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
336
301
  break;
337
302
  case 2:
338
- this.CurrentAmbientLightLevel = (this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels;
303
+ this.LightSensor!.CurrentAmbientLightLevel = (set_maxLux - set_minLux) / spaceBetweenLevels;
339
304
  this.debugLog(
340
- `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel},` +
341
- ` Calculation: ${(this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels}`,
305
+ `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel},` +
306
+ ` Calculation: ${(set_maxLux - set_minLux) / spaceBetweenLevels}`,
342
307
  );
343
308
  break;
344
309
  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}`);
310
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 2;
311
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
347
312
  break;
348
313
  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}`);
314
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 3;
315
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
351
316
  break;
352
317
  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}`);
318
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 4;
319
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
355
320
  break;
356
321
  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}`);
322
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 5;
323
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
359
324
  break;
360
325
  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}`);
326
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 6;
327
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
363
328
  break;
364
329
  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}`);
330
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 7;
331
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
367
332
  break;
368
333
  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}`);
334
+ this.LightSensor!.CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * 8;
335
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel}`);
371
336
  break;
372
337
  case 10:
373
338
  default:
374
- this.CurrentAmbientLightLevel = this.set_maxLux;
339
+ this.LightSensor!.CurrentAmbientLightLevel = set_maxLux;
375
340
  this.debugLog();
376
341
  }
377
342
  this.debugLog(
378
- `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.BLE_CurrentAmbientLightLevel},` +
379
- ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
343
+ `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${serviceData.lightLevel},` +
344
+ ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`,
380
345
  );
381
346
  }
382
347
  // Battery
383
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
384
- if (this.BatteryLevel < 10) {
385
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
348
+ this.Battery.BatteryLevel = Number(serviceData.battery);
349
+ if (this.Battery.BatteryLevel < 10) {
350
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
386
351
  } else {
387
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
352
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
388
353
  }
389
354
  this.debugLog(
390
- `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},` + ` StatusLowBattery: ${this.StatusLowBattery}`,
355
+ `${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
356
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`,
391
357
  );
392
358
  }
393
359
 
394
- async openAPIparseStatus(): Promise<void> {
360
+
361
+ /**
362
+ * Parse the device status from the SwitchBot OpenAPI
363
+ */
364
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
395
365
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
396
366
 
397
- const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(this.OpenAPI_CurrentPosition),
398
- String(this.OpenAPI_Direction));
399
- this.debugLog(` device: ${this.OpenAPI_CurrentPosition} => HK: ${homekitPosition}`);
367
+ const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(deviceStatus.body.slidePosition),
368
+ String(deviceStatus.body.direction));
369
+ this.debugLog(` device: ${deviceStatus.body.slidePosition} => HK: ${homekitPosition}`);
400
370
 
401
- this.CurrentPosition = homekitPosition;
371
+ this.WindowCovering!.CurrentPosition = homekitPosition;
402
372
  // CurrentPosition
403
373
  await this.setMinMax();
404
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
374
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
405
375
 
406
376
  if (homekitTiltAngle) {
407
- this.CurrentHorizontalTiltAngle = homekitTiltAngle!;
408
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
377
+ this.WindowCovering.CurrentHorizontalTiltAngle = homekitTiltAngle!;
378
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
379
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
409
380
  }
410
381
 
411
382
  if (this.setNewTarget) {
412
383
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
413
384
  }
414
385
 
415
- if (this.setNewTarget && this.OpenAPI_InMotion) {
386
+ if (this.setNewTarget && deviceStatus.body.moving) {
416
387
  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}`);
388
+ if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
389
+ || (homekitTiltAngle && this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle)) {
390
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition} `);
391
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
392
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
393
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} INCREASING`
394
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
395
+ } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
396
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition} `);
397
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
398
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
399
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} DECREASING`
400
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
427
401
  } else {
428
402
  this.debugLog(
429
- `${this.device.deviceType}: ${this.CurrentPosition} Standby because reached position,` + ` CurrentPosition: ${this.CurrentPosition}`,
403
+ `${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} Standby because reached position,`
404
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
430
405
  );
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}`);
406
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
407
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
408
+ this.debugLog(`${this.device.deviceType}: ${this.WindowCovering.CurrentPosition} STOPPED`
409
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
434
410
  }
435
411
  } else {
436
412
  this.debugLog(
437
- `${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,` + ` CurrentPosition: ${this.CurrentPosition}`,
413
+ `${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,`
414
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
438
415
  );
439
- this.TargetPosition = this.CurrentPosition;
416
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
440
417
  if (homekitTiltAngle) {
441
- this.TargetHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
418
+ this.WindowCovering.TargetHorizontalTiltAngle = this.WindowCovering.CurrentHorizontalTiltAngle;
442
419
  }
443
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
420
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
444
421
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
445
422
  }
446
423
  this.debugLog(
447
- `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
448
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
424
+ `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition},` +
425
+ ` TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`,
449
426
  );
450
427
 
451
428
  if (!this.device.blindTilt?.hide_lightsensor) {
452
- this.set_minLux = this.minLux();
453
- this.set_maxLux = this.maxLux();
429
+ const set_minLux = await this.minLux();
430
+ const set_maxLux = await this.maxLux();
454
431
  // Brightness
455
- switch (this.OpenAPI_CurrentAmbientLightLevel) {
432
+ switch (deviceStatus.body.brightness) {
456
433
  case 'dim':
457
- this.CurrentAmbientLightLevel = this.set_minLux;
434
+ this.LightSensor!.CurrentAmbientLightLevel = set_minLux;
458
435
  break;
459
436
  case 'bright':
460
437
  default:
461
- this.CurrentAmbientLightLevel = this.set_maxLux;
438
+ this.LightSensor!.CurrentAmbientLightLevel = set_maxLux;
462
439
  }
463
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
440
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
441
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
464
442
  }
465
443
 
466
444
  // BatteryLevel
467
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
468
- if (this.BatteryLevel < 10) {
469
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
445
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
446
+ if (this.Battery.BatteryLevel < 10) {
447
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
470
448
  } else {
471
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
449
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
472
450
  }
473
- if (Number.isNaN(this.BatteryLevel)) {
474
- this.BatteryLevel = 100;
451
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
452
+ this.Battery.BatteryLevel = 100;
475
453
  }
476
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},`
477
- + ` StatusLowBattery: ${this.StatusLowBattery}`);
454
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
455
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
478
456
 
479
- // FirmwareRevision
480
- this.FirmwareRevision = this.OpenAPI_FirmwareRevision!;
481
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
457
+ // Firmware Version
458
+ const version = deviceStatus.body.version?.toString();
459
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
460
+ if (deviceStatus.body.version) {
461
+ this.accessory.context.version = version?.replace(/^V|-.*$/g, '');
462
+ this.accessory
463
+ .getService(this.hap.Service.AccessoryInformation)!
464
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, this.accessory.context.version)
465
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
466
+ .updateValue(this.accessory.context.version);
467
+ }
482
468
  }
483
469
 
484
470
  async refreshStatus(): Promise<void> {
@@ -510,21 +496,13 @@ export class BlindTilt {
510
496
  // Start to monitor advertisement packets
511
497
  (async () => {
512
498
  // Start to monitor advertisement packets
513
- await switchbot.startScan({
514
- model: 'x',
515
- id: this.device.bleMac,
516
- });
499
+ await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
517
500
  // Set an event handler
518
501
  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') {
502
+ if (this.device.bleMac === ad.address && ad.model === this.device.bleModel) {
503
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
504
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
522
505
  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
506
  } else {
529
507
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
530
508
  }
@@ -534,83 +512,27 @@ export class BlindTilt {
534
512
  // Stop to monitor
535
513
  await switchbot.stopScan();
536
514
  // Update HomeKit
537
- await this.BLEparseStatus();
515
+ await this.BLEparseStatus(switchbot.onadvertisement.serviceData);
538
516
  await this.updateHomeKitCharacteristics();
539
517
  })();
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 {
518
+ if (switchbot === undefined) {
590
519
  await this.BLERefreshConnection(switchbot);
591
- }*/
520
+ }
592
521
  }
593
522
 
594
523
  async openAPIRefreshStatus(): Promise<void> {
595
524
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
596
525
  try {
597
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
598
- headers: this.platform.generateHeaders(),
599
- });
526
+ const { body, statusCode } = await this.platform.retryRequest(this.deviceMaxRetries, this.deviceDelayBetweenRetries,
527
+ `${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders() });
600
528
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
601
529
  const deviceStatus: any = await body.json();
602
530
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
603
531
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
604
532
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
605
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
533
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
606
534
  + `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();
535
+ this.openAPIparseStatus(deviceStatus);
614
536
  this.updateHomeKitCharacteristics();
615
537
  } else {
616
538
  this.statusCode(statusCode);
@@ -649,7 +571,7 @@ export class BlindTilt {
649
571
 
650
572
  async BLEpushChanges(): Promise<void> {
651
573
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
652
- if (this.TargetPosition !== this.CurrentPosition) {
574
+ if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition) {
653
575
  const switchbot = await this.platform.connectBLE();
654
576
  // Convert to BLE Address
655
577
  this.device.bleMac = this.device
@@ -657,26 +579,24 @@ export class BlindTilt {
657
579
  .join(':')
658
580
  .toLowerCase();
659
581
  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}`);
582
+ const { setPositionMode, Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
583
+ this.debugLog(`${this.accessory.displayName} Mode: ${Mode}`);
666
584
  if (switchbot !== false) {
667
585
  switchbot
668
586
  .discover({ model: 'c', quick: true, id: this.device.bleMac })
669
587
  .then(async (device_list: any) => {
670
- this.infoLog(`${this.accessory.displayName} Target Position: ${this.TargetPosition}`);
671
- return await this.retry({
672
- max: this.maxRetry(),
588
+ this.infoLog(`${this.accessory.displayName} Target Position: ${this.WindowCovering.TargetPosition}`);
589
+ return await this.retryBLE({
590
+ max: await this.maxRetryBLE(),
673
591
  fn: async () => {
674
- return await device_list[0].runToPos(100 - Number(this.TargetPosition), adjustedMode);
592
+ return await device_list[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), setPositionMode);
675
593
  },
676
594
  });
677
595
  })
678
596
  .then(() => {
679
597
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
598
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
599
+ + `Target Position: ${this.WindowCovering.TargetPosition} sent over BLE, sent successfully`);
680
600
  })
681
601
  .catch(async (e: any) => {
682
602
  this.apiError(e);
@@ -693,39 +613,24 @@ export class BlindTilt {
693
613
  } else {
694
614
  this.debugLog(
695
615
  `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` +
696
- ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
616
+ ` CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition ${this.WindowCovering.TargetPosition}`,
697
617
  );
698
618
  }
699
619
  }
700
620
 
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
621
  async openAPIpushChanges(): Promise<void> {
722
622
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
723
623
  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}`);
624
+ this.mappingMode === BlindTiltMappingMode.UseTiltForDirection
625
+ && this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle;
626
+ if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition
627
+ || hasDifferentAndRelevantHorizontalTiltAngle || this.device.disableCaching) {
628
+ const [direction, position] = this.mapHomekitValuesToDeviceValues(Number(this.WindowCovering.TargetPosition),
629
+ Number(this.WindowCovering.TargetHorizontalTiltAngle));
630
+ const { Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
631
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
632
+ + ` Pushing ${this.WindowCovering.TargetPosition} (device = ${direction};${position})`);
633
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Mode: ${Mode}`);
729
634
  let bodyChange = '';
730
635
  if (position === 100) {
731
636
  bodyChange = JSON.stringify({
@@ -757,8 +662,10 @@ export class BlindTilt {
757
662
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
758
663
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
759
664
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
760
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
665
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
761
666
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
667
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
668
+ + `request to SwitchBot API, body: ${JSON.stringify(bodyChange)} sent successfully`);
762
669
  } else {
763
670
  this.statusCode(statusCode);
764
671
  this.statusCode(deviceStatus.statusCode);
@@ -766,15 +673,16 @@ export class BlindTilt {
766
673
  } catch (e: any) {
767
674
  this.apiError(e);
768
675
  this.errorLog(
769
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` +
770
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
676
+ `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
677
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
771
678
  );
772
679
  }
773
680
  } else {
774
681
  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}`,
682
+ `${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.`
683
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition ${this.WindowCovering.TargetPosition}`
684
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle},`
685
+ + ` TargetPosition ${this.WindowCovering.TargetHorizontalTiltAngle}`,
778
686
  );
779
687
  }
780
688
  }
@@ -783,16 +691,16 @@ export class BlindTilt {
783
691
  * Handle requests to set the value of the "Target Horizontal Tilt" characteristic
784
692
  */
785
693
  async TargetHorizontalTiltAngleSet(value: CharacteristicValue): Promise<void> {
786
- if (this.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
694
+ if (this.WindowCovering.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
787
695
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetHorizontalTiltAngle: ${value}`);
788
696
  } else {
789
697
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetHorizontalTiltAngle: ${value}`);
790
698
  }
791
699
 
792
700
  //value = value < 0 ? -90 : 90;
793
- this.TargetHorizontalTiltAngle = value;
701
+ this.WindowCovering.TargetHorizontalTiltAngle = value;
794
702
  if (this.device.mqttURL) {
795
- this.mqttPublish('TargetHorizontalTiltAngle', this.TargetHorizontalTiltAngle);
703
+ this.mqttPublish('TargetHorizontalTiltAngle', this.WindowCovering.TargetHorizontalTiltAngle.toString());
796
704
  }
797
705
 
798
706
  this.startUpdatingBlindTiltIfNeeded();
@@ -802,15 +710,15 @@ export class BlindTilt {
802
710
  * Handle requests to set the value of the "Target Position" characteristic
803
711
  */
804
712
  async TargetPositionSet(value: CharacteristicValue): Promise<void> {
805
- if (this.TargetPosition === this.accessory.context.TargetPosition) {
713
+ if (this.WindowCovering.TargetPosition === this.accessory.context.TargetPosition) {
806
714
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetPosition: ${value}`);
807
715
  } else {
808
716
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
809
717
  }
810
718
 
811
- this.TargetPosition = value;
719
+ this.WindowCovering.TargetPosition = value;
812
720
  if (this.device.mqttURL) {
813
- this.mqttPublish('TargetPosition', this.TargetPosition);
721
+ this.mqttPublish('TargetPosition', this.WindowCovering.TargetPosition.toString());
814
722
  }
815
723
  this.startUpdatingBlindTiltIfNeeded();
816
724
  }
@@ -818,39 +726,43 @@ export class BlindTilt {
818
726
  async startUpdatingBlindTiltIfNeeded(): Promise<void> {
819
727
  await this.setMinMax();
820
728
  this.debugLog('setMinMax');
821
- if (this.TargetPosition > this.CurrentPosition || this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle) {
822
- this.PositionState = this.hap.Characteristic.PositionState.INCREASING;
729
+ if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
730
+ || this.WindowCovering.TargetHorizontalTiltAngle !== this.WindowCovering.CurrentHorizontalTiltAngle) {
731
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
823
732
  this.setNewTarget = true;
824
733
  this.debugLog(
825
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
734
+ `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
735
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
826
736
  );
827
- } else if (this.TargetPosition < this.CurrentPosition) {
828
- this.PositionState = this.hap.Characteristic.PositionState.DECREASING;
737
+ } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
738
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
829
739
  this.setNewTarget = true;
830
740
  this.debugLog(
831
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
741
+ `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
742
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
832
743
  );
833
744
  } else {
834
- this.PositionState = this.hap.Characteristic.PositionState.STOPPED;
745
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
835
746
  this.setNewTarget = false;
836
747
  this.debugLog(
837
- `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` + ` CurrentPosition: ${this.CurrentPosition}`,
748
+ `${this.device.deviceType}: ${this.accessory.displayName} value: ${this.WindowCovering.CurrentPosition},`
749
+ + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`,
838
750
  );
839
751
  }
840
- this.windowCoveringService.setCharacteristic(this.hap.Characteristic.PositionState, this.PositionState);
841
- this.windowCoveringService.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.PositionState);
752
+ this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.PositionState, this.WindowCovering.PositionState);
753
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
842
754
 
843
755
  /**
844
756
  * If Blind Tilt movement time is short, the moving flag from backend is always false.
845
757
  * The minimum time depends on the network control latency.
846
758
  */
847
759
  clearTimeout(this.setNewTargetTimer);
848
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.updateRate}`);
760
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.deviceUpdateRate}`);
849
761
  if (this.setNewTarget) {
850
762
  this.setNewTargetTimer = setTimeout(() => {
851
763
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} setNewTarget ${this.setNewTarget} timeout`);
852
764
  this.setNewTarget = false;
853
- }, this.updateRate * 1000);
765
+ }, this.deviceUpdateRate * 1000);
854
766
  }
855
767
  this.doBlindTiltUpdate.next();
856
768
  }
@@ -859,152 +771,108 @@ export class BlindTilt {
859
771
  await this.setMinMax();
860
772
  // CurrentHorizontalTiltAngle
861
773
  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}`);
774
+ if (this.WindowCovering.CurrentHorizontalTiltAngle === undefined || Number.isNaN(this.WindowCovering.CurrentHorizontalTiltAngle)) {
775
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
776
+ + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
864
777
  } else {
865
778
  if (this.device.mqttURL) {
866
- this.mqttPublish('CurrentHorizontalTiltAngle', this.CurrentHorizontalTiltAngle);
779
+ this.mqttPublish('CurrentHorizontalTiltAngle', this.WindowCovering.CurrentHorizontalTiltAngle.toString());
867
780
  }
868
- this.accessory.context.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
869
- this.windowCoveringService.updateCharacteristic(
781
+ this.accessory.context.CurrentHorizontalTiltAngle = this.WindowCovering.CurrentHorizontalTiltAngle;
782
+ this.WindowCovering.Service.updateCharacteristic(
870
783
  this.hap.Characteristic.CurrentHorizontalTiltAngle,
871
- Number(this.CurrentHorizontalTiltAngle),
784
+ Number(this.WindowCovering.CurrentHorizontalTiltAngle),
872
785
  );
873
786
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}
874
- updateCharacteristic CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
787
+ updateCharacteristic CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
875
788
  }
876
789
  }
877
790
  // CurrentPosition
878
- if (this.CurrentPosition === undefined || Number.isNaN(this.CurrentPosition)) {
879
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
791
+ if (this.WindowCovering.CurrentPosition === undefined || Number.isNaN(this.WindowCovering.CurrentPosition)) {
792
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
880
793
  } else {
881
794
  if (this.device.mqttURL) {
882
- this.mqttPublish('CurrentPosition', this.CurrentPosition);
795
+ this.mqttPublish('CurrentPosition', this.WindowCovering.CurrentPosition.toString());
883
796
  }
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}`);
797
+ this.accessory.context.CurrentPosition = this.WindowCovering.CurrentPosition;
798
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, Number(this.WindowCovering.CurrentPosition));
799
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
800
+ + ` updateCharacteristic CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
887
801
  }
888
802
  // PositionState
889
- if (this.PositionState === undefined) {
890
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.PositionState}`);
803
+ if (this.WindowCovering.PositionState === undefined) {
804
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.WindowCovering.PositionState}`);
891
805
  } else {
892
806
  if (this.device.mqttURL) {
893
- this.mqttPublish('PositionState', this.PositionState);
807
+ this.mqttPublish('PositionState', this.WindowCovering.PositionState.toString());
894
808
  }
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}`);
809
+ this.accessory.context.PositionState = this.WindowCovering.PositionState;
810
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, Number(this.WindowCovering.PositionState));
811
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
812
+ + ` PositionState: ${this.WindowCovering.PositionState}`);
898
813
  }
899
814
  // TargetPosition
900
- if (this.TargetPosition === undefined || Number.isNaN(this.TargetPosition)) {
901
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.TargetPosition}`);
815
+ if (this.WindowCovering.TargetPosition === undefined || Number.isNaN(this.WindowCovering.TargetPosition)) {
816
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.WindowCovering.TargetPosition}`);
902
817
  } else {
903
818
  if (this.device.mqttURL) {
904
- this.mqttPublish('TargetPosition', this.TargetPosition);
819
+ this.mqttPublish('TargetPosition', this.WindowCovering.TargetPosition.toString());
905
820
  }
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}`);
821
+ this.accessory.context.TargetPosition = this.WindowCovering.TargetPosition;
822
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, Number(this.WindowCovering.TargetPosition));
823
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
824
+ + ` TargetPosition: ${this.WindowCovering.TargetPosition}`);
909
825
  }
910
826
  // CurrentAmbientLightLevel
911
827
  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}`);
828
+ if (this.LightSensor!.CurrentAmbientLightLevel === undefined || Number.isNaN(this.LightSensor!.CurrentAmbientLightLevel)) {
829
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
830
+ + ` CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`);
914
831
  } else {
915
832
  if (this.device.mqttURL) {
916
- this.mqttPublish('CurrentAmbientLightLevel', this.CurrentAmbientLightLevel);
833
+ this.mqttPublish('CurrentAmbientLightLevel', this.LightSensor!.CurrentAmbientLightLevel.toString());
917
834
  }
918
- this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel;
919
- this.lightSensorService?.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
835
+ this.accessory.context.CurrentAmbientLightLevel = this.LightSensor!.CurrentAmbientLightLevel;
836
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.LightSensor!.CurrentAmbientLightLevel);
920
837
  this.debugLog(
921
838
  `${this.device.deviceType}: ${this.accessory.displayName}` +
922
- ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
839
+ ` updateCharacteristic CurrentAmbientLightLevel: ${this.LightSensor!.CurrentAmbientLightLevel}`,
923
840
  );
924
841
  }
925
842
  }
926
843
  // BatteryLevel
927
- if (this.BatteryLevel === undefined) {
928
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
844
+ if (this.Battery.BatteryLevel === undefined) {
845
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
929
846
  } else {
930
847
  if (this.device.mqttURL) {
931
- this.mqttPublish('BatteryLevel', this.BatteryLevel);
848
+ this.mqttPublish('BatteryLevel', this.Battery.BatteryLevel.toString());
932
849
  }
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}`);
850
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
851
+ this.Battery?.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
852
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
936
853
  }
937
854
  // StatusLowBattery
938
- if (this.StatusLowBattery === undefined) {
939
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
855
+ if (this.Battery.StatusLowBattery === undefined) {
856
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
940
857
  } else {
941
858
  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}`);
859
+ this.mqttPublish('StatusLowBattery', this.Battery.StatusLowBattery.toString());
979
860
  }
861
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
862
+ this.Battery?.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
863
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
864
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
980
865
  }
981
- }
982
-
983
- async stopScanning(switchbot: any) {
984
- switchbot.stopScan();
985
- if (this.BLE_IsConnected) {
986
- await this.BLEparseStatus();
987
- await this.updateHomeKitCharacteristics();
866
+ if (this.Battery.ChargingState === undefined) {
867
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ChargingState: ${this.Battery.ChargingState}`);
988
868
  } 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
- })();
869
+ if (this.device.mqttURL) {
870
+ this.mqttPublish('ChargingState', this.Battery.ChargingState.toString());
871
+ }
872
+ this.accessory.context.ChargingState = this.Battery.ChargingState;
873
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, this.Battery.ChargingState);
874
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
875
+ + ` ChargingState: ${this.Battery.ChargingState}`);
1008
876
  }
1009
877
  }
1010
878
 
@@ -1024,218 +892,104 @@ export class BlindTilt {
1024
892
  }
1025
893
  }
1026
894
 
1027
- async SilentPerformance() {
1028
- if (Number(this.TargetPosition) > 50) {
895
+ async setPerformance() {
896
+ let setPositionMode: number;
897
+ let Mode: string;
898
+ if (Number(this.WindowCovering.TargetPosition) > 50) {
1029
899
  if (this.device.blindTilt?.setOpenMode === '1') {
1030
- this.setPositionMode = 1;
1031
- this.Mode = 'Silent Mode';
900
+ setPositionMode = 1;
901
+ Mode = 'Silent Mode';
902
+ } else if (this.device.blindTilt?.setOpenMode === '0') {
903
+ setPositionMode = 0;
904
+ Mode = 'Performance Mode';
1032
905
  } else {
1033
- this.setPositionMode = 0;
1034
- this.Mode = 'Performance Mode';
906
+ setPositionMode = 0;
907
+ Mode = 'Default Mode';
1035
908
  }
1036
909
  } else {
1037
910
  if (this.device.blindTilt?.setCloseMode === '1') {
1038
- this.setPositionMode = 1;
1039
- this.Mode = 'Silent Mode';
911
+ setPositionMode = 1;
912
+ Mode = 'Silent Mode';
913
+ } else if (this.device.blindTilt?.setOpenMode === '0') {
914
+ setPositionMode = 0;
915
+ Mode = 'Performance Mode';
1040
916
  } else {
1041
- this.setPositionMode = 0;
1042
- this.Mode = 'Performance Mode';
917
+ setPositionMode = 0;
918
+ Mode = 'Default Mode';
1043
919
  }
1044
920
  }
921
+ return { setPositionMode, Mode };
1045
922
  }
1046
923
 
1047
924
  async setMinMax(): Promise<void> {
1048
925
  if (this.device.blindTilt?.set_min) {
1049
- if (Number(this.CurrentPosition) <= this.device.blindTilt?.set_min) {
1050
- this.CurrentPosition = 0;
926
+ if (Number(this.WindowCovering.CurrentPosition) <= this.device.blindTilt?.set_min) {
927
+ this.WindowCovering.CurrentPosition = 0;
1051
928
  }
1052
929
  }
1053
930
  if (this.device.blindTilt?.set_max) {
1054
- if (Number(this.CurrentPosition) >= this.device.blindTilt?.set_max) {
1055
- this.CurrentPosition = 100;
931
+ if (Number(this.WindowCovering.CurrentPosition) >= this.device.blindTilt?.set_max) {
932
+ this.WindowCovering.CurrentPosition = 100;
1056
933
  }
1057
934
  }
1058
935
 
1059
936
  if (this.mappingMode === BlindTiltMappingMode.UseTiltForDirection) {
1060
- this.CurrentHorizontalTiltAngle = Number(this.CurrentHorizontalTiltAngle) < 0 ? -90 : 90;
937
+ this.WindowCovering.CurrentHorizontalTiltAngle = Number(this.WindowCovering.CurrentHorizontalTiltAngle) < 0 ? -90 : 90;
1061
938
  }
1062
939
  }
1063
940
 
1064
- minStep(device: device & devicesConfig): number {
941
+ async minStep(device: device & devicesConfig): Promise<number> {
942
+ let set_minStep: number;
1065
943
  if (device.blindTilt?.set_minStep) {
1066
- this.set_minStep = device.blindTilt?.set_minStep;
944
+ set_minStep = device.blindTilt?.set_minStep;
1067
945
  } else {
1068
- this.set_minStep = 1;
946
+ set_minStep = 1;
1069
947
  }
1070
- return this.set_minStep;
948
+ return set_minStep;
1071
949
  }
1072
950
 
1073
- minLux(): number {
951
+ async minLux(): Promise<number> {
952
+ let set_minLux: number;
1074
953
  if (this.device.blindTilt?.set_minLux) {
1075
- this.set_minLux = this.device.blindTilt?.set_minLux;
954
+ set_minLux = this.device.blindTilt?.set_minLux;
1076
955
  } else {
1077
- this.set_minLux = 1;
956
+ set_minLux = 1;
1078
957
  }
1079
- return this.set_minLux;
958
+ return set_minLux;
1080
959
  }
1081
960
 
1082
- maxLux(): number {
961
+ async maxLux(): Promise<number> {
962
+ let set_maxLux: number;
1083
963
  if (this.device.blindTilt?.set_maxLux) {
1084
- this.set_maxLux = this.device.blindTilt?.set_maxLux;
964
+ set_maxLux = this.device.blindTilt?.set_maxLux;
1085
965
  } else {
1086
- this.set_maxLux = 6001;
1087
- }
1088
- return this.set_maxLux;
1089
- }
1090
-
1091
- async scan(device: device & devicesConfig): Promise<void> {
1092
- if (device.scanDuration) {
1093
- if (this.updateRate > device.scanDuration) {
1094
- this.scanDuration = this.updateRate;
1095
- if (this.BLE) {
1096
- this.warnLog(
1097
- `${this.device.deviceType}: ` +
1098
- `${this.accessory.displayName} scanDuration is less than updateRate, overriding scanDuration with updateRate`,
1099
- );
1100
- }
1101
- } else {
1102
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
1103
- }
1104
- if (this.BLE) {
1105
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
1106
- }
1107
- } else {
1108
- if (this.updateRate > 1) {
1109
- this.scanDuration = this.updateRate;
1110
- } else {
1111
- this.scanDuration = this.accessory.context.scanDuration = 1;
1112
- }
1113
- if (this.BLE) {
1114
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
1115
- }
1116
- }
1117
- }
1118
-
1119
- async statusCode(statusCode: number): Promise<void> {
1120
- switch (statusCode) {
1121
- case 151:
1122
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
1123
- break;
1124
- case 152:
1125
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
1126
- break;
1127
- case 160:
1128
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
1129
- break;
1130
- case 161:
1131
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
1132
- this.offlineOff();
1133
- break;
1134
- case 171:
1135
- this.errorLog(
1136
- `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` +
1137
- `Hub: ${this.device.hubDeviceId}`,
1138
- );
1139
- this.offlineOff();
1140
- break;
1141
- case 190:
1142
- this.errorLog(
1143
- `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
1144
- ` Or command format is invalid, statusCode: ${statusCode}`,
1145
- );
1146
- break;
1147
- case 100:
1148
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
1149
- break;
1150
- case 200:
1151
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
1152
- break;
1153
- case 400:
1154
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bad Request, The client has issued an invalid request. `
1155
- + `This is commonly used to specify validation errors in a request payload, statusCode: ${statusCode}`);
1156
- break;
1157
- case 401:
1158
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unauthorized, Authorization for the API is required, `
1159
- + `but the request has not been authenticated, statusCode: ${statusCode}`);
1160
- break;
1161
- case 403:
1162
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Forbidden, The request has been authenticated but does not `
1163
- + `have appropriate permissions, or a requested resource is not found, statusCode: ${statusCode}`);
1164
- break;
1165
- case 404:
1166
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Found, Specifies the requested path does not exist, `
1167
- + `statusCode: ${statusCode}`);
1168
- break;
1169
- case 406:
1170
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Acceptable, The client has requested a MIME type via `
1171
- + `the Accept header for a value not supported by the server, statusCode: ${statusCode}`);
1172
- break;
1173
- case 415:
1174
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unsupported Media Type, The client has defined a contentType `
1175
- + `header that is not supported by the server, statusCode: ${statusCode}`);
1176
- break;
1177
- case 422:
1178
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unprocessable Entity, The client has made a valid request, `
1179
- + `but the server cannot process it. This is often used for APIs for which certain limits have been exceeded, statusCode: ${statusCode}`);
1180
- break;
1181
- case 429:
1182
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Too Many Requests, The client has exceeded the number of `
1183
- + `requests allowed for a given time window, statusCode: ${statusCode}`);
1184
- break;
1185
- case 500:
1186
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Internal Server Error, An unexpected error on the SmartThings `
1187
- + `servers has occurred. These errors should be rare, statusCode: ${statusCode}`);
1188
- break;
1189
- default:
1190
- this.infoLog(
1191
- `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` +
1192
- `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`,
1193
- );
966
+ set_maxLux = 6001;
1194
967
  }
968
+ return set_maxLux;
1195
969
  }
1196
970
 
1197
971
  async offlineOff(): Promise<void> {
1198
972
  if (this.device.offline) {
1199
- await this.deviceContext();
1200
- await this.updateHomeKitCharacteristics();
973
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
974
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
975
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
976
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle, 90);
977
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle, 90);
1201
978
  }
1202
979
  }
1203
980
 
1204
981
  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);
982
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
983
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e);
984
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
985
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle, e);
986
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle, e);
987
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
988
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
989
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, e);
1208
990
  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;
991
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, e);
992
+ this.LightSensor!.Service.updateCharacteristic(this.hap.Characteristic.StatusActive, e);
1239
993
  }
1240
994
  }
1241
995
 
@@ -1358,130 +1112,4 @@ export class BlindTilt {
1358
1112
  }
1359
1113
  }
1360
1114
  }
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
1115
  }