@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
@@ -2,77 +2,98 @@
2
2
  *
3
3
  * curtain.ts: @switchbot/homebridge-switchbot.
4
4
  */
5
- import { hostname } from 'os';
6
- import { deviceBase } from './device.js';
7
- import { SwitchBotBLEModel, SwitchBotBLEModelName } from 'node-switchbot';
8
- import { Subject, debounceTime, interval, skipWhile, take, tap } from 'rxjs';
9
-
10
- import type { devicesConfig } from '../settings.js';
11
- import type { device } from '../types/devicelist.js';
12
- import type { SwitchBotPlatform } from '../platform.js';
13
- import type { curtainStatus } from '../types/devicestatus.js';
14
- import type { curtainServiceData, curtain3ServiceData } from '../types/bledevicestatus.js';
15
- import type { curtain3WebhookContext, curtainWebhookContext } from '../types/devicewebhookstatus.js';
16
- import type { Service, PlatformAccessory, CharacteristicValue, CharacteristicChange } from 'homebridge';
5
+ import type { CharacteristicChange, CharacteristicValue, PlatformAccessory, Service } from 'homebridge'
6
+
7
+ import type { SwitchBotPlatform } from '../platform.js'
8
+ import type { devicesConfig } from '../settings.js'
9
+ import type { curtain3ServiceData, curtainServiceData } from '../types/bledevicestatus.js'
10
+ import type { device } from '../types/devicelist.js'
11
+ import type { curtainStatus } from '../types/devicestatus.js'
12
+ import type { curtain3WebhookContext, curtainWebhookContext } from '../types/devicewebhookstatus.js'
13
+
14
+ import { hostname } from 'node:os'
15
+
16
+ /*
17
+ * For Testing Locally:
18
+ * import { SwitchBotBLEModel, SwitchBotBLEModelName } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
19
+ */
20
+ import { SwitchBotBLEModel, SwitchBotBLEModelName } from 'node-switchbot'
21
+ import { debounceTime, interval, skipWhile, Subject, take, tap } from 'rxjs'
22
+
23
+ import { deviceBase } from './device.js'
17
24
 
18
25
  export class Curtain extends deviceBase {
19
26
  // Services
20
27
  private WindowCovering: {
21
- Name: CharacteristicValue;
22
- Service: Service;
23
- PositionState: CharacteristicValue;
24
- TargetPosition: CharacteristicValue;
25
- CurrentPosition: CharacteristicValue;
26
- HoldPosition: CharacteristicValue;
27
- };
28
+ Name: CharacteristicValue
29
+ Service: Service
30
+ PositionState: CharacteristicValue
31
+ TargetPosition: CharacteristicValue
32
+ CurrentPosition: CharacteristicValue
33
+ HoldPosition: CharacteristicValue
34
+ }
28
35
 
29
36
  private Battery: {
30
- Name: CharacteristicValue;
31
- Service: Service;
32
- BatteryLevel: CharacteristicValue;
33
- StatusLowBattery: CharacteristicValue;
34
- ChargingState: CharacteristicValue;
35
- };
37
+ Name: CharacteristicValue
38
+ Service: Service
39
+ BatteryLevel: CharacteristicValue
40
+ StatusLowBattery: CharacteristicValue
41
+ ChargingState: CharacteristicValue
42
+ }
36
43
 
37
44
  private LightSensor?: {
38
- Name: CharacteristicValue;
39
- Service: Service;
40
- CurrentAmbientLightLevel?: CharacteristicValue;
41
- };
45
+ Name: CharacteristicValue
46
+ Service: Service
47
+ CurrentAmbientLightLevel?: CharacteristicValue
48
+ }
49
+
50
+ private OpenModeSwitch?: {
51
+ Name: CharacteristicValue
52
+ Service: Service
53
+ On: CharacteristicValue
54
+ }
55
+
56
+ private CloseModeSwitch?: {
57
+ Name: CharacteristicValue
58
+ Service: Service
59
+ On: CharacteristicValue
60
+ }
42
61
 
43
62
  // OpenAPI
44
- deviceStatus!: curtainStatus;
63
+ deviceStatus!: curtainStatus
45
64
 
46
- //Webhook
47
- webhookContext!: curtainWebhookContext | curtain3WebhookContext;
65
+ // Webhook
66
+ webhookContext!: curtainWebhookContext | curtain3WebhookContext
48
67
 
49
68
  // BLE
50
- serviceData!: curtainServiceData | curtain3ServiceData;
69
+ serviceData!: curtainServiceData | curtain3ServiceData
51
70
 
52
71
  // Target
53
- setNewTarget!: boolean;
54
- setNewTargetTimer!: NodeJS.Timeout;
72
+ setNewTarget!: boolean
73
+ setNewTargetTimer!: NodeJS.Timeout
55
74
 
56
75
  // Updates
57
- curtainUpdateInProgress!: boolean;
58
- doCurtainUpdate!: Subject<void>;
76
+ curtainMoving!: boolean
77
+ curtainUpdateInProgress!: boolean
78
+ doCurtainUpdate!: Subject<void>
59
79
 
60
80
  constructor(
61
81
  readonly platform: SwitchBotPlatform,
62
82
  accessory: PlatformAccessory,
63
83
  device: device & devicesConfig,
64
84
  ) {
65
- super(platform, accessory, device);
85
+ super(platform, accessory, device)
66
86
  // Set category
67
- accessory.category = this.hap.Categories.WINDOW_COVERING;
87
+ accessory.category = this.hap.Categories.WINDOW_COVERING
68
88
 
69
89
  // this is subject we use to track when we need to POST changes to the SwitchBot API
70
- this.doCurtainUpdate = new Subject();
71
- this.curtainUpdateInProgress = false;
72
- this.setNewTarget = false;
90
+ this.doCurtainUpdate = new Subject()
91
+ this.curtainMoving = false
92
+ this.curtainUpdateInProgress = false
93
+ this.setNewTarget = false
73
94
 
74
95
  // Initialize WindowCovering Service
75
- accessory.context.WindowCovering = accessory.context.WindowCovering ?? {};
96
+ accessory.context.WindowCovering = accessory.context.WindowCovering ?? {}
76
97
  this.WindowCovering = {
77
98
  Name: accessory.displayName,
78
99
  Service: accessory.getService(this.hap.Service.WindowCovering) ?? accessory.addService(this.hap.Service.WindowCovering) as Service,
@@ -80,343 +101,385 @@ export class Curtain extends deviceBase {
80
101
  TargetPosition: accessory.context.TargetPosition ?? 100,
81
102
  CurrentPosition: accessory.context.CurrentPosition ?? 100,
82
103
  HoldPosition: accessory.context.HoldPosition ?? false,
83
- };
84
- accessory.context.WindowCovering = this.WindowCovering as object;
104
+ }
105
+ accessory.context.WindowCovering = this.WindowCovering as object
85
106
 
86
107
  // Initialize WindowCovering Service
87
- this.WindowCovering.Service.
88
- setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name)
89
- .setCharacteristic(this.hap.Characteristic.ObstructionDetected, false)
90
- .getCharacteristic(this.hap.Characteristic.PositionState)
91
- .onGet(() => {
92
- return this.WindowCovering.PositionState;
93
- });
108
+ this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name).setCharacteristic(this.hap.Characteristic.ObstructionDetected, false).getCharacteristic(this.hap.Characteristic.PositionState).onGet(() => {
109
+ return this.WindowCovering.PositionState
110
+ })
94
111
 
95
112
  // Initialize WindowCovering CurrentPosition
96
- this.WindowCovering.Service
97
- .getCharacteristic(this.hap.Characteristic.CurrentPosition)
98
- .setProps({
99
- minStep: device.curtain?.set_minStep ?? 1,
100
- minValue: 0,
101
- maxValue: 100,
102
- validValueRanges: [0, 100],
103
- })
104
- .onGet(() => {
105
- return this.WindowCovering.CurrentPosition;
106
- });
113
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.CurrentPosition).setProps({
114
+ minStep: device.curtain?.set_minStep ?? 1,
115
+ minValue: 0,
116
+ maxValue: 100,
117
+ validValueRanges: [0, 100],
118
+ }).onGet(() => {
119
+ return this.WindowCovering.CurrentPosition
120
+ })
107
121
 
108
122
  // Initialize WindowCovering TargetPosition
109
- this.WindowCovering.Service
110
- .getCharacteristic(this.hap.Characteristic.TargetPosition)
111
- .setProps({
112
- minStep: device.curtain?.set_minStep ?? 1,
113
- minValue: 0,
114
- maxValue: 100,
115
- validValueRanges: [0, 100],
116
- })
117
- .onGet(() => {
118
- return this.WindowCovering.TargetPosition;
119
- })
120
- .onSet(this.TargetPositionSet.bind(this));
123
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.TargetPosition).setProps({
124
+ minStep: device.curtain?.set_minStep ?? 1,
125
+ minValue: 0,
126
+ maxValue: 100,
127
+ validValueRanges: [0, 100],
128
+ }).onGet(() => {
129
+ return this.WindowCovering.TargetPosition
130
+ }).onSet(this.TargetPositionSet.bind(this))
121
131
 
122
132
  // Initialize WindowCovering TargetPosition
123
- this.WindowCovering.Service
124
- .getCharacteristic(this.hap.Characteristic.HoldPosition)
125
- .onGet(() => {
126
- return this.WindowCovering.HoldPosition;
127
- })
128
- .onSet(this.HoldPositionSet.bind(this));
133
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.HoldPosition).onGet(() => {
134
+ return this.WindowCovering.HoldPosition
135
+ }).onSet(this.HoldPositionSet.bind(this))
129
136
 
130
137
  // Initialize Battery Service
131
- accessory.context.Battery = accessory.context.Battery ?? {};
138
+ accessory.context.Battery = accessory.context.Battery ?? {}
132
139
  this.Battery = {
133
140
  Name: `${accessory.displayName} Battery`,
134
141
  Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
135
142
  BatteryLevel: accessory.context.BatteryLevel ?? 100,
136
143
  StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
137
144
  ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGING,
138
- };
139
- accessory.context.Battery = this.Battery as object;
145
+ }
146
+ accessory.context.Battery = this.Battery as object
140
147
 
141
148
  // Initialize Battery Service
142
- this.Battery.Service
143
- .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
144
- .getCharacteristic(this.hap.Characteristic.BatteryLevel)
145
- .onGet(() => {
146
- return this.Battery.BatteryLevel;
147
- });
148
-
149
- this.Battery.Service
150
- .getCharacteristic(this.hap.Characteristic.StatusLowBattery)
151
- .onGet(() => {
152
- return this.Battery.StatusLowBattery;
153
- });
154
-
155
- this.Battery.Service
156
- .getCharacteristic(this.hap.Characteristic.ChargingState)
157
- .onGet(() => {
158
- return this.Battery.ChargingState;
159
- });
149
+ this.Battery.Service.setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name).getCharacteristic(this.hap.Characteristic.BatteryLevel).onGet(() => {
150
+ return this.Battery.BatteryLevel
151
+ })
152
+
153
+ this.Battery.Service.getCharacteristic(this.hap.Characteristic.StatusLowBattery).onGet(() => {
154
+ return this.Battery.StatusLowBattery
155
+ })
156
+
157
+ this.Battery.Service.getCharacteristic(this.hap.Characteristic.ChargingState).onGet(() => {
158
+ return this.Battery.ChargingState
159
+ })
160
160
 
161
161
  // Initialize LightSensor Service
162
- if (device.curtain?.hide_lightsensor) {
162
+ if (device.curtain?.hide_lightsensor || (device.deviceType !== 'curtain' && device.deviceType !== 'curtain3')) {
163
163
  if (this.LightSensor?.Service) {
164
- this.debugLog('Removing Light Sensor Service');
165
- this.LightSensor.Service = this.accessory.getService(this.hap.Service.LightSensor) as Service;
166
- accessory.removeService(this.LightSensor.Service);
167
- accessory.context.LightSensor = {};
164
+ this.debugLog('Removing Light Sensor Service')
165
+ this.LightSensor.Service = this.accessory.getService(this.hap.Service.LightSensor) as Service
166
+ accessory.removeService(this.LightSensor.Service)
167
+ accessory.context.LightSensor = {}
168
168
  }
169
- } else {
170
- accessory.context.LightSensor = accessory.context.LightSensor ?? {};
169
+ } else if (device.deviceType === 'curtain' || device.deviceType === 'curtain3') {
170
+ accessory.context.LightSensor = accessory.context.LightSensor ?? {}
171
171
  this.LightSensor = {
172
172
  Name: `${accessory.displayName} Light Sensor`,
173
173
  Service: accessory.getService(this.hap.Service.LightSensor) ?? this.accessory.addService(this.hap.Service.LightSensor) as Service,
174
174
  CurrentAmbientLightLevel: accessory.context.CurrentAmbientLightLevel ?? 0.0001,
175
- };
176
- accessory.context.LightSensor = this.LightSensor as object;
175
+ }
176
+ accessory.context.LightSensor = this.LightSensor as object
177
177
 
178
178
  // Initialize LightSensor Characteristic
179
- this.LightSensor.Service
180
- .setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name)
181
- .setCharacteristic(this.hap.Characteristic.StatusActive, true)
182
- .getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel)
183
- .onGet(() => {
184
- return this.LightSensor!.CurrentAmbientLightLevel!;
185
- });
179
+ this.LightSensor.Service.setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name).setCharacteristic(this.hap.Characteristic.StatusActive, true).getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel).onGet(() => {
180
+ return this.LightSensor!.CurrentAmbientLightLevel!
181
+ })
182
+ }
183
+
184
+ // Initialize Open Mode Switch Service
185
+ if (!device.curtain?.silentModeSwitch) {
186
+ if (this.OpenModeSwitch?.Service) {
187
+ this.debugLog('Removing Open Mode Switch Service')
188
+ this.OpenModeSwitch.Service = this.accessory.getService(this.hap.Service.Switch) as Service
189
+ accessory.removeService(this.OpenModeSwitch.Service)
190
+ accessory.context.OpenModeSwitch = {}
191
+ }
192
+ } else {
193
+ accessory.context.OpenModeSwitch = accessory.context.OpenModeSwitch ?? {}
194
+ this.OpenModeSwitch = {
195
+ Name: `${accessory.displayName} Silent Open Mode`,
196
+ Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch) as Service,
197
+ On: accessory.context.OpenModeSwitch.On ?? false,
198
+ }
199
+ accessory.context.OpenModeSwitch = this.OpenModeSwitch as object
200
+
201
+ // Initialize Open Mode Switch Service
202
+ this.OpenModeSwitch.Service.setCharacteristic(this.hap.Characteristic.Name, this.OpenModeSwitch.Name).getCharacteristic(this.hap.Characteristic.On).onGet(() => {
203
+ return this.OpenModeSwitch?.On ?? false
204
+ })
205
+
206
+ this.OpenModeSwitch.Service.getCharacteristic(this.hap.Characteristic.On).onSet(this.OpenModeSwitchSet.bind(this))
207
+ }
208
+
209
+ // Initialize Close Mode Switch Service
210
+ if (!device.curtain?.silentModeSwitch) {
211
+ if (this.CloseModeSwitch?.Service) {
212
+ this.debugLog('Removing Close Mode Switch Service')
213
+ this.CloseModeSwitch.Service = this.accessory.getService(this.hap.Service.Switch) as Service
214
+ accessory.removeService(this.CloseModeSwitch.Service)
215
+ accessory.context.CloseModeSwitch = {}
216
+ }
217
+ } else {
218
+ accessory.context.CloseModeSwitch = accessory.context.CloseModeSwitch ?? {}
219
+ this.CloseModeSwitch = {
220
+ Name: `${accessory.displayName} Silent Close Mode`,
221
+ Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch) as Service,
222
+ On: accessory.context.CloseModeSwitch.On ?? false,
223
+ }
224
+ accessory.context.CloseModeSwitch = this.CloseModeSwitch as object
225
+
226
+ // Initialize Close Mode Switch Service
227
+ this.CloseModeSwitch.Service.setCharacteristic(this.hap.Characteristic.Name, this.CloseModeSwitch.Name).getCharacteristic(this.hap.Characteristic.On).onGet(() => {
228
+ return this.CloseModeSwitch?.On ?? false
229
+ })
230
+
231
+ this.CloseModeSwitch.Service.getCharacteristic(this.hap.Characteristic.On).onSet(this.CloseModeSwitchSet.bind(this))
186
232
  }
187
233
 
188
234
  // Retrieve initial values and updateHomekit
189
- this.debugLog('Retrieve initial values and update Homekit');
190
- this.refreshStatus();
235
+ try {
236
+ this.debugLog('Retrieve initial values and update Homekit')
237
+ this.refreshStatus()
238
+ } catch (e: any) {
239
+ this.errorLog(`failed to retrieve initial values and update Homekit, Error: ${e}`)
240
+ }
191
241
 
192
- //regisiter webhook event handler
193
- this.debugLog('Registering Webhook Event Handler');
194
- this.registerWebhook();
242
+ // regisiter webhook event handler if enabled
243
+ try {
244
+ this.debugLog('Registering Webhook Event Handler')
245
+ this.registerWebhook()
246
+ } catch (e: any) {
247
+ this.errorLog(`failed to registerWebhook, Error: ${e}`)
248
+ }
249
+
250
+ // regisiter platform BLE event handler if enabled
251
+ try {
252
+ this.debugLog('Registering Platform BLE Event Handler')
253
+ this.registerPlatformBLE()
254
+ } catch (e: any) {
255
+ this.errorLog(`failed to registerPlatformBLE, Error: ${e}`)
256
+ }
195
257
 
196
258
  // History
197
- this.history();
259
+ this.history()
198
260
 
199
261
  // Start an update interval
200
262
  interval(this.deviceRefreshRate * 1000)
201
263
  .pipe(skipWhile(() => this.curtainUpdateInProgress))
202
264
  .subscribe(async () => {
203
- await this.refreshStatus();
204
- });
265
+ await this.refreshStatus()
266
+ })
205
267
 
206
268
  // update slide progress
207
269
  interval(this.deviceUpdateRate * 1000)
208
- //.pipe(skipWhile(() => this.curtainUpdateInProgress))
270
+ .pipe(skipWhile(() => !this.curtainMoving))
209
271
  .subscribe(async () => {
210
272
  if (this.WindowCovering.PositionState === this.hap.Characteristic.PositionState.STOPPED) {
211
- return;
273
+ return
212
274
  }
213
- await this.debugLog(`Refresh Status When Moving, PositionState: ${this.WindowCovering.PositionState}`);
214
- await this.refreshStatus();
215
- });
275
+ await this.debugLog(`Refresh Status When Moving, PositionState: ${this.WindowCovering.PositionState}`)
276
+ await this.refreshStatus()
277
+ })
216
278
 
217
279
  // Watch for Curtain change events
218
280
  // We put in a debounce of 100ms so we don't make duplicate calls
219
281
  this.doCurtainUpdate
220
282
  .pipe(
221
283
  tap(() => {
222
- this.curtainUpdateInProgress = true;
284
+ this.curtainUpdateInProgress = true
223
285
  }),
224
286
  debounceTime(this.devicePushRate * 1000),
225
287
  )
226
288
  .subscribe(async () => {
227
289
  try {
228
- await this.pushChanges();
290
+ await this.pushChanges()
229
291
  } catch (e: any) {
230
- await this.apiError(e);
231
- await this.errorLog(`failed pushChanges with ${device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`);
292
+ await this.apiError(e)
293
+ await this.errorLog(`failed pushChanges with ${device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`)
232
294
  }
233
- this.curtainUpdateInProgress = false;
234
- });
295
+ this.curtainUpdateInProgress = false
296
+ })
235
297
 
236
298
  // Setup EVE history features
237
- this.setupHistoryService();
299
+ this.setupHistoryService()
238
300
  }
239
301
 
240
302
  async history() {
241
303
  if (this.device.history === true) {
242
304
  // initialize when this accessory is newly created.
243
- this.accessory.context.lastActivation = this.accessory.context.lastActivation ?? 0;
305
+ this.accessory.context.lastActivation = this.accessory.context.lastActivation ?? 0
244
306
  } else {
245
307
  // removes cached values if history is turned off
246
- delete this.accessory.context.lastActivation;
308
+ delete this.accessory.context.lastActivation
247
309
  }
248
310
  }
249
311
 
250
312
  /*
251
313
  * Setup EVE history features for curtain devices.
252
314
  */
253
- async setupHistoryService(): Promise<void> {
315
+ async setupHistoryService(): Promise < void> {
254
316
  if (this.device.history !== true) {
255
- return;
317
+ return
256
318
  }
257
319
 
258
320
  const mac = this.device
259
321
  .deviceId!.match(/.{1,2}/g)!
260
322
  .join(':')
261
- .toLowerCase();
323
+ .toLowerCase()
262
324
  this.historyService = new this.platform.fakegatoAPI('custom', this.accessory, {
263
325
  log: this.platform.log,
264
326
  storage: 'fs',
265
327
  filename: `${hostname().split('.')[0]}_${mac}_persist.json`,
266
- });
267
- const motion: Service =
268
- this.accessory.getService(this.hap.Service.MotionSensor) ||
269
- this.accessory.addService(this.hap.Service.MotionSensor, 'Motion');
270
- motion.addOptionalCharacteristic(this.platform.eve.Characteristics.LastActivation);
328
+ })
329
+ const motion: Service
330
+ = this.accessory.getService(this.hap.Service.MotionSensor)
331
+ || this.accessory.addService(this.hap.Service.MotionSensor, 'Motion')
332
+ motion.addOptionalCharacteristic(this.platform.eve.Characteristics.LastActivation)
271
333
  motion.getCharacteristic(this.platform.eve.Characteristics.LastActivation).onGet(() => {
272
334
  const lastActivation = this.accessory.context.lastActivation
273
335
  ? Math.max(0, this.accessory.context.lastActivation - this.historyService.getInitialTime())
274
- : 0;
275
- return lastActivation;
276
- });
277
- await this.setMinMax();
336
+ : 0
337
+ return lastActivation
338
+ })
339
+ await this.setMinMax()
278
340
  motion.getCharacteristic(this.hap.Characteristic.MotionDetected).on('change', (event: CharacteristicChange) => {
279
341
  if (event.newValue !== event.oldValue) {
280
- const sensor = this.accessory.getService(this.hap.Service.MotionSensor);
342
+ const sensor = this.accessory.getService(this.hap.Service.MotionSensor)
281
343
  const entry = {
282
344
  time: Math.round(new Date().valueOf() / 1000),
283
345
  motion: event.newValue,
284
- };
285
- this.accessory.context.lastActivation = entry.time;
346
+ }
347
+ this.accessory.context.lastActivation = entry.time
286
348
  sensor?.updateCharacteristic(
287
349
  this.platform.eve.Characteristics.LastActivation,
288
- Math.max(0, this.accessory.context.lastActivation - this.historyService.getInitialTime()));
289
- this.historyService.addEntry(entry);
350
+ Math.max(0, this.accessory.context.lastActivation - this.historyService.getInitialTime()),
351
+ )
352
+ this.historyService.addEntry(entry)
290
353
  }
291
- });
292
- this.updateHistory();
354
+ })
355
+ this.updateHistory()
293
356
  }
294
357
 
295
358
  async updateHistory(): Promise<void> {
296
- const motion = Number(this.WindowCovering.CurrentPosition) > 0 ? 1 : 0;
359
+ const motion = Number(this.WindowCovering.CurrentPosition) > 0 ? 1 : 0
297
360
  this.historyService.addEntry({
298
361
  time: Math.round(new Date().valueOf() / 1000),
299
- motion: motion,
300
- });
362
+ motion,
363
+ })
301
364
  setTimeout(async () => {
302
- await this.updateHistory();
303
- }, 10 * 60 * 1000);
365
+ await this.updateHistory()
366
+ }, 10 * 60 * 1000)
304
367
  }
305
368
 
306
369
  async BLEparseStatus(): Promise<void> {
307
- await this.debugLog('BLEparseStatus');
308
- await this.debugLog(`(position, battery) = BLE:(${this.serviceData.position}, ${this.serviceData.battery}),`
309
- + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
370
+ await this.debugLog('BLEparseStatus')
371
+ await this.debugLog(`(position, battery) = BLE:(${this.serviceData.position}, ${this.serviceData.battery}), current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`)
310
372
  // CurrentPosition
311
- this.WindowCovering.CurrentPosition = 100 -this.serviceData.position;
312
- await this.getCurrentPostion();
373
+ this.WindowCovering.CurrentPosition = 100 - this.serviceData.position
374
+ await this.getCurrentPostion()
313
375
  // CurrentAmbientLightLevel
314
376
  if (!this.device.curtain?.hide_lightsensor && this.LightSensor?.Service) {
315
- const set_minLux = this.device.curtain?.set_minLux ?? 1;
316
- const set_maxLux = this.device.curtain?.set_maxLux ?? 6001;
317
- const lightLevel = this.serviceData.lightLevel;
318
- this.LightSensor.CurrentAmbientLightLevel = await this.getLightLevel(lightLevel, set_minLux, set_maxLux, 19);
319
- this.debugLog(`LightLevel: ${this.serviceData.lightLevel},`
320
- + ` CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`);
377
+ const set_minLux = this.device.curtain?.set_minLux ?? 1
378
+ const set_maxLux = this.device.curtain?.set_maxLux ?? 6001
379
+ const lightLevel = this.serviceData.lightLevel
380
+ this.LightSensor.CurrentAmbientLightLevel = await this.getLightLevel(lightLevel, set_minLux, set_maxLux, 19)
381
+ this.debugLog(`LightLevel: ${this.serviceData.lightLevel}, CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`)
321
382
  }
322
383
  // BatteryLevel
323
- this.Battery.BatteryLevel = this.serviceData.battery;
324
- await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
384
+ this.Battery.BatteryLevel = this.serviceData.battery
385
+ await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`)
325
386
  // StatusLowBattery
326
387
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
327
- ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
328
- await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
388
+ ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW
389
+ : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL
390
+ await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`)
329
391
  }
330
392
 
331
393
  async openAPIparseStatus(): Promise<void> {
332
- await this.debugLog('openAPIparseStatus');
333
- await this.debugLog(`(slidePosition, battery) = OpenAPI:(${this.deviceStatus.slidePosition}, ${this.deviceStatus.battery}),`
334
- + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
394
+ await this.debugLog('openAPIparseStatus')
395
+ await this.debugLog(`(slidePosition, battery, version) = OpenAPI:(${this.deviceStatus.slidePosition}, ${this.deviceStatus.battery}, ${this.deviceStatus.version}), current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel}, ${this.accessory.context.version})`)
335
396
  // CurrentPosition
336
- this.WindowCovering.CurrentPosition = 100 - this.deviceStatus.slidePosition;
337
- await this.setMinMax();
338
- await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
397
+ this.WindowCovering.CurrentPosition = 100 - this.deviceStatus.slidePosition
398
+ await this.setMinMax()
399
+ await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
339
400
  if (this.setNewTarget) {
340
- await this.infoLog('Checking Status ...');
401
+ await this.infoLog('Checking Status ...')
341
402
  }
342
403
  if (this.setNewTarget && this.deviceStatus.moving) {
343
- await this.setMinMax();
404
+ this.curtainMoving = true
405
+ await this.setMinMax()
344
406
  if (Number(this.WindowCovering.TargetPosition) > this.WindowCovering.CurrentPosition) {
345
- await this.debugLog(`Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
346
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
347
- this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
348
- await this.debugLog(`Increasing, PositionState: ${this.WindowCovering.PositionState}`);
407
+ await this.debugLog(`Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
408
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING
409
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState)
410
+ await this.debugLog(`Increasing, PositionState: ${this.WindowCovering.PositionState}`)
349
411
  } else if (Number(this.WindowCovering.TargetPosition) < this.WindowCovering.CurrentPosition) {
350
- await this.debugLog(`Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
351
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
352
- this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
353
- await this.debugLog(`Decreasing, PositionState: ${this.WindowCovering.PositionState}`);
412
+ await this.debugLog(`Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
413
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING
414
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState)
415
+ await this.debugLog(`Decreasing, PositionState: ${this.WindowCovering.PositionState}`)
354
416
  } else {
355
- await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
356
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
357
- this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
358
- await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`);
417
+ await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
418
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED
419
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState)
420
+ await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`)
359
421
  }
360
422
  } else {
361
- await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
362
- this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
363
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
364
- await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`);
423
+ this.curtainMoving = false
424
+ await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
425
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition
426
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED
427
+ await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`)
365
428
  }
366
- await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition},`
367
- + ` PositionState: ${this.WindowCovering.PositionState},`);
429
+ await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`)
368
430
 
369
431
  // Brightness
370
432
  if (!this.device.curtain?.hide_lightsensor && this.LightSensor?.Service) {
371
- const set_minLux = this.device.curtain?.set_minLux ?? 1;
372
- const set_maxLux = this.device.curtain?.set_maxLux ?? 6001;
373
- const lightLevel = this.deviceStatus.lightLevel === 'bright' ? set_maxLux : set_minLux;
374
- this.LightSensor.CurrentAmbientLightLevel = await this.getLightLevel(lightLevel, set_minLux, set_maxLux, 2);
375
- await this.debugLog(`CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`);
433
+ const set_minLux = this.device.curtain?.set_minLux ?? 1
434
+ const set_maxLux = this.device.curtain?.set_maxLux ?? 6001
435
+ const lightLevel = this.deviceStatus.lightLevel === 'bright' ? set_maxLux : set_minLux
436
+ this.LightSensor.CurrentAmbientLightLevel = await this.getLightLevel(lightLevel, set_minLux, set_maxLux, 2)
437
+ await this.debugLog(`CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`)
376
438
  }
377
439
 
378
440
  // BatteryLevel
379
- this.Battery.BatteryLevel = this.deviceStatus.battery;
380
- await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
441
+ this.Battery.BatteryLevel = this.deviceStatus.battery
442
+ await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`)
381
443
 
382
444
  // StatusLowBattery
383
445
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
384
- ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
385
- await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
446
+ ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW
447
+ : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL
448
+ await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`)
386
449
 
387
450
  // Firmware Version
388
451
  if (this.deviceStatus.version) {
389
- const version = this.deviceStatus.version.toString();
390
- await this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`);
391
- const deviceVersion = version.replace(/^V|-.*$/g, '') ?? '0.0.0';
452
+ const version = this.deviceStatus.version.toString()
453
+ await this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`)
454
+ const deviceVersion = version.replace(/^V|-.*$/g, '') ?? '0.0.0'
392
455
  this.accessory
393
456
  .getService(this.hap.Service.AccessoryInformation)!
394
457
  .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
395
458
  .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
396
459
  .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
397
- .updateValue(deviceVersion);
398
- this.accessory.context.version = deviceVersion;
399
- await this.debugSuccessLog(`version: ${this.accessory.context.version}`);
460
+ .updateValue(deviceVersion)
461
+ this.accessory.context.version = deviceVersion
462
+ await this.debugSuccessLog(`version: ${this.accessory.context.version}`)
400
463
  }
401
464
  }
402
465
 
403
466
  async parseStatusWebhook(): Promise<void> {
404
- await this.debugLog('parseStatusWebhook');
405
- await this.debugLog(`(slidePosition, battery) = Webhook:(${this.webhookContext.slidePosition}, ${this.webhookContext.battery}),`
406
- + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
467
+ await this.debugLog('parseStatusWebhook')
468
+ await this.debugLog(`(slidePosition, battery) = Webhook:(${this.webhookContext.slidePosition}, ${this.webhookContext.battery}), current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`)
407
469
 
408
470
  // CurrentPosition
409
- this.WindowCovering.CurrentPosition = 100 - this.webhookContext.slidePosition;
410
- await this.getCurrentPostion();
471
+ this.WindowCovering.CurrentPosition = 100 - this.webhookContext.slidePosition
472
+ await this.getCurrentPostion()
411
473
 
412
474
  // BatteryLevel
413
- this.Battery.BatteryLevel = this.webhookContext.battery;
414
- await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
475
+ this.Battery.BatteryLevel = this.webhookContext.battery
476
+ await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`)
415
477
 
416
478
  // StatusLowBattery
417
479
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
418
- ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
419
- await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
480
+ ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW
481
+ : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL
482
+ await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`)
420
483
  }
421
484
 
422
485
  /**
@@ -424,94 +487,98 @@ export class Curtain extends deviceBase {
424
487
  */
425
488
  async refreshStatus(): Promise<void> {
426
489
  if (!this.device.enableCloudService && this.OpenAPI) {
427
- await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
428
- } else if (this.BLE || this.config.options?.BLE) {
429
- await this.BLERefreshStatus();
490
+ await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`)
491
+ } else if (this.BLE) {
492
+ await this.BLERefreshStatus()
430
493
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
431
- await this.openAPIRefreshStatus();
494
+ await this.openAPIRefreshStatus()
432
495
  } else {
433
- await this.offlineOff();
434
- await this.debugWarnLog(`Connection Type: ${this.device.connectionType}, refreshStatus will not happen.`);
496
+ await this.offlineOff()
497
+ await this.debugWarnLog(`Connection Type: ${this.device.connectionType}, refreshStatus will not happen.`)
435
498
  }
436
499
  }
437
500
 
438
501
  async BLERefreshStatus(): Promise<void> {
439
- await this.debugLog('BLERefreshStatus');
440
- if (this.config.options?.BLE) {
441
- await this.debugLog('is listening to Platform BLE.');
442
- this.device.bleMac = this.device.deviceId!.match(/.{1,2}/g)!.join(':').toLowerCase();
443
- await this.debugLog(`bleMac: ${this.device.bleMac}`);
444
- this.platform.bleEventHandler[this.device.bleMac] = async (context: curtainServiceData | curtain3ServiceData) => {
445
- try {
446
- await this.debugLog(`received BLE: ${JSON.stringify(context)}`);
447
- this.serviceData = context;
448
- await this.BLEparseStatus();
449
- await this.updateHomeKitCharacteristics();
450
- } catch (e: any) {
451
- await this.errorLog(`failed to handle BLE. Received: ${JSON.stringify(context)} Error: ${e}`);
452
- }
453
- };
502
+ await this.debugLog('BLERefreshStatus')
503
+ const switchbot = await this.switchbotBLE()
504
+ if (switchbot === undefined) {
505
+ await this.BLERefreshConnection(switchbot)
454
506
  } else {
455
- await this.debugLog('is using Device BLE Scanning.');
456
- const switchbot = await this.switchbotBLE();
457
- if (switchbot === undefined) {
458
- await this.BLERefreshConnection(switchbot);
459
- } else {
507
+ // Start to monitor advertisement packets
508
+ (async () => {
460
509
  // Start to monitor advertisement packets
461
- (async () => {
462
- // Start to monitor advertisement packets
463
- const serviceData = await this.monitorAdvertisementPackets(switchbot) as curtainServiceData | curtain3ServiceData;
464
- // Update HomeKit
465
- if ((serviceData.model === SwitchBotBLEModel.Curtain || SwitchBotBLEModel.Curtain3)
510
+ const serviceData = await this.monitorAdvertisementPackets(switchbot) as curtainServiceData | curtain3ServiceData
511
+ // Update HomeKit
512
+ if ((serviceData.model === SwitchBotBLEModel.Curtain || SwitchBotBLEModel.Curtain3)
466
513
  && (serviceData.modelName === SwitchBotBLEModelName.Curtain || SwitchBotBLEModelName.Curtain3)) {
467
- this.serviceData = serviceData;
468
- await this.BLEparseStatus();
469
- await this.updateHomeKitCharacteristics();
470
- } else {
471
- await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`);
472
- await this.BLERefreshConnection(switchbot);
473
- }
474
- })();
475
- }
514
+ this.serviceData = serviceData
515
+ await this.BLEparseStatus()
516
+ await this.updateHomeKitCharacteristics()
517
+ } else {
518
+ await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`)
519
+ await this.BLERefreshConnection(switchbot)
520
+ }
521
+ })()
476
522
  }
477
523
  }
478
524
 
479
525
  async openAPIRefreshStatus(): Promise<void> {
480
- await this.debugLog('openAPIRefreshStatus');
526
+ await this.debugLog('openAPIRefreshStatus')
481
527
  try {
482
- const { body, statusCode } = await this.deviceRefreshStatus();
483
- const deviceStatus: any = await body.json();
484
- await this.debugLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);;
528
+ const { body, statusCode } = await this.deviceRefreshStatus()
529
+ const deviceStatus: any = await body.json()
530
+ await this.debugLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
485
531
  if (await this.successfulStatusCodes(statusCode, deviceStatus)) {
486
- await this.debugSuccessLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
487
- this.deviceStatus = deviceStatus.body;
488
- await this.openAPIparseStatus();
489
- await this.updateHomeKitCharacteristics();
532
+ await this.debugSuccessLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
533
+ this.deviceStatus = deviceStatus.body
534
+ await this.openAPIparseStatus()
535
+ await this.updateHomeKitCharacteristics()
490
536
  } else {
491
- await this.debugWarnLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
492
- await this.debugWarnLog(statusCode, deviceStatus);
537
+ await this.debugWarnLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
538
+ await this.debugWarnLog(statusCode, deviceStatus)
493
539
  }
494
540
  } catch (e: any) {
495
- await this.apiError(e);
496
- await this.errorLog(`failed openAPIRefreshStatus with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`);
541
+ await this.apiError(e)
542
+ await this.errorLog(`failed openAPIRefreshStatus with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`)
497
543
  }
498
544
  }
499
545
 
500
546
  async registerWebhook() {
501
547
  if (this.device.webhook) {
502
- await this.debugLog('is listening webhook.');
548
+ await this.debugLog('is listening webhook.')
503
549
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: curtainWebhookContext | curtain3WebhookContext) => {
504
550
  try {
505
- await this.debugLog(`received Webhook: ${JSON.stringify(context)}`);
506
- this.webhookContext = context;
507
- await this.parseStatusWebhook();
508
- await this.updateHomeKitCharacteristics();
551
+ await this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
552
+ this.webhookContext = context
553
+ await this.parseStatusWebhook()
554
+ await this.updateHomeKitCharacteristics()
509
555
  } catch (e: any) {
510
- await this.errorLog(`failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
556
+ await this.errorLog(`failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`)
511
557
  }
512
- };
558
+ }
513
559
  } else {
514
- await this.debugLog('is not listening webhook.');
560
+ await this.debugLog('is not listening webhook.')
561
+ }
562
+ }
563
+
564
+ async registerPlatformBLE(): Promise<void> {
565
+ await this.debugLog('registerPlatformBLE')
566
+ if (this.config.options?.BLE) {
567
+ await this.debugLog('is listening to Platform BLE.')
568
+ this.device.bleMac = this.device.deviceId!.match(/.{1,2}/g)!.join(':').toLowerCase()
569
+ await this.debugLog(`bleMac: ${this.device.bleMac}`)
570
+ this.platform.bleEventHandler[this.device.bleMac] = async (context: curtainServiceData | curtain3ServiceData) => {
571
+ try {
572
+ await this.debugLog(`received BLE: ${JSON.stringify(context)}`)
573
+ this.serviceData = context
574
+ await this.BLEparseStatus()
575
+ await this.updateHomeKitCharacteristics()
576
+ } catch (e: any) {
577
+ await this.errorLog(`failed to handle BLE. Received: ${JSON.stringify(context)} Error: ${e}`)
578
+ }
579
+ }
580
+ } else {
581
+ await this.debugLog('is not listening to Platform BLE')
515
582
  }
516
583
  }
517
584
 
@@ -520,32 +587,32 @@ export class Curtain extends deviceBase {
520
587
  */
521
588
  async pushChanges(): Promise<void> {
522
589
  if (!this.device.enableCloudService && this.OpenAPI) {
523
- await this.errorLog(`pushChanges enableCloudService: ${this.device.enableCloudService}`);
590
+ await this.errorLog(`pushChanges enableCloudService: ${this.device.enableCloudService}`)
524
591
  } else if (this.BLE) {
525
- await this.BLEpushChanges();
592
+ await this.BLEpushChanges()
526
593
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
527
- await this.openAPIpushChanges();
594
+ await this.openAPIpushChanges()
528
595
  } else {
529
- await this.offlineOff();
530
- await this.debugWarnLog(`Connection Type: ${this.device.connectionType}, pushChanges will not happen.`);
596
+ await this.offlineOff()
597
+ await this.debugWarnLog(`Connection Type: ${this.device.connectionType}, pushChanges will not happen.`)
531
598
  }
532
599
  // Refresh the status from the API
533
600
  interval(15000)
534
601
  .pipe(skipWhile(() => this.curtainUpdateInProgress))
535
602
  .pipe(take(1))
536
603
  .subscribe(async () => {
537
- await this.refreshStatus();
538
- });
604
+ await this.refreshStatus()
605
+ })
539
606
  }
540
607
 
541
608
  async BLEpushChanges(): Promise<void> {
542
- await this.debugLog('BLEpushChanges');
609
+ await this.debugLog('BLEpushChanges')
543
610
  if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition) {
544
- const switchbot = await this.platform.connectBLE(this.accessory, this.device);
545
- await this.convertBLEAddress();
546
- const { setPositionMode, Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
547
- const adjustedMode = setPositionMode === 1 ? 0x01 : 0xff;
548
- await this.debugLog(`Mode: ${Mode}, setPositionMode: ${setPositionMode}`);
611
+ const switchbot = await this.platform.connectBLE(this.accessory, this.device)
612
+ await this.convertBLEAddress()
613
+ const { setPositionMode, Mode }: { setPositionMode: number, Mode: string } = await this.setPerformance()
614
+ const adjustedMode = setPositionMode === 1 ? 0x01 : 0xFF
615
+ await this.debugLog(`Mode: ${Mode}, setPositionMode: ${setPositionMode}`)
549
616
  if (switchbot !== false) {
550
617
  switchbot
551
618
  .discover({ model: this.device.bleModel, quick: true, id: this.device.bleMac })
@@ -553,70 +620,68 @@ export class Curtain extends deviceBase {
553
620
  return await this.retryBLE({
554
621
  max: await this.maxRetryBLE(),
555
622
  fn: async () => {
556
- return await device_list[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), adjustedMode);
623
+ return await device_list[0].runToPos(100 - Number(this.WindowCovering.TargetPosition), adjustedMode)
557
624
  },
558
- });
625
+ })
559
626
  })
560
627
  .then(async () => {
561
- await this.successLog(`TargetPostion: ${this.WindowCovering.TargetPosition} sent over SwitchBot BLE, sent successfully`);
562
- await this.updateHomeKitCharacteristics();
628
+ await this.successLog(`TargetPostion: ${this.WindowCovering.TargetPosition} sent over SwitchBot BLE, sent successfully`)
629
+ await this.updateHomeKitCharacteristics()
563
630
  })
564
631
  .catch(async (e: any) => {
565
- await this.apiError(e);
566
- await this.errorLog(`failed BLEpushChanges with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`);
567
- await this.BLEPushConnection();
568
- });
632
+ await this.apiError(e)
633
+ await this.errorLog(`failed BLEpushChanges with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`)
634
+ await this.BLEPushConnection()
635
+ })
569
636
  } else {
570
- await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
571
- await this.BLEPushConnection();
637
+ await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`)
638
+ await this.BLEPushConnection()
572
639
  }
573
640
  } else {
574
- await this.debugLog(`No changes (BLEpushChanges), TargetPosition: ${this.WindowCovering.TargetPosition},`
575
- + ` CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
641
+ await this.debugLog(`No changes (BLEpushChanges), TargetPosition: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
576
642
  }
577
643
  }
578
644
 
579
645
  async openAPIpushChanges(): Promise<void> {
580
- await this.debugLog('openAPIpushChanges');
646
+ await this.debugLog('openAPIpushChanges')
581
647
  if (this.WindowCovering.TargetPosition !== this.WindowCovering.CurrentPosition || this.device.disableCaching) {
582
- await this.debugLog(`Pushing ${this.WindowCovering.TargetPosition}`);
583
- const adjustedTargetPosition = 100 - Number(this.WindowCovering.TargetPosition);
584
- const { setPositionMode, Mode }: { setPositionMode: number; Mode: string; } = await this.setPerformance();
585
- await this.debugLog(`Mode: ${Mode}, setPositionMode: ${setPositionMode}`);
586
- const adjustedMode = setPositionMode || 'ff';
587
- let bodyChange: string;
648
+ await this.debugLog(`Pushing ${this.WindowCovering.TargetPosition}`)
649
+ const adjustedTargetPosition = 100 - Number(this.WindowCovering.TargetPosition)
650
+ const { setPositionMode, Mode }: { setPositionMode: number, Mode: string } = await this.setPerformance()
651
+ await this.debugLog(`Mode: ${Mode}, setPositionMode: ${setPositionMode}`)
652
+ const adjustedMode = setPositionMode || 'ff'
653
+ let bodyChange: string
588
654
  if (this.WindowCovering.HoldPosition) {
589
655
  bodyChange = JSON.stringify({
590
656
  command: 'pause',
591
657
  parameter: 'default',
592
658
  commandType: 'command',
593
- });
659
+ })
594
660
  } else {
595
661
  bodyChange = JSON.stringify({
596
662
  command: 'setPosition',
597
663
  parameter: `0,${adjustedMode},${adjustedTargetPosition}`,
598
664
  commandType: 'command',
599
- });
665
+ })
600
666
  }
601
- await this.debugLog(`SwitchBot OpenAPI bodyChange: ${JSON.stringify(bodyChange)}`);
667
+ await this.debugLog(`SwitchBot OpenAPI bodyChange: ${JSON.stringify(bodyChange)}`)
602
668
  try {
603
- const { body, statusCode } = await this.pushChangeRequest(bodyChange);
604
- const deviceStatus: any = await body.json();
605
- await this.debugLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
669
+ const { body, statusCode } = await this.pushChangeRequest(bodyChange)
670
+ const deviceStatus: any = await body.json()
671
+ await this.debugLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
606
672
  if (await this.successfulStatusCodes(statusCode, deviceStatus)) {
607
- await this.debugSuccessLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
608
- await this.updateHomeKitCharacteristics();
673
+ await this.debugSuccessLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
674
+ await this.updateHomeKitCharacteristics()
609
675
  } else {
610
- await this.statusCode(statusCode);
611
- await this.statusCode(deviceStatus.statusCode);
676
+ await this.statusCode(statusCode)
677
+ await this.statusCode(deviceStatus.statusCode)
612
678
  }
613
679
  } catch (e: any) {
614
- await this.apiError(e);
615
- await this.errorLog(`failed openAPIpushChanges with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`);
680
+ await this.apiError(e)
681
+ await this.errorLog(`failed openAPIpushChanges with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`)
616
682
  }
617
683
  } else {
618
- await this.debugLog(`No changes (openAPIpushChanges), CurrentPosition: ${this.WindowCovering.CurrentPosition},`
619
- + ` TargetPosition: ${this.WindowCovering.TargetPosition}`);
684
+ await this.debugLog(`No changes (openAPIpushChanges), CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition}`)
620
685
  }
621
686
  }
622
687
 
@@ -625,206 +690,223 @@ export class Curtain extends deviceBase {
625
690
  */
626
691
  async TargetPositionSet(value: CharacteristicValue): Promise<void> {
627
692
  if (this.WindowCovering.TargetPosition !== this.accessory.context.TargetPosition) {
628
- await this.infoLog(`Set TargetPosition: ${value}`);
693
+ await this.infoLog(`Set TargetPosition: ${value}`)
629
694
  } else {
630
- await this.debugLog(`No Changes, TargetPosition: ${value}`);
695
+ await this.debugLog(`No Changes, TargetPosition: ${value}`)
631
696
  }
632
697
 
633
698
  // Set HoldPosition to false when TargetPosition is changed
634
- this.WindowCovering.HoldPosition = false;
635
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.HoldPosition, this.WindowCovering.HoldPosition);
699
+ this.WindowCovering.HoldPosition = false
700
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.HoldPosition, this.WindowCovering.HoldPosition)
636
701
 
637
- this.WindowCovering.TargetPosition = value;
638
- await this.mqtt('TargetPosition', this.WindowCovering.TargetPosition);
639
- await this.mqtt('HoldPosition', this.WindowCovering.HoldPosition);
640
- await this.startUpdatingCurtainIfNeeded();
702
+ this.WindowCovering.TargetPosition = value
703
+ await this.mqtt('TargetPosition', this.WindowCovering.TargetPosition)
704
+ await this.mqtt('HoldPosition', this.WindowCovering.HoldPosition)
705
+ await this.startUpdatingCurtainIfNeeded()
641
706
  }
642
707
 
643
708
  async startUpdatingCurtainIfNeeded() {
644
- await this.setMinMax();
709
+ await this.setMinMax()
645
710
  if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition) {
646
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
647
- this.setNewTarget = true;
648
- await this.debugLog(`value: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
711
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING
712
+ this.setNewTarget = true
713
+ await this.debugLog(`value: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
649
714
  } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
650
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
651
- this.setNewTarget = true;
652
- await this.debugLog(`value: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
715
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING
716
+ this.setNewTarget = true
717
+ await this.debugLog(`value: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
653
718
  } else {
654
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
655
- this.setNewTarget = false;
656
- await this.debugLog(`value: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
719
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED
720
+ this.setNewTarget = false
721
+ await this.debugLog(`value: ${this.WindowCovering.TargetPosition}, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
657
722
  }
658
- this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.PositionState, this.WindowCovering.PositionState);
659
- this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
723
+ this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.PositionState, this.WindowCovering.PositionState)
724
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState)
660
725
 
661
726
  /**
662
727
  * If Curtain movement time is short, the moving flag from backend is always false.
663
728
  * The minimum time depends on the network control latency.
664
729
  */
665
- clearTimeout(this.setNewTargetTimer);
666
- await this.debugLog(`deviceUpdateRate: ${this.deviceUpdateRate}`);
730
+ clearTimeout(this.setNewTargetTimer)
731
+ await this.debugLog(`deviceUpdateRate: ${this.deviceUpdateRate}`)
667
732
  if (this.setNewTarget) {
668
733
  this.setNewTargetTimer = setTimeout(async () => {
669
- await this.debugLog(`setNewTarget ${this.setNewTarget} timeout`);
670
- this.setNewTarget = false;
671
- }, this.deviceUpdateRate * 1000);
734
+ await this.debugLog(`setNewTarget ${this.setNewTarget} timeout`)
735
+ this.setNewTarget = false
736
+ }, this.deviceUpdateRate * 1000)
672
737
  }
673
- this.doCurtainUpdate.next();
738
+ this.doCurtainUpdate.next()
674
739
  }
675
740
 
676
741
  /**
677
742
  * Handle requests to set the value of the "Target Position" characteristic
678
743
  */
679
744
  async HoldPositionSet(value: CharacteristicValue): Promise<void> {
680
- this.debugLog(`HoldPosition: ${value}`);
681
- this.WindowCovering.HoldPosition = value;
682
- this.doCurtainUpdate.next();
745
+ this.debugLog(`HoldPosition: ${value}`)
746
+ this.WindowCovering.HoldPosition = value
747
+ this.doCurtainUpdate.next()
748
+ }
749
+
750
+ /**
751
+ * Handle requests to set the value of the "Target Position" characteristic
752
+ */
753
+ async OpenModeSwitchSet(value: CharacteristicValue): Promise<void> {
754
+ if (this.OpenModeSwitch && this.device.curtain?.silentModeSwitch) {
755
+ this.debugLog(`Silent Open Mode: ${value}`)
756
+ this.OpenModeSwitch.On = value
757
+ this.accessory.context.OpenModeSwitch.On = value
758
+ this.doCurtainUpdate.next()
759
+ }
760
+ }
761
+
762
+ /**
763
+ * Handle requests to set the value of the "Target Position" characteristic
764
+ */
765
+ async CloseModeSwitchSet(value: CharacteristicValue): Promise<void> {
766
+ if (this.CloseModeSwitch && this.device.curtain?.silentModeSwitch) {
767
+ this.debugLog(`Silent Close Mode: ${value}`)
768
+ this.CloseModeSwitch.On = value
769
+ this.accessory.context.CloseModeSwitch.On = value
770
+ this.doCurtainUpdate.next()
771
+ }
683
772
  }
684
773
 
685
774
  async updateHomeKitCharacteristics(): Promise<void> {
686
- await this.setMinMax();
775
+ await this.setMinMax()
687
776
  // CurrentPosition
688
- await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.CurrentPosition,
689
- this.WindowCovering.CurrentPosition, 'CurrentPosition');
777
+ await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.CurrentPosition, this.WindowCovering.CurrentPosition, 'CurrentPosition')
690
778
  // PositionState
691
- await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.PositionState,
692
- this.WindowCovering.PositionState, 'PositionState');
779
+ await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.PositionState, this.WindowCovering.PositionState, 'PositionState')
693
780
  // TargetPosition
694
- await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.TargetPosition,
695
- this.WindowCovering.TargetPosition, 'TargetPosition');
781
+ await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.TargetPosition, this.WindowCovering.TargetPosition, 'TargetPosition')
696
782
  // HoldPosition
697
- await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.HoldPosition,
698
- this.WindowCovering.HoldPosition, 'HoldPosition');
783
+ await this.updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.HoldPosition, this.WindowCovering.HoldPosition, 'HoldPosition')
699
784
  // CurrentAmbientLightLevel
700
785
  if (!this.device.curtain?.hide_lightsensor && this.LightSensor?.Service) {
701
- const history = { time: Math.round(new Date().valueOf() / 1000), lux: this.LightSensor.CurrentAmbientLightLevel };
702
- await this.updateCharacteristic(this.LightSensor?.Service, this.hap.Characteristic.CurrentAmbientLightLevel,
703
- this.LightSensor?.CurrentAmbientLightLevel, 'CurrentAmbientLightLevel', history);
786
+ const history = { time: Math.round(new Date().valueOf() / 1000), lux: this.LightSensor.CurrentAmbientLightLevel }
787
+ await this.updateCharacteristic(this.LightSensor?.Service, this.hap.Characteristic.CurrentAmbientLightLevel, this.LightSensor?.CurrentAmbientLightLevel, 'CurrentAmbientLightLevel', history)
704
788
  }
705
789
  // BatteryLevel
706
- await this.updateCharacteristic(this.Battery.Service, this.hap.Characteristic.BatteryLevel,
707
- this.Battery.BatteryLevel, 'BatteryLevel');
790
+ await this.updateCharacteristic(this.Battery.Service, this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel, 'BatteryLevel')
708
791
  // StatusLowBattery
709
- await this.updateCharacteristic(this.Battery.Service, this.hap.Characteristic.StatusLowBattery,
710
- this.Battery.StatusLowBattery, 'StatusLowBattery');
792
+ await this.updateCharacteristic(this.Battery.Service, this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery, 'StatusLowBattery')
711
793
  // ChargingState
712
- await this.updateCharacteristic(this.Battery.Service, this.hap.Characteristic.ChargingState,
713
- this.Battery.ChargingState, 'ChargingState');
794
+ await this.updateCharacteristic(this.Battery.Service, this.hap.Characteristic.ChargingState, this.Battery.ChargingState, 'ChargingState')
714
795
  }
715
796
 
716
797
  async BLEPushConnection() {
717
798
  if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
718
- await this.warnLog('Using OpenAPI Connection to Push Changes');
719
- await this.openAPIpushChanges();
799
+ await this.warnLog('Using OpenAPI Connection to Push Changes')
800
+ await this.openAPIpushChanges()
720
801
  }
721
802
  }
722
803
 
723
804
  async BLERefreshConnection(switchbot: any): Promise<void> {
724
- await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
805
+ await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`)
725
806
  if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
726
- await this.warnLog('Using OpenAPI Connection to Refresh Status');
727
- await this.openAPIRefreshStatus();
807
+ await this.warnLog('Using OpenAPI Connection to Refresh Status')
808
+ await this.openAPIRefreshStatus()
728
809
  }
729
810
  }
730
811
 
731
812
  async setPerformance() {
732
- let setPositionMode: number;
733
- let Mode: string;
813
+ let setPositionMode: number
814
+ let Mode: string
734
815
  if (Number(this.WindowCovering.TargetPosition) > 50) {
735
- if (this.device.curtain?.setOpenMode === '1') {
736
- setPositionMode = 1;
737
- Mode = 'Silent Mode';
738
- } else if (this.device.curtain?.setOpenMode === '0') {
739
- setPositionMode = 0;
740
- Mode = 'Performance Mode';
816
+ if (this.device.curtain?.setOpenMode === '1' || this.OpenModeSwitch?.On) {
817
+ setPositionMode = 1
818
+ Mode = 'Silent Mode'
819
+ } else if (this.device.curtain?.setOpenMode === '0' || !this.OpenModeSwitch?.On) {
820
+ setPositionMode = 0
821
+ Mode = 'Performance Mode'
741
822
  } else {
742
- setPositionMode = 0;
743
- Mode = 'Default Mode';
823
+ setPositionMode = 0
824
+ Mode = 'Default Mode'
744
825
  }
745
826
  } else {
746
- if (this.device.curtain?.setCloseMode === '1') {
747
- setPositionMode = 1;
748
- Mode = 'Silent Mode';
749
- } else if (this.device.curtain?.setOpenMode === '0') {
750
- setPositionMode = 0;
751
- Mode = 'Performance Mode';
827
+ if (this.device.curtain?.setCloseMode === '1' || this.CloseModeSwitch?.On) {
828
+ setPositionMode = 1
829
+ Mode = 'Silent Mode'
830
+ } else if (this.device.curtain?.setCloseMode === '0' || !this.CloseModeSwitch?.On) {
831
+ setPositionMode = 0
832
+ Mode = 'Performance Mode'
752
833
  } else {
753
- setPositionMode = 0;
754
- Mode = 'Default Mode';
834
+ setPositionMode = 0
835
+ Mode = 'Default Mode'
755
836
  }
756
837
  }
757
- return { setPositionMode, Mode };
838
+ return { setPositionMode, Mode }
758
839
  }
759
840
 
760
841
  async getCurrentPostion() {
761
- await this.setMinMax();
762
- await this.debugLog(`CurrentPosition ${this.WindowCovering.CurrentPosition}`);
842
+ await this.setMinMax()
843
+ await this.debugLog(`CurrentPosition ${this.WindowCovering.CurrentPosition}`)
763
844
  if (this.setNewTarget) {
764
- this.infoLog('Checking Status ...');
765
- await this.setMinMax();
845
+ this.curtainMoving = true
846
+ this.infoLog('Checking Status ...')
847
+ await this.setMinMax()
766
848
  if (this.WindowCovering.TargetPosition > this.WindowCovering.CurrentPosition) {
767
- await this.debugLog(`Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
768
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING;
769
- this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
770
- await this.debugLog(`Increasing, PositionState: ${this.WindowCovering.PositionState}`);
849
+ await this.debugLog(`Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
850
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.INCREASING
851
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState)
852
+ await this.debugLog(`Increasing, PositionState: ${this.WindowCovering.PositionState}`)
771
853
  } else if (this.WindowCovering.TargetPosition < this.WindowCovering.CurrentPosition) {
772
- await this.debugLog(`Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
773
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING;
774
- this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
775
- await this.debugLog(`Decreasing, PositionState: ${this.WindowCovering.PositionState}`);
854
+ await this.debugLog(`Opening, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
855
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.DECREASING
856
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState)
857
+ await this.debugLog(`Decreasing, PositionState: ${this.WindowCovering.PositionState}`)
776
858
  } else {
777
- await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
778
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
779
- this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState);
780
- await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`);
859
+ await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
860
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED
861
+ this.WindowCovering.Service.getCharacteristic(this.hap.Characteristic.PositionState).updateValue(this.WindowCovering.PositionState)
862
+ await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`)
781
863
  }
782
864
  } else {
783
- await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
784
- this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition;
785
- this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED;
786
- await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`);
865
+ this.curtainMoving = false
866
+ await this.debugLog(`Standby, CurrentPosition: ${this.WindowCovering.CurrentPosition}`)
867
+ this.WindowCovering.TargetPosition = this.WindowCovering.CurrentPosition
868
+ this.WindowCovering.PositionState = this.hap.Characteristic.PositionState.STOPPED
869
+ await this.debugLog(`Stopped, PositionState: ${this.WindowCovering.PositionState}`)
787
870
  }
788
- await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition},`
789
- + ` PositionState: ${this.WindowCovering.PositionState},`);
871
+ await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition}, PositionState: ${this.WindowCovering.PositionState},`)
790
872
  }
791
873
 
792
874
  async setMinMax(): Promise<void> {
793
875
  if (this.device.curtain?.set_min) {
794
876
  if (Number(this.WindowCovering.CurrentPosition) <= this.device.curtain?.set_min) {
795
- this.WindowCovering.CurrentPosition = 0;
877
+ this.WindowCovering.CurrentPosition = 0
796
878
  }
797
879
  }
798
880
  if (this.device.curtain?.set_max) {
799
881
  if (Number(this.WindowCovering.CurrentPosition) >= this.device.curtain?.set_max) {
800
- this.WindowCovering.CurrentPosition = 100;
882
+ this.WindowCovering.CurrentPosition = 100
801
883
  }
802
884
  }
803
885
  if (this.device.history) {
804
- const motion = this.accessory.getService(this.hap.Service.MotionSensor);
805
- const state = Number(this.WindowCovering.CurrentPosition) > 0 ? 1 : 0;
806
- motion?.updateCharacteristic(this.hap.Characteristic.MotionDetected, state);
886
+ const motion = this.accessory.getService(this.hap.Service.MotionSensor)
887
+ const state = Number(this.WindowCovering.CurrentPosition) > 0 ? 1 : 0
888
+ motion?.updateCharacteristic(this.hap.Characteristic.MotionDetected, state)
807
889
  }
808
890
  }
809
891
 
810
892
  async offlineOff(): Promise<void> {
811
893
  if (this.device.offline) {
812
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
813
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
814
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
894
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100)
895
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100)
896
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
815
897
  }
816
898
  }
817
899
 
818
900
  async apiError(e: any): Promise<void> {
819
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
820
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e);
821
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
822
- this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
823
- this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
824
- this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, e);
901
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e)
902
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e)
903
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e)
904
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e)
905
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e)
906
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.ChargingState, e)
825
907
  if (!this.device.curtain?.hide_lightsensor && this.LightSensor?.Service) {
826
- this.LightSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, e);
827
- this.LightSensor.Service.updateCharacteristic(this.hap.Characteristic.StatusActive, e);
908
+ this.LightSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, e)
909
+ this.LightSensor.Service.updateCharacteristic(this.hap.Characteristic.StatusActive, e)
828
910
  }
829
911
  }
830
912
  }