@switchbot/homebridge-switchbot 3.7.1-beta.2 → 3.7.1-beta.21

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 (199) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +14 -0
  3. package/assets/security-privacy-bluetooth.png +0 -0
  4. package/config.schema.json +74 -2
  5. package/dist/device/blindtilt.d.ts +21 -9
  6. package/dist/device/blindtilt.d.ts.map +1 -1
  7. package/dist/device/blindtilt.js +167 -96
  8. package/dist/device/blindtilt.js.map +1 -1
  9. package/dist/device/bot-old.d.ts +132 -0
  10. package/dist/device/bot-old.d.ts.map +1 -0
  11. package/dist/device/bot-old.js +1482 -0
  12. package/dist/device/bot-old.js.map +1 -0
  13. package/dist/device/bot.d.ts +10 -9
  14. package/dist/device/bot.d.ts.map +1 -1
  15. package/dist/device/bot.js +186 -187
  16. package/dist/device/bot.js.map +1 -1
  17. package/dist/device/ceilinglight.d.ts +14 -13
  18. package/dist/device/ceilinglight.d.ts.map +1 -1
  19. package/dist/device/ceilinglight.js +87 -97
  20. package/dist/device/ceilinglight.js.map +1 -1
  21. package/dist/device/colorbulb.d.ts +13 -12
  22. package/dist/device/colorbulb.d.ts.map +1 -1
  23. package/dist/device/colorbulb.js +92 -105
  24. package/dist/device/colorbulb.js.map +1 -1
  25. package/dist/device/contact.d.ts +6 -5
  26. package/dist/device/contact.d.ts.map +1 -1
  27. package/dist/device/contact.js +71 -68
  28. package/dist/device/contact.js.map +1 -1
  29. package/dist/device/curtain.d.ts +17 -5
  30. package/dist/device/curtain.d.ts.map +1 -1
  31. package/dist/device/curtain.js +184 -118
  32. package/dist/device/curtain.js.map +1 -1
  33. package/dist/device/device.d.ts +18 -18
  34. package/dist/device/device.d.ts.map +1 -1
  35. package/dist/device/device.js +33 -36
  36. package/dist/device/device.js.map +1 -1
  37. package/dist/device/fan.d.ts +9 -8
  38. package/dist/device/fan.d.ts.map +1 -1
  39. package/dist/device/fan.js +94 -101
  40. package/dist/device/fan.js.map +1 -1
  41. package/dist/device/hub.d.ts +6 -5
  42. package/dist/device/hub.d.ts.map +1 -1
  43. package/dist/device/hub.js +69 -65
  44. package/dist/device/hub.js.map +1 -1
  45. package/dist/device/humidifier.d.ts +6 -5
  46. package/dist/device/humidifier.d.ts.map +1 -1
  47. package/dist/device/humidifier.js +89 -104
  48. package/dist/device/humidifier.js.map +1 -1
  49. package/dist/device/iosensor.d.ts +6 -5
  50. package/dist/device/iosensor.d.ts.map +1 -1
  51. package/dist/device/iosensor.js +72 -66
  52. package/dist/device/iosensor.js.map +1 -1
  53. package/dist/device/lightstrip.d.ts +7 -6
  54. package/dist/device/lightstrip.d.ts.map +1 -1
  55. package/dist/device/lightstrip.js +85 -99
  56. package/dist/device/lightstrip.js.map +1 -1
  57. package/dist/device/lock.d.ts +10 -9
  58. package/dist/device/lock.d.ts.map +1 -1
  59. package/dist/device/lock.js +89 -79
  60. package/dist/device/lock.js.map +1 -1
  61. package/dist/device/meter.d.ts +6 -5
  62. package/dist/device/meter.d.ts.map +1 -1
  63. package/dist/device/meter.js +72 -65
  64. package/dist/device/meter.js.map +1 -1
  65. package/dist/device/meterplus.d.ts +6 -5
  66. package/dist/device/meterplus.d.ts.map +1 -1
  67. package/dist/device/meterplus.js +72 -64
  68. package/dist/device/meterplus.js.map +1 -1
  69. package/dist/device/motion.d.ts +6 -5
  70. package/dist/device/motion.d.ts.map +1 -1
  71. package/dist/device/motion.js +65 -58
  72. package/dist/device/motion.js.map +1 -1
  73. package/dist/device/plug.d.ts +13 -12
  74. package/dist/device/plug.d.ts.map +1 -1
  75. package/dist/device/plug.js +68 -52
  76. package/dist/device/plug.js.map +1 -1
  77. package/dist/device/robotvacuumcleaner.d.ts +12 -11
  78. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  79. package/dist/device/robotvacuumcleaner.js +93 -82
  80. package/dist/device/robotvacuumcleaner.js.map +1 -1
  81. package/dist/device/waterdetector.d.ts +6 -5
  82. package/dist/device/waterdetector.d.ts.map +1 -1
  83. package/dist/device/waterdetector.js +73 -63
  84. package/dist/device/waterdetector.js.map +1 -1
  85. package/dist/homebridge-ui/server.js +2 -2
  86. package/dist/homebridge-ui/server.js.map +1 -1
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +0 -4
  89. package/dist/index.js.map +1 -1
  90. package/dist/irdevice/airconditioner.d.ts +8 -8
  91. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  92. package/dist/irdevice/airconditioner.js +61 -105
  93. package/dist/irdevice/airconditioner.js.map +1 -1
  94. package/dist/irdevice/airpurifier.d.ts +10 -10
  95. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  96. package/dist/irdevice/airpurifier.js +22 -42
  97. package/dist/irdevice/airpurifier.js.map +1 -1
  98. package/dist/irdevice/camera.d.ts +9 -9
  99. package/dist/irdevice/camera.d.ts.map +1 -1
  100. package/dist/irdevice/camera.js +15 -25
  101. package/dist/irdevice/camera.js.map +1 -1
  102. package/dist/irdevice/fan.d.ts +8 -8
  103. package/dist/irdevice/fan.d.ts.map +1 -1
  104. package/dist/irdevice/fan.js +21 -40
  105. package/dist/irdevice/fan.js.map +1 -1
  106. package/dist/irdevice/irdevice.d.ts +11 -11
  107. package/dist/irdevice/irdevice.d.ts.map +1 -1
  108. package/dist/irdevice/irdevice.js +14 -22
  109. package/dist/irdevice/irdevice.js.map +1 -1
  110. package/dist/irdevice/light.d.ts +9 -9
  111. package/dist/irdevice/light.d.ts.map +1 -1
  112. package/dist/irdevice/light.js +24 -47
  113. package/dist/irdevice/light.js.map +1 -1
  114. package/dist/irdevice/other.d.ts +9 -9
  115. package/dist/irdevice/other.d.ts.map +1 -1
  116. package/dist/irdevice/other.js +40 -83
  117. package/dist/irdevice/other.js.map +1 -1
  118. package/dist/irdevice/tv.d.ts +9 -9
  119. package/dist/irdevice/tv.d.ts.map +1 -1
  120. package/dist/irdevice/tv.js +29 -54
  121. package/dist/irdevice/tv.js.map +1 -1
  122. package/dist/irdevice/vacuumcleaner.d.ts +5 -5
  123. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  124. package/dist/irdevice/vacuumcleaner.js +11 -21
  125. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  126. package/dist/irdevice/waterheater.d.ts +5 -5
  127. package/dist/irdevice/waterheater.d.ts.map +1 -1
  128. package/dist/irdevice/waterheater.js +11 -22
  129. package/dist/irdevice/waterheater.js.map +1 -1
  130. package/dist/platform.d.ts +24 -23
  131. package/dist/platform.d.ts.map +1 -1
  132. package/dist/platform.js +509 -723
  133. package/dist/platform.js.map +1 -1
  134. package/dist/settings.d.ts +5 -2
  135. package/dist/settings.d.ts.map +1 -1
  136. package/dist/settings.js.map +1 -1
  137. package/dist/types/bledevicestatus.d.ts +9 -9
  138. package/dist/types/bledevicestatus.d.ts.map +1 -1
  139. package/dist/types/devicelist.d.ts +6 -6
  140. package/dist/types/devicelist.d.ts.map +1 -1
  141. package/dist/types/deviceresponse.d.ts +4 -4
  142. package/dist/types/deviceresponse.d.ts.map +1 -1
  143. package/dist/types/devicestatus.d.ts +2 -2
  144. package/dist/types/devicestatus.d.ts.map +1 -1
  145. package/dist/types/devicewebhookstatus.d.ts +5 -5
  146. package/dist/types/devicewebhookstatus.d.ts.map +1 -1
  147. package/dist/types/irdevicelist.d.ts +4 -4
  148. package/dist/types/irdevicelist.d.ts.map +1 -1
  149. package/dist/types/pushbody.d.ts +2 -2
  150. package/dist/types/pushbody.d.ts.map +1 -1
  151. package/dist/utils.d.ts +4 -4
  152. package/dist/utils.d.ts.map +1 -1
  153. package/dist/utils.js +9 -13
  154. package/dist/utils.js.map +1 -1
  155. package/eslint.config.js +48 -93
  156. package/package.json +64 -57
  157. package/src/device/blindtilt.ts +537 -456
  158. package/src/device/bot-old.ts +1540 -0
  159. package/src/device/bot.ts +732 -725
  160. package/src/device/ceilinglight.ts +359 -368
  161. package/src/device/colorbulb.ts +441 -453
  162. package/src/device/contact.ts +229 -226
  163. package/src/device/curtain.ts +526 -444
  164. package/src/device/device.ts +206 -208
  165. package/src/device/fan.ts +336 -345
  166. package/src/device/hub.ts +213 -214
  167. package/src/device/humidifier.ts +326 -347
  168. package/src/device/iosensor.ts +211 -209
  169. package/src/device/lightstrip.ts +391 -404
  170. package/src/device/lock.ts +292 -282
  171. package/src/device/meter.ts +212 -210
  172. package/src/device/meterplus.ts +212 -209
  173. package/src/device/motion.ts +198 -190
  174. package/src/device/plug.ts +203 -182
  175. package/src/device/robotvacuumcleaner.ts +280 -269
  176. package/src/device/waterdetector.ts +198 -189
  177. package/src/homebridge-ui/server.ts +16 -15
  178. package/src/index.ts +5 -6
  179. package/src/irdevice/airconditioner.ts +277 -326
  180. package/src/irdevice/airpurifier.ts +124 -143
  181. package/src/irdevice/camera.ts +58 -64
  182. package/src/irdevice/fan.ts +106 -123
  183. package/src/irdevice/irdevice.ts +116 -119
  184. package/src/irdevice/light.ts +119 -143
  185. package/src/irdevice/other.ts +417 -461
  186. package/src/irdevice/tv.ts +155 -177
  187. package/src/irdevice/vacuumcleaner.ts +54 -60
  188. package/src/irdevice/waterheater.ts +56 -63
  189. package/src/platform.ts +1491 -1681
  190. package/src/settings.ts +172 -169
  191. package/src/types/bledevicestatus.ts +252 -256
  192. package/src/types/devicelist.ts +79 -79
  193. package/src/types/deviceresponse.ts +12 -13
  194. package/src/types/devicestatus.ts +124 -124
  195. package/src/types/devicewebhookstatus.ts +126 -131
  196. package/src/types/irdevicelist.ts +10 -10
  197. package/src/types/pushbody.ts +5 -5
  198. package/src/utils.ts +64 -65
  199. package/tsconfig.json +10 -9
@@ -1,21 +1,23 @@
1
- /* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
- *
3
- * blindtilt.ts: @switchbot/homebridge-switchbot.
4
- */
5
- import { deviceBase } from './device.js';
6
- import { BlindTiltMappingMode } from '../utils.js';
1
+ /*
2
+ * For Testing Locally:
3
+ * import { SwitchBotBLEModel, SwitchBotBLEModelName } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
4
+ */
7
5
  import { SwitchBotBLEModel, SwitchBotBLEModelName } from 'node-switchbot';
8
- import { Subject, debounceTime, interval, skipWhile, take, tap } from 'rxjs';
6
+ import { debounceTime, interval, skipWhile, Subject, take, tap } from 'rxjs';
7
+ import { BlindTiltMappingMode } from '../utils.js';
8
+ import { deviceBase } from './device.js';
9
9
  export class BlindTilt extends deviceBase {
10
10
  platform;
11
11
  // Services
12
12
  WindowCovering;
13
13
  Battery;
14
14
  LightSensor;
15
+ OpenModeSwitch;
16
+ CloseModeSwitch;
15
17
  // OpenAPI
16
18
  deviceStatus;
17
19
  mappingMode = BlindTiltMappingMode.OnlyUp;
18
- //Webhook
20
+ // Webhook
19
21
  webhookContext;
20
22
  // BLE
21
23
  serviceData;
@@ -23,6 +25,7 @@ export class BlindTilt extends deviceBase {
23
25
  setNewTarget;
24
26
  setNewTargetTimer;
25
27
  // Updates
28
+ blindTiltMoving;
26
29
  blindTiltUpdateInProgress;
27
30
  doBlindTiltUpdate;
28
31
  constructor(platform, accessory, device) {
@@ -35,6 +38,7 @@ export class BlindTilt extends deviceBase {
35
38
  this.debugLog(`Mapping mode: ${this.mappingMode}`);
36
39
  // this is subject we use to track when we need to POST changes to the SwitchBot API
37
40
  this.doBlindTiltUpdate = new Subject();
41
+ this.blindTiltMoving = false;
38
42
  this.blindTiltUpdateInProgress = false;
39
43
  this.setNewTarget = false;
40
44
  // Initialize WindowCovering Service
@@ -50,23 +54,16 @@ export class BlindTilt extends deviceBase {
50
54
  };
51
55
  accessory.context.WindowCovering = this.WindowCovering;
52
56
  // Initialize WindowCovering Characteristics
53
- this.WindowCovering.Service
54
- .setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name)
55
- .getCharacteristic(this.hap.Characteristic.TargetPosition)
56
- .setProps({
57
+ this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name).getCharacteristic(this.hap.Characteristic.TargetPosition).setProps({
57
58
  minStep: device.blindTilt?.set_minStep ?? 1,
58
59
  minValue: 0,
59
60
  maxValue: 100,
60
61
  validValueRanges: [0, 100],
61
- })
62
- .onGet(() => {
62
+ }).onGet(() => {
63
63
  return this.WindowCovering.TargetPosition;
64
- })
65
- .onSet(this.TargetPositionSet.bind(this));
64
+ }).onSet(this.TargetPositionSet.bind(this));
66
65
  // Initialize WindowCovering CurrentPosition Characteristic
67
- this.WindowCovering.Service
68
- .getCharacteristic(this.hap.Characteristic.CurrentPosition)
69
- .setProps({
66
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.CurrentPosition).setProps({
70
67
  minStep: device.blindTilt?.set_minStep ?? 1,
71
68
  minValue: 0,
72
69
  maxValue: 100,
@@ -75,22 +72,16 @@ export class BlindTilt extends deviceBase {
75
72
  return this.WindowCovering.CurrentPosition ?? 0;
76
73
  });
77
74
  // Initialize WindowCovering TargetHorizontalTiltAngle Characteristic
78
- this.WindowCovering.Service
79
- .getCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle)
80
- .setProps({
75
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.TargetHorizontalTiltAngle).setProps({
81
76
  minStep: 180,
82
77
  minValue: -90,
83
78
  maxValue: 90,
84
79
  validValues: [-90, 90],
85
- })
86
- .onGet(() => {
80
+ }).onGet(() => {
87
81
  return this.WindowCovering.TargetHorizontalTiltAngle;
88
- })
89
- .onSet(this.TargetHorizontalTiltAngleSet.bind(this));
82
+ }).onSet(this.TargetHorizontalTiltAngleSet.bind(this));
90
83
  // Initialize WindowCovering CurrentHorizontalTiltAngle Characteristic
91
- this.WindowCovering.Service
92
- .getCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle)
93
- .setProps({
84
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.CurrentHorizontalTiltAngle).setProps({
94
85
  minStep: 180,
95
86
  minValue: -90,
96
87
  maxValue: 90,
@@ -109,9 +100,7 @@ export class BlindTilt extends deviceBase {
109
100
  };
110
101
  accessory.context.Battery = this.Battery;
111
102
  // Initialize Battery Name Characteristic
112
- this.Battery.Service
113
- .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
114
- .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
103
+ this.Battery.Service.setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name).setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
115
104
  // Initialize LightSensor Service
116
105
  if (device.blindTilt?.hide_lightsensor) {
117
106
  if (this.LightSensor?.Service) {
@@ -133,20 +122,80 @@ export class BlindTilt extends deviceBase {
133
122
  };
134
123
  accessory.context.LightSensor = this.LightSensor;
135
124
  // Initialize LightSensor Characteristics
136
- this.LightSensor.Service
137
- .setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name)
138
- .setCharacteristic(this.hap.Characteristic.StatusActive, true)
139
- .getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel)
140
- .onGet(() => {
125
+ this.LightSensor.Service.setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name).setCharacteristic(this.hap.Characteristic.StatusActive, true).getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel).onGet(() => {
141
126
  return this.LightSensor?.CurrentAmbientLightLevel ?? 0.0001;
142
127
  });
143
128
  }
129
+ // Initialize Open Mode Switch Service
130
+ if (!device.blindTilt?.silentModeSwitch) {
131
+ if (this.OpenModeSwitch?.Service) {
132
+ this.debugLog('Removing Open Mode Switch Service');
133
+ this.OpenModeSwitch.Service = this.accessory.getService(this.hap.Service.Switch);
134
+ accessory.removeService(this.OpenModeSwitch.Service);
135
+ accessory.context.OpenModeSwitch = {};
136
+ }
137
+ }
138
+ else {
139
+ accessory.context.OpenModeSwitch = accessory.context.OpenModeSwitch ?? {};
140
+ this.OpenModeSwitch = {
141
+ Name: `${accessory.displayName} Silent Open Mode`,
142
+ Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch),
143
+ On: accessory.context.OpenModeSwitch.On ?? false,
144
+ };
145
+ accessory.context.OpenModeSwitch = this.OpenModeSwitch;
146
+ // Initialize Open Mode Switch Service
147
+ this.OpenModeSwitch.Service.setCharacteristic(this.hap.Characteristic.Name, this.OpenModeSwitch.Name).getCharacteristic(this.hap.Characteristic.On).onGet(() => {
148
+ return this.OpenModeSwitch?.On ?? false;
149
+ });
150
+ this.OpenModeSwitch.Service.getCharacteristic(this.hap.Characteristic.On).onSet(this.OpenModeSwitchSet.bind(this));
151
+ }
152
+ // Initialize Close Mode Switch Service
153
+ if (!device.blindTilt?.silentModeSwitch) {
154
+ if (this.CloseModeSwitch?.Service) {
155
+ this.debugLog('Removing Close Mode Switch Service');
156
+ this.CloseModeSwitch.Service = this.accessory.getService(this.hap.Service.Switch);
157
+ accessory.removeService(this.CloseModeSwitch.Service);
158
+ accessory.context.CloseModeSwitch = {};
159
+ }
160
+ }
161
+ else {
162
+ accessory.context.CloseModeSwitch = accessory.context.CloseModeSwitch ?? {};
163
+ this.CloseModeSwitch = {
164
+ Name: `${accessory.displayName} Silent Close Mode`,
165
+ Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch),
166
+ On: accessory.context.CloseModeSwitch.On ?? false,
167
+ };
168
+ accessory.context.CloseModeSwitch = this.CloseModeSwitch;
169
+ // Initialize Close Mode Switch Service
170
+ this.CloseModeSwitch.Service.setCharacteristic(this.hap.Characteristic.Name, this.CloseModeSwitch.Name).getCharacteristic(this.hap.Characteristic.On).onGet(() => {
171
+ return this.CloseModeSwitch?.On ?? false;
172
+ });
173
+ this.CloseModeSwitch.Service.getCharacteristic(this.hap.Characteristic.On).onSet(this.CloseModeSwitchSet.bind(this));
174
+ }
144
175
  // Retrieve initial values and updateHomekit
145
- this.debugLog('Retrieve initial values and update Homekit');
146
- this.refreshStatus();
147
- //regisiter webhook event handler
148
- this.debugLog('Registering Webhook Event Handler');
149
- this.registerWebhook();
176
+ try {
177
+ this.debugLog('Retrieve initial values and update Homekit');
178
+ this.refreshStatus();
179
+ }
180
+ catch (e) {
181
+ this.errorLog(`failed to retrieve initial values and update Homekit, Error: ${e}`);
182
+ }
183
+ // regisiter webhook event handler if enabled
184
+ try {
185
+ this.debugLog('Registering Webhook Event Handler');
186
+ this.registerWebhook();
187
+ }
188
+ catch (e) {
189
+ this.errorLog(`failed to registerWebhook, Error: ${e}`);
190
+ }
191
+ // regisiter platform BLE event handler if enabled
192
+ try {
193
+ this.debugLog('Registering Platform BLE Event Handler');
194
+ this.registerPlatformBLE();
195
+ }
196
+ catch (e) {
197
+ this.errorLog(`failed to registerPlatformBLE, Error: ${e}`);
198
+ }
150
199
  // Start an update interval
151
200
  interval(this.deviceRefreshRate * 1000)
152
201
  .pipe(skipWhile(() => this.blindTiltUpdateInProgress))
@@ -155,6 +204,7 @@ export class BlindTilt extends deviceBase {
155
204
  });
156
205
  // update slide progress
157
206
  interval(this.deviceUpdateRate * 1000)
207
+ .pipe(skipWhile(() => !this.blindTiltMoving))
158
208
  .subscribe(async () => {
159
209
  if (this.WindowCovering.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
160
210
  return;
@@ -184,9 +234,7 @@ export class BlindTilt extends deviceBase {
184
234
  */
185
235
  async BLEparseStatus() {
186
236
  await this.debugLog('BLEparseStatus');
187
- await this.debugLog(`(direction, slidePosition, battery, version) = BLE:(${this.serviceData.tilt}, ${this.serviceData.tilt},`
188
- + ` ${this.serviceData.battery}, ${this.accessory.context.version}), current:(${this.WindowCovering.CurrentHorizontalTiltAngle},`
189
- + ` ${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel}, ${this.accessory.context.version})`);
237
+ await this.debugLog(`(direction, slidePosition, battery, version) = BLE:(${this.serviceData.tilt}, ${this.serviceData.tilt}, ${this.serviceData.battery}, ${this.accessory.context.version}), current:(${this.WindowCovering.CurrentHorizontalTiltAngle}, ${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel}, ${this.accessory.context.version})`);
190
238
  // CurrentPosition
191
239
  this.WindowCovering.CurrentPosition = 100 - Number(this.serviceData.tilt);
192
240
  await this.setMinMax();
@@ -195,6 +243,7 @@ export class BlindTilt extends deviceBase {
195
243
  await this.infoLog('Checking Status ...');
196
244
  }
197
245
  if (this.setNewTarget && this.serviceData.inMotion) {
246
+ this.blindTiltMoving = true;
198
247
  await this.setMinMax();
199
248
  if (Number(this.WindowCovering.TargetPosition) > this.WindowCovering.CurrentPosition) {
200
249
  await this.debugLog(`Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
@@ -216,13 +265,13 @@ export class BlindTilt extends deviceBase {
216
265
  }
217
266
  }
218
267
  else {
268
+ this.blindTiltMoving = false;
219
269
  await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
220
270
  this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
221
271
  this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
222
272
  await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`);
223
273
  }
224
- await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition},`
225
- + ` PositionState: ${this.WindowCovering.PositionState}`);
274
+ await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState}`);
226
275
  // CurrentAmbientLightLevel
227
276
  if (!this.device.blindTilt?.hide_lightsensor && this.LightSensor?.Service) {
228
277
  const set_minLux = this.device.blindTilt?.set_minLux ?? 1;
@@ -236,7 +285,8 @@ export class BlindTilt extends deviceBase {
236
285
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
237
286
  // StatusLowBattery
238
287
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
239
- ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
288
+ ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW
289
+ : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
240
290
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
241
291
  }
242
292
  ;
@@ -245,9 +295,7 @@ export class BlindTilt extends deviceBase {
245
295
  */
246
296
  async openAPIparseStatus() {
247
297
  await this.debugLog('openAPIparseStatus');
248
- await this.debugLog(`(direction, slidePosition, battery, version) = OpenAPI:(${this.deviceStatus.direction}, ${this.deviceStatus.slidePosition},`
249
- + ` ${this.deviceStatus.battery}, ${this.deviceStatus.version}), current:(${this.WindowCovering.CurrentHorizontalTiltAngle},`
250
- + ` ${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel}, ${this.accessory.context.version})`);
298
+ await this.debugLog(`(direction, slidePosition, battery, version) = OpenAPI:(${this.deviceStatus.direction}, ${this.deviceStatus.slidePosition}, ${this.deviceStatus.battery}, ${this.deviceStatus.version}), current:(${this.WindowCovering.CurrentHorizontalTiltAngle}, ${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel}, ${this.accessory.context.version})`);
251
299
  // CurrentPosition
252
300
  await this.getCurrentPosttionDirection(this.deviceStatus.direction, this.deviceStatus.slidePosition);
253
301
  if (!this.device.blindTilt?.hide_lightsensor && this.LightSensor?.Service) {
@@ -262,7 +310,8 @@ export class BlindTilt extends deviceBase {
262
310
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
263
311
  // StatusLowBattery
264
312
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
265
- ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
313
+ ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW
314
+ : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
266
315
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
267
316
  // Firmware Version
268
317
  const version = this.deviceStatus.version.toString();
@@ -270,7 +319,7 @@ export class BlindTilt extends deviceBase {
270
319
  let deviceVersion;
271
320
  if (version?.includes('.') === false) {
272
321
  const replace = version?.replace(/^V|-.*$/g, '');
273
- const match = replace?.match(/.{1,1}/g);
322
+ const match = replace?.match(/./g);
274
323
  const blindTiltVersion = match?.join('.') ?? '0.0.0';
275
324
  deviceVersion = blindTiltVersion;
276
325
  }
@@ -288,9 +337,7 @@ export class BlindTilt extends deviceBase {
288
337
  }
289
338
  async parseStatusWebhook() {
290
339
  await this.debugLog('parseStatusWebhook');
291
- await this.debugLog(`(slidePosition, battery, version) = Webhook:(${this.webhookContext.direction}, ${this.webhookContext.slidePosition},`
292
- + ` ${this.webhookContext.battery}, ${this.webhookContext.version}, current:(${this.WindowCovering.CurrentHorizontalTiltAngle},`
293
- + ` ${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel}, ${this.accessory.context.version})`);
340
+ await this.debugLog(`(slidePosition, battery, version) = Webhook:(${this.webhookContext.direction}, ${this.webhookContext.slidePosition}, ${this.webhookContext.battery}, ${this.webhookContext.version}, current:(${this.WindowCovering.CurrentHorizontalTiltAngle}, ${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel}, ${this.accessory.context.version})`);
294
341
  // CurrentPosition and CurrentHorizontalTiltAngle
295
342
  await this.getCurrentPosttionDirection(this.webhookContext.direction, this.webhookContext.slidePosition);
296
343
  // BatteryLevel
@@ -298,7 +345,8 @@ export class BlindTilt extends deviceBase {
298
345
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
299
346
  // StatusLowBattery
300
347
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
301
- ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
348
+ ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW
349
+ : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
302
350
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
303
351
  // Firmware Version
304
352
  const deviceVersion = this.webhookContext.version.replace(/^V|-.*$/g, '') ?? '0.0.0';
@@ -318,7 +366,7 @@ export class BlindTilt extends deviceBase {
318
366
  if (!this.device.enableCloudService && this.OpenAPI) {
319
367
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
320
368
  }
321
- else if (this.BLE || this.config.options?.BLE) {
369
+ else if (this.BLE) {
322
370
  await this.BLERefreshStatus();
323
371
  }
324
372
  else if (this.OpenAPI && this.platform.config.credentials?.token) {
@@ -330,6 +378,31 @@ export class BlindTilt extends deviceBase {
330
378
  }
331
379
  }
332
380
  async BLERefreshStatus() {
381
+ await this.debugLog('BLERefreshStatus');
382
+ const switchbot = await this.switchbotBLE();
383
+ if (switchbot === undefined) {
384
+ await this.BLERefreshConnection(switchbot);
385
+ }
386
+ else {
387
+ // Start to monitor advertisement packets
388
+ (async () => {
389
+ // Start to monitor advertisement packets
390
+ const serviceData = await this.monitorAdvertisementPackets(switchbot);
391
+ // Update HomeKit
392
+ if (serviceData.model === SwitchBotBLEModel.BlindTilt && serviceData.modelName === SwitchBotBLEModelName.BlindTilt) {
393
+ this.serviceData = serviceData;
394
+ await this.BLEparseStatus();
395
+ await this.updateHomeKitCharacteristics();
396
+ }
397
+ else {
398
+ await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`);
399
+ await this.BLERefreshConnection(switchbot);
400
+ }
401
+ })();
402
+ }
403
+ }
404
+ async registerPlatformBLE() {
405
+ await this.debugLog('registerPlatformBLE');
333
406
  if (this.config.options?.BLE) {
334
407
  await this.debugLog('is listening to Platform BLE.');
335
408
  this.device.bleMac = this.device.deviceId.match(/.{1,2}/g).join(':').toLowerCase();
@@ -347,28 +420,7 @@ export class BlindTilt extends deviceBase {
347
420
  };
348
421
  }
349
422
  else {
350
- await this.debugLog('is using Device BLE Scanning.');
351
- const switchbot = await this.switchbotBLE();
352
- if (switchbot === undefined) {
353
- await this.BLERefreshConnection(switchbot);
354
- }
355
- else {
356
- // Start to monitor advertisement packets
357
- (async () => {
358
- // Start to monitor advertisement packets
359
- const serviceData = await this.monitorAdvertisementPackets(switchbot);
360
- // Update HomeKit
361
- if (serviceData.model === SwitchBotBLEModel.BlindTilt && serviceData.modelName === SwitchBotBLEModelName.BlindTilt) {
362
- this.serviceData = serviceData;
363
- await this.BLEparseStatus();
364
- await this.updateHomeKitCharacteristics();
365
- }
366
- else {
367
- await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`);
368
- await this.BLERefreshConnection(switchbot);
369
- }
370
- })();
371
- }
423
+ await this.debugLog('is not listening to Platform BLE');
372
424
  }
373
425
  }
374
426
  async openAPIRefreshStatus() {
@@ -377,7 +429,6 @@ export class BlindTilt extends deviceBase {
377
429
  const { body, statusCode } = await this.deviceRefreshStatus();
378
430
  const deviceStatus = await body.json();
379
431
  await this.debugLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
380
- ;
381
432
  if (await this.successfulStatusCodes(statusCode, deviceStatus)) {
382
433
  await this.debugSuccessLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
383
434
  this.deviceStatus = deviceStatus.body;
@@ -470,8 +521,7 @@ export class BlindTilt extends deviceBase {
470
521
  }
471
522
  }
472
523
  else {
473
- await this.debugLog(`No changes (BLEpushChanges), TargetPosition: ${this.WindowCovering.TargetPosition},`
474
- + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
524
+ await this.debugLog(`No changes (BLEpushChanges), TargetPosition: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
475
525
  }
476
526
  }
477
527
  async openAPIpushChanges() {
@@ -526,10 +576,8 @@ export class BlindTilt extends deviceBase {
526
576
  }
527
577
  }
528
578
  else {
529
- await this.debugLog(`No changes (openAPIpushChanges), TargetPosition: ${this.WindowCovering.TargetPosition},`
530
- + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
531
- await this.debugLog(`No changes (openAPIpushChanges), TargetHorizontalTiltAngle: ${this.WindowCovering.TargetHorizontalTiltAngle},`
532
- + ` CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
579
+ await this.debugLog(`No changes (openAPIpushChanges), TargetPosition: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
580
+ await this.debugLog(`No changes (openAPIpushChanges), TargetHorizontalTiltAngle: ${this.WindowCovering.TargetHorizontalTiltAngle}, CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
533
581
  }
534
582
  }
535
583
  /**
@@ -542,7 +590,7 @@ export class BlindTilt extends deviceBase {
542
590
  else {
543
591
  await this.debugLog(`No changes, TargetHorizontalTiltAngle: ${value}`);
544
592
  }
545
- //value = value < 0 ? -90 : 90;
593
+ // value = value < 0 ? -90 : 90;
546
594
  this.WindowCovering.TargetHorizontalTiltAngle = value;
547
595
  await this.mqtt('TargetHorizontalTiltAngle', this.WindowCovering.TargetHorizontalTiltAngle);
548
596
  await this.startUpdatingBlindTiltIfNeeded();
@@ -596,6 +644,28 @@ export class BlindTilt extends deviceBase {
596
644
  }
597
645
  this.doBlindTiltUpdate.next();
598
646
  }
647
+ /**
648
+ * Handle requests to set the value of the "Target Position" characteristic
649
+ */
650
+ async OpenModeSwitchSet(value) {
651
+ if (this.OpenModeSwitch && this.device.blindTilt?.silentModeSwitch) {
652
+ this.debugLog(`Silent Open Mode: ${value}`);
653
+ this.OpenModeSwitch.On = value;
654
+ this.accessory.context.OpenModeSwitch.On = value;
655
+ this.doBlindTiltUpdate.next();
656
+ }
657
+ }
658
+ /**
659
+ * Handle requests to set the value of the "Target Position" characteristic
660
+ */
661
+ async CloseModeSwitchSet(value) {
662
+ if (this.CloseModeSwitch && this.device.blindTilt?.silentModeSwitch) {
663
+ this.debugLog(`Silent Close Mode: ${value}`);
664
+ this.CloseModeSwitch.On = value;
665
+ this.accessory.context.CloseModeSwitch.On = value;
666
+ this.doBlindTiltUpdate.next();
667
+ }
668
+ }
599
669
  async updateHomeKitCharacteristics() {
600
670
  await this.setMinMax();
601
671
  // CurrentHorizontalTiltAngle
@@ -637,11 +707,11 @@ export class BlindTilt extends deviceBase {
637
707
  let setPositionMode;
638
708
  let Mode;
639
709
  if (Number(this.WindowCovering.TargetPosition) > 50) {
640
- if (this.device.blindTilt?.setOpenMode === '1') {
710
+ if (this.device.blindTilt?.setOpenMode === '1' || this.OpenModeSwitch?.On) {
641
711
  setPositionMode = 1;
642
712
  Mode = 'Silent Mode';
643
713
  }
644
- else if (this.device.blindTilt?.setOpenMode === '0') {
714
+ else if (this.device.blindTilt?.setOpenMode === '0' || !this.OpenModeSwitch?.On) {
645
715
  setPositionMode = 0;
646
716
  Mode = 'Performance Mode';
647
717
  }
@@ -651,11 +721,11 @@ export class BlindTilt extends deviceBase {
651
721
  }
652
722
  }
653
723
  else {
654
- if (this.device.blindTilt?.setCloseMode === '1') {
724
+ if (this.device.blindTilt?.setCloseMode === '1' || this.CloseModeSwitch?.On) {
655
725
  setPositionMode = 1;
656
726
  Mode = 'Silent Mode';
657
727
  }
658
- else if (this.device.blindTilt?.setOpenMode === '0') {
728
+ else if (this.device.blindTilt?.setOpenMode === '0' || !this.CloseModeSwitch?.On) {
659
729
  setPositionMode = 0;
660
730
  Mode = 'Performance Mode';
661
731
  }
@@ -721,6 +791,7 @@ export class BlindTilt extends deviceBase {
721
791
  await this.debugLog(`CurrentHorizontalTiltAngle: ${this.WindowCovering.CurrentHorizontalTiltAngle}`);
722
792
  }
723
793
  if (this.setNewTarget) {
794
+ this.blindTiltMoving = true;
724
795
  await this.infoLog('Checking Status ...');
725
796
  await this.setMinMax();
726
797
  if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition
@@ -744,6 +815,7 @@ export class BlindTilt extends deviceBase {
744
815
  }
745
816
  }
746
817
  else {
818
+ this.blindTiltMoving = false;
747
819
  await this.debugLog(`Standby because device not moving, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
748
820
  this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
749
821
  if (homekitTiltAngle) {
@@ -752,14 +824,13 @@ export class BlindTilt extends deviceBase {
752
824
  this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
753
825
  await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`);
754
826
  }
755
- await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition},`
756
- + ` PositionState: ${this.WindowCovering.PositionState}`);
827
+ await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState}`);
757
828
  }
758
829
  /**
759
830
  * Maps device values to homekit values
760
831
  *
761
832
  * @param devicePosition the position as reported by the devide
762
- * @param direction the direction as reported by the device
833
+ * @param deviceDirection the direction as reported by the device
763
834
  * @returns [homekit position, homekit tiltAngle]
764
835
  */
765
836
  mapDeviceValuesToHomekitValues(devicePosition, deviceDirection) {
@@ -812,7 +883,7 @@ export class BlindTilt extends deviceBase {
812
883
  * Maps homekit values to device values
813
884
  *
814
885
  * @param homekitPosition the position as reported by homekit
815
- * @param homekitTiltAngle? the tilt angle as reported by homekit
886
+ * @param homekitTiltAngle the tilt angle as reported by homekit
816
887
  * @returns [device position, device direction]
817
888
  */
818
889
  mapHomekitValuesToDeviceValues(homekitPosition, homekitTiltAngle) {