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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/.vscode/settings.json +4 -1
  2. package/CHANGELOG.md +4 -1
  3. package/config.schema.json +120 -17
  4. package/dist/device/blindtilt.d.ts +23 -96
  5. package/dist/device/blindtilt.d.ts.map +1 -1
  6. package/dist/device/blindtilt.js +425 -778
  7. package/dist/device/blindtilt.js.map +1 -1
  8. package/dist/device/bot.d.ts +26 -72
  9. package/dist/device/bot.d.ts.map +1 -1
  10. package/dist/device/bot.js +803 -837
  11. package/dist/device/bot.js.map +1 -1
  12. package/dist/device/ceilinglight.d.ts +14 -68
  13. package/dist/device/ceilinglight.d.ts.map +1 -1
  14. package/dist/device/ceilinglight.js +241 -606
  15. package/dist/device/ceilinglight.js.map +1 -1
  16. package/dist/device/colorbulb.d.ts +14 -75
  17. package/dist/device/colorbulb.d.ts.map +1 -1
  18. package/dist/device/colorbulb.js +283 -658
  19. package/dist/device/colorbulb.js.map +1 -1
  20. package/dist/device/contact.d.ts +15 -66
  21. package/dist/device/contact.d.ts.map +1 -1
  22. package/dist/device/contact.js +254 -545
  23. package/dist/device/contact.js.map +1 -1
  24. package/dist/device/curtain.d.ts +19 -88
  25. package/dist/device/curtain.d.ts.map +1 -1
  26. package/dist/device/curtain.js +412 -806
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/device.d.ts +59 -0
  29. package/dist/device/device.d.ts.map +1 -0
  30. package/dist/device/device.js +711 -0
  31. package/dist/device/device.js.map +1 -0
  32. package/dist/device/fan.d.ts +51 -0
  33. package/dist/device/fan.d.ts.map +1 -0
  34. package/dist/device/fan.js +540 -0
  35. package/dist/device/fan.js.map +1 -0
  36. package/dist/device/hub.d.ts +16 -60
  37. package/dist/device/hub.d.ts.map +1 -1
  38. package/dist/device/hub.js +261 -616
  39. package/dist/device/hub.js.map +1 -1
  40. package/dist/device/humidifier.d.ts +11 -66
  41. package/dist/device/humidifier.d.ts.map +1 -1
  42. package/dist/device/humidifier.js +240 -594
  43. package/dist/device/humidifier.js.map +1 -1
  44. package/dist/device/iosensor.d.ts +11 -64
  45. package/dist/device/iosensor.d.ts.map +1 -1
  46. package/dist/device/iosensor.js +196 -600
  47. package/dist/device/iosensor.js.map +1 -1
  48. package/dist/device/lightstrip.d.ts +11 -69
  49. package/dist/device/lightstrip.d.ts.map +1 -1
  50. package/dist/device/lightstrip.js +281 -586
  51. package/dist/device/lightstrip.js.map +1 -1
  52. package/dist/device/lock.d.ts +16 -63
  53. package/dist/device/lock.d.ts.map +1 -1
  54. package/dist/device/lock.js +252 -560
  55. package/dist/device/lock.js.map +1 -1
  56. package/dist/device/meter.d.ts +14 -64
  57. package/dist/device/meter.d.ts.map +1 -1
  58. package/dist/device/meter.js +191 -593
  59. package/dist/device/meter.js.map +1 -1
  60. package/dist/device/meterplus.d.ts +14 -65
  61. package/dist/device/meterplus.d.ts.map +1 -1
  62. package/dist/device/meterplus.js +180 -593
  63. package/dist/device/meterplus.js.map +1 -1
  64. package/dist/device/motion.d.ts +13 -69
  65. package/dist/device/motion.d.ts.map +1 -1
  66. package/dist/device/motion.js +188 -532
  67. package/dist/device/motion.js.map +1 -1
  68. package/dist/device/plug.d.ts +9 -57
  69. package/dist/device/plug.d.ts.map +1 -1
  70. package/dist/device/plug.js +96 -458
  71. package/dist/device/plug.js.map +1 -1
  72. package/dist/device/robotvacuumcleaner.d.ts +12 -63
  73. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  74. package/dist/device/robotvacuumcleaner.js +202 -521
  75. package/dist/device/robotvacuumcleaner.js.map +1 -1
  76. package/dist/device/waterdetector.d.ts +10 -63
  77. package/dist/device/waterdetector.d.ts.map +1 -1
  78. package/dist/device/waterdetector.js +146 -475
  79. package/dist/device/waterdetector.js.map +1 -1
  80. package/dist/homebridge-ui/public/index.html +22 -16
  81. package/dist/homebridge-ui/server.js +1 -1
  82. package/dist/homebridge-ui/server.js.map +1 -1
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +2 -2
  86. package/dist/index.js.map +1 -1
  87. package/dist/irdevice/airconditioner.d.ts +10 -50
  88. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  89. package/dist/irdevice/airconditioner.js +324 -452
  90. package/dist/irdevice/airconditioner.js.map +1 -1
  91. package/dist/irdevice/airpurifier.d.ts +8 -39
  92. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  93. package/dist/irdevice/airpurifier.js +93 -307
  94. package/dist/irdevice/airpurifier.js.map +1 -1
  95. package/dist/irdevice/camera.d.ts +7 -36
  96. package/dist/irdevice/camera.d.ts.map +1 -1
  97. package/dist/irdevice/camera.js +39 -281
  98. package/dist/irdevice/camera.js.map +1 -1
  99. package/dist/irdevice/fan.d.ts +10 -43
  100. package/dist/irdevice/fan.d.ts.map +1 -1
  101. package/dist/irdevice/fan.js +113 -341
  102. package/dist/irdevice/fan.js.map +1 -1
  103. package/dist/irdevice/irdevice.d.ts +40 -0
  104. package/dist/irdevice/irdevice.d.ts.map +1 -0
  105. package/dist/irdevice/irdevice.js +330 -0
  106. package/dist/irdevice/irdevice.js.map +1 -0
  107. package/dist/irdevice/light.d.ts +12 -45
  108. package/dist/irdevice/light.d.ts.map +1 -1
  109. package/dist/irdevice/light.js +118 -362
  110. package/dist/irdevice/light.js.map +1 -1
  111. package/dist/irdevice/other.d.ts +19 -48
  112. package/dist/irdevice/other.d.ts.map +1 -1
  113. package/dist/irdevice/other.js +438 -570
  114. package/dist/irdevice/other.js.map +1 -1
  115. package/dist/irdevice/tv.d.ts +8 -40
  116. package/dist/irdevice/tv.d.ts.map +1 -1
  117. package/dist/irdevice/tv.js +87 -335
  118. package/dist/irdevice/tv.js.map +1 -1
  119. package/dist/irdevice/vacuumcleaner.d.ts +7 -36
  120. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  121. package/dist/irdevice/vacuumcleaner.js +45 -285
  122. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  123. package/dist/irdevice/waterheater.d.ts +7 -36
  124. package/dist/irdevice/waterheater.d.ts.map +1 -1
  125. package/dist/irdevice/waterheater.js +47 -291
  126. package/dist/irdevice/waterheater.js.map +1 -1
  127. package/dist/platform.d.ts +19 -6
  128. package/dist/platform.d.ts.map +1 -1
  129. package/dist/platform.js +310 -172
  130. package/dist/platform.js.map +1 -1
  131. package/dist/settings.d.ts +62 -19
  132. package/dist/settings.d.ts.map +1 -1
  133. package/dist/settings.js +16 -552
  134. package/dist/settings.js.map +1 -1
  135. package/dist/utils.d.ts +77 -0
  136. package/dist/utils.d.ts.map +1 -1
  137. package/dist/utils.js +638 -1
  138. package/dist/utils.js.map +1 -1
  139. package/eslint.config.js +96 -0
  140. package/package.json +19 -15
  141. package/src/custom.d.ts +2 -1
  142. package/src/device/blindtilt.ts +462 -817
  143. package/src/device/bot.ts +862 -931
  144. package/src/device/ceilinglight.ts +259 -633
  145. package/src/device/colorbulb.ts +300 -688
  146. package/src/device/contact.ts +288 -571
  147. package/src/device/curtain.ts +441 -838
  148. package/src/device/device.ts +734 -0
  149. package/src/device/fan.ts +596 -0
  150. package/src/device/hub.ts +299 -645
  151. package/src/device/humidifier.ts +274 -647
  152. package/src/device/iosensor.ts +233 -626
  153. package/src/device/lightstrip.ts +309 -620
  154. package/src/device/lock.ts +292 -601
  155. package/src/device/meter.ts +228 -619
  156. package/src/device/meterplus.ts +216 -619
  157. package/src/device/motion.ts +218 -559
  158. package/src/device/plug.ts +111 -490
  159. package/src/device/robotvacuumcleaner.ts +228 -550
  160. package/src/device/waterdetector.ts +169 -501
  161. package/src/homebridge-ui/public/index.html +22 -16
  162. package/src/homebridge-ui/server.ts +1 -1
  163. package/src/index.ts +4 -3
  164. package/src/irdevice/airconditioner.ts +350 -477
  165. package/src/irdevice/airpurifier.ts +120 -330
  166. package/src/irdevice/camera.ts +53 -301
  167. package/src/irdevice/fan.ts +130 -360
  168. package/src/irdevice/irdevice.ts +346 -0
  169. package/src/irdevice/light.ts +157 -412
  170. package/src/irdevice/other.ts +507 -648
  171. package/src/irdevice/tv.ts +117 -367
  172. package/src/irdevice/vacuumcleaner.ts +59 -311
  173. package/src/irdevice/waterheater.ts +61 -320
  174. package/src/platform.ts +355 -219
  175. package/src/settings.ts +116 -611
  176. package/src/utils.ts +642 -1
  177. package/src/device/waterdetector.json +0 -11
package/src/device/bot.ts CHANGED
@@ -1,114 +1,155 @@
1
+ /* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
+ *
3
+ * bot.ts: @switchbot/homebridge-switchbot.
4
+ */
1
5
  import { request } from 'undici';
2
- import { sleep } from '../utils.js';
6
+ import { deviceBase } from './device.js';
3
7
  import { interval, Subject } from 'rxjs';
4
- import { SwitchBotPlatform } from '../platform.js';
8
+ import { Devices } from '../settings.js';
5
9
  import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
6
- import { Service, PlatformAccessory, CharacteristicValue, API, Logging, HAP } from 'homebridge';
7
- import { device, devicesConfig, deviceStatus, serviceData, Devices, SwitchBotPlatformConfig } from '../settings.js';
10
+
11
+ import type { SwitchBotPlatform } from '../platform.js';
12
+ import type { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
13
+ import type { device, devicesConfig, serviceData, deviceStatus } from '../settings.js';
8
14
 
9
15
  /**
10
16
  * Platform Accessory
11
17
  * An instance of this class is created for each accessory your platform registers
12
18
  * Each accessory may expose multiple services of different service types.
13
19
  */
14
- export class Bot {
15
- public readonly api: API;
16
- public readonly log: Logging;
17
- public readonly config!: SwitchBotPlatformConfig;
18
- protected readonly hap: HAP;
20
+ export class Bot extends deviceBase {
19
21
  // Services
20
- fanService?: Service;
21
- doorService?: Service;
22
- lockService?: Service;
23
- faucetService?: Service;
24
- windowService?: Service;
25
- switchService?: Service;
26
- outletService?: Service;
27
- batteryService: Service;
28
- garageDoorService?: Service;
29
- windowCoveringService?: Service;
30
- statefulProgrammableSwitchService?: Service;
31
-
32
- // Characteristic Values
33
- On!: CharacteristicValue;
34
- BatteryLevel!: CharacteristicValue;
35
- FirmwareRevision!: CharacteristicValue;
36
- StatusLowBattery!: CharacteristicValue;
37
-
38
- // OpenAPI Status
39
- OpenAPI_On: deviceStatus['power'];
40
- OpenAPI_BatteryLevel: deviceStatus['battery'];
41
- OpenAPI_FirmwareRevision: deviceStatus['version'];
42
-
43
- // BLE Status
44
- BLE_On!: serviceData['state'];
45
- BLE_Mode!: serviceData['mode'];
46
- BLE_BatteryLevel!: serviceData['battery'];
47
-
48
- //BLE Others
49
- BLE_IsConnected?: boolean;
22
+ private Battery: {
23
+ Name: CharacteristicValue;
24
+ Service: Service;
25
+ BatteryLevel: CharacteristicValue;
26
+ StatusLowBattery: CharacteristicValue;
27
+ };
28
+
29
+ private Switch?: {
30
+ Name: CharacteristicValue;
31
+ Service: Service;
32
+ On: CharacteristicValue;
33
+ };
34
+
35
+ private GarageDoor?: {
36
+ Name: CharacteristicValue;
37
+ Service: Service;
38
+ On: CharacteristicValue;
39
+ };
40
+
41
+ private Door?: {
42
+ Name: CharacteristicValue;
43
+ Service: Service;
44
+ On: CharacteristicValue;
45
+ };
46
+
47
+ private Window?: {
48
+ Name: CharacteristicValue;
49
+ Service: Service;
50
+ On: CharacteristicValue;
51
+ };
52
+
53
+ private WindowCovering?: {
54
+ Name: CharacteristicValue;
55
+ Service: Service;
56
+ On: CharacteristicValue;
57
+ };
58
+
59
+ private LockMechanism?: {
60
+ Name: CharacteristicValue;
61
+ Service: Service;
62
+ On: CharacteristicValue;
63
+ };
64
+
65
+ private Faucet?: {
66
+ Name: CharacteristicValue;
67
+ Service: Service;
68
+ On: CharacteristicValue;
69
+ };
70
+
71
+ private Fan?: {
72
+ Name: CharacteristicValue;
73
+ Service: Service;
74
+ On: CharacteristicValue;
75
+ };
76
+
77
+ private StatefulProgrammableSwitch?: {
78
+ Name: CharacteristicValue;
79
+ Service: Service;
80
+ On: CharacteristicValue;
81
+ };
82
+
83
+ private Outlet?: {
84
+ Name: CharacteristicValue;
85
+ Service: Service;
86
+ On: CharacteristicValue;
87
+ };
50
88
 
51
89
  // Config
52
90
  botMode!: string;
53
91
  allowPush?: boolean;
54
92
  doublePress!: number;
55
- scanDuration!: number;
56
93
  botDeviceType!: string;
57
94
  pushRatePress!: number;
58
- deviceLogging!: string;
59
95
  multiPressCount!: number;
60
- deviceRefreshRate!: number;
61
96
 
62
97
  // Updates
63
98
  botUpdateInProgress!: boolean;
64
99
  doBotUpdate!: Subject<void>;
65
100
 
66
- // Connection
67
- private readonly OpenAPI: boolean;
68
- private readonly BLE: boolean;
69
-
70
101
  constructor(
71
- private readonly platform: SwitchBotPlatform,
72
- private accessory: PlatformAccessory,
73
- public device: device & devicesConfig,
102
+ readonly platform: SwitchBotPlatform,
103
+ accessory: PlatformAccessory,
104
+ device: device & devicesConfig,
74
105
  ) {
75
- this.api = this.platform.api;
76
- this.log = this.platform.log;
77
- this.config = this.platform.config;
78
- this.hap = this.api.hap;
79
- // Connection
80
- this.BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI';
81
- this.OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI';
106
+ super(platform, accessory, device);
82
107
  // default placeholders
83
- this.deviceLogs(device);
84
- this.deviceType(device);
85
- this.scan(device);
86
- this.refreshRate(device);
87
- this.PressOrSwitch(device);
88
- this.allowPushChanges(device);
89
- this.deviceContext();
90
- this.DoublePress(device);
91
- this.deviceConfig(device);
92
-
93
- this.multiPressCount = 0;
108
+ this.getBotConfigSettings(device);
94
109
 
95
110
  // this is subject we use to track when we need to POST changes to the SwitchBot API
96
111
  this.doBotUpdate = new Subject();
97
112
  this.botUpdateInProgress = false;
98
113
 
99
- // Retrieve initial values and updateHomekit
100
- this.refreshStatus();
101
-
102
- // set accessory information
103
- accessory
104
- .getService(this.hap.Service.AccessoryInformation)!
105
- .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
106
- .setCharacteristic(this.hap.Characteristic.Model, 'SWITCHBOT-BOT-S1')
107
- .setCharacteristic(this.hap.Characteristic.SerialNumber, device.deviceId)
108
- .setCharacteristic(this.hap.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision);
114
+ accessory.context.Battery = accessory.context.Battery ?? {};
115
+ // Initialize Battery property
116
+ this.Battery = {
117
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
118
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
119
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
120
+ StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
121
+ };
122
+ accessory.context.Battery = this.Battery as object;
123
+
124
+ // Initialize Battery Characteristics
125
+ this.Battery.Service
126
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
127
+ .setCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery)
128
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
109
129
 
110
130
  // deviceType
111
131
  if (this.botDeviceType === 'switch') {
132
+ // Initialize Switch Service
133
+ accessory.context.Switch = accessory.context.Switch ?? {};
134
+ this.Switch = {
135
+ Name: accessory.context.Switch.Name ?? accessory.displayName,
136
+ Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch) as Service,
137
+ On: accessory.context.On ?? false,
138
+ };
139
+ accessory.context.Switch = this.Switch as object;
140
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Switch`);
141
+
142
+ // Initialize Switch Characteristics
143
+ this.Switch.Service
144
+ .setCharacteristic(this.hap.Characteristic.Name, this.Switch.Name)
145
+ .setCharacteristic(this.hap.Characteristic.On, this.Switch.On)
146
+ .getCharacteristic(this.hap.Characteristic.On)
147
+ .onGet(() => {
148
+ return this.Switch!.On;
149
+ })
150
+ .onSet(this.OnSet.bind(this));
151
+
152
+ // Remove other services
112
153
  this.removeFanService(accessory);
113
154
  this.removeLockService(accessory);
114
155
  this.removeDoorService(accessory);
@@ -118,19 +159,33 @@ export class Bot {
118
159
  this.removeGarageDoorService(accessory);
119
160
  this.removeWindowCoveringService(accessory);
120
161
  this.removeStatefulProgrammableSwitchService(accessory);
162
+ } else if (this.botDeviceType === 'garagedoor') {
163
+ // Initialize GarageDoor Service
164
+ accessory.context.GarageDoor = accessory.context.GarageDoor ?? {};
165
+ this.GarageDoor = {
166
+ Name: accessory.context.GarageDoor.Name ?? accessory.displayName,
167
+ Service: accessory.getService(this.hap.Service.GarageDoorOpener) ?? accessory.addService(this.hap.Service.GarageDoorOpener) as Service,
168
+ On: accessory.context.On ?? false,
169
+ };
170
+ accessory.context.GarageDoor = this.GarageDoor as object;
171
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Garage Door Opener`);
121
172
 
122
- // Add switchService
123
- const switchService = `${accessory.displayName} Switch`;
124
- (this.switchService = accessory.getService(this.hap.Service.Switch)
125
- || accessory.addService(this.hap.Service.Switch)), switchService;
126
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Switch`);
173
+ // Initialize GarageDoor Characteristics
174
+ this.GarageDoor.Service
175
+ .setCharacteristic(this.hap.Characteristic.Name, this.GarageDoor.Name)
176
+ .setCharacteristic(this.hap.Characteristic.ObstructionDetected, false)
177
+ .getCharacteristic(this.hap.Characteristic.TargetDoorState).setProps({
178
+ validValues: [0, 100],
179
+ minValue: 0,
180
+ maxValue: 100,
181
+ minStep: 100,
182
+ })
183
+ .onGet(() => {
184
+ return this.GarageDoor!.On;
185
+ })
186
+ .onSet(this.OnSet.bind(this));
127
187
 
128
- this.switchService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
129
- if (!this.switchService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
130
- this.switchService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
131
- }
132
- this.switchService.getCharacteristic(this.hap.Characteristic.On).onSet(this.OnSet.bind(this));
133
- } else if (this.botDeviceType === 'garagedoor') {
188
+ // Remove other services
134
189
  this.removeFanService(accessory);
135
190
  this.removeLockService(accessory);
136
191
  this.removeDoorService(accessory);
@@ -140,20 +195,33 @@ export class Bot {
140
195
  this.removeWindowService(accessory);
141
196
  this.removeWindowCoveringService(accessory);
142
197
  this.removeStatefulProgrammableSwitchService(accessory);
198
+ } else if (this.botDeviceType === 'door') {
199
+ // Initialize Door Service
200
+ accessory.context.Door = accessory.context.Door ?? {};
201
+ this.Door = {
202
+ Name: accessory.context.Door.Name ?? accessory.displayName,
203
+ Service: accessory.getService(this.hap.Service.Door) ?? accessory.addService(this.hap.Service.Door) as Service,
204
+ On: accessory.context.On ?? false,
205
+ };
206
+ accessory.context.Door = this.Door as object;
207
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Door`);
143
208
 
144
- // Add garageDoorService
145
- const garageDoorService = `${accessory.displayName} Garage Door Opener`;
146
- (this.garageDoorService = accessory.getService(this.hap.Service.GarageDoorOpener)
147
- || accessory.addService(this.hap.Service.GarageDoorOpener)), garageDoorService;
148
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Garage Door Opener`);
209
+ // Initialize Door Characteristics
210
+ this.Door.Service
211
+ .setCharacteristic(this.hap.Characteristic.Name, this.Door.Name)
212
+ .setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
213
+ .getCharacteristic(this.hap.Characteristic.TargetPosition).setProps({
214
+ validValues: [0, 100],
215
+ minValue: 0,
216
+ maxValue: 100,
217
+ minStep: 100,
218
+ })
219
+ .onGet(() => {
220
+ return this.Door!.On;
221
+ })
222
+ .onSet(this.OnSet.bind(this));
149
223
 
150
- this.garageDoorService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
151
- if (!this.garageDoorService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
152
- this.garageDoorService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
153
- }
154
- this.garageDoorService.getCharacteristic(this.hap.Characteristic.TargetDoorState).onSet(this.OnSet.bind(this));
155
- this.garageDoorService.setCharacteristic(this.hap.Characteristic.ObstructionDetected, false);
156
- } else if (this.botDeviceType === 'door') {
224
+ // Remove other services
157
225
  this.removeFanService(accessory);
158
226
  this.removeLockService(accessory);
159
227
  this.removeOutletService(accessory);
@@ -163,28 +231,33 @@ export class Bot {
163
231
  this.removeGarageDoorService(accessory);
164
232
  this.removeWindowCoveringService(accessory);
165
233
  this.removeStatefulProgrammableSwitchService(accessory);
234
+ } else if (this.botDeviceType === 'window') {
235
+ // Initialize Window Service
236
+ accessory.context.Window = accessory.context.Window ?? {};
237
+ this.Window = {
238
+ Name: accessory.context.Window.Name ?? accessory.displayName,
239
+ Service: accessory.getService(this.hap.Service.Window) ?? accessory.addService(this.hap.Service.Window) as Service,
240
+ On: accessory.context.On ?? false,
241
+ };
242
+ accessory.context.Window = this.Window as object;
243
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window`);
166
244
 
167
- // Add doorService
168
- const doorService = `${accessory.displayName} Door`;
169
- (this.doorService = accessory.getService(this.hap.Service.Door)
170
- || accessory.addService(this.hap.Service.Door)), doorService;
171
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Door`);
172
-
173
- this.doorService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
174
- if (!this.doorService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
175
- this.doorService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
176
- }
177
- this.doorService
178
- .getCharacteristic(this.hap.Characteristic.TargetPosition)
179
- .setProps({
245
+ // Initialize Window Characteristics
246
+ this.Window.Service
247
+ .setCharacteristic(this.hap.Characteristic.Name, this.Window.Name)
248
+ .setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
249
+ .getCharacteristic(this.hap.Characteristic.TargetPosition).setProps({
180
250
  validValues: [0, 100],
181
251
  minValue: 0,
182
252
  maxValue: 100,
183
253
  minStep: 100,
184
254
  })
255
+ .onGet(() => {
256
+ return this.Window!.On;
257
+ })
185
258
  .onSet(this.OnSet.bind(this));
186
- this.doorService.setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
187
- } else if (this.botDeviceType === 'window') {
259
+
260
+ // Remove other services
188
261
  this.removeFanService(accessory);
189
262
  this.removeLockService(accessory);
190
263
  this.removeDoorService(accessory);
@@ -194,28 +267,33 @@ export class Bot {
194
267
  this.removeGarageDoorService(accessory);
195
268
  this.removeWindowCoveringService(accessory);
196
269
  this.removeStatefulProgrammableSwitchService(accessory);
270
+ } else if (this.botDeviceType === 'windowcovering') {
271
+ // Initialize WindowCovering Service
272
+ accessory.context.WindowCovering = accessory.context.WindowCovering ?? {};
273
+ this.WindowCovering = {
274
+ Name: accessory.context.WindowCovering.Name ?? accessory.displayName,
275
+ Service: accessory.getService(this.hap.Service.WindowCovering) ?? accessory.addService(this.hap.Service.WindowCovering) as Service,
276
+ On: accessory.context.On ?? false,
277
+ };
278
+ accessory.context.WindowCovering = this.WindowCovering as object;
279
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window Covering`);
197
280
 
198
- // Add windowService
199
- const windowService = `${accessory.displayName} Window`;
200
- (this.windowService = accessory.getService(this.hap.Service.Window)
201
- || accessory.addService(this.hap.Service.Window)), windowService;
202
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window`);
203
-
204
- this.windowService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
205
- if (!this.windowService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
206
- this.windowService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
207
- }
208
- this.windowService
209
- .getCharacteristic(this.hap.Characteristic.TargetPosition)
210
- .setProps({
281
+ // Initialize WindowCovering Characteristics
282
+ this.WindowCovering.Service
283
+ .setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name)
284
+ .setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
285
+ .getCharacteristic(this.hap.Characteristic.TargetPosition).setProps({
211
286
  validValues: [0, 100],
212
287
  minValue: 0,
213
288
  maxValue: 100,
214
289
  minStep: 100,
215
290
  })
291
+ .onGet(() => {
292
+ return this.WindowCovering!.On;
293
+ })
216
294
  .onSet(this.OnSet.bind(this));
217
- this.windowService.setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
218
- } else if (this.botDeviceType === 'windowcovering') {
295
+
296
+ // Remove other services
219
297
  this.removeFanService(accessory);
220
298
  this.removeLockService(accessory);
221
299
  this.removeDoorService(accessory);
@@ -225,28 +303,27 @@ export class Bot {
225
303
  this.removeWindowService(accessory);
226
304
  this.removeGarageDoorService(accessory);
227
305
  this.removeStatefulProgrammableSwitchService(accessory);
306
+ } else if (this.botDeviceType === 'lock') {
307
+ // Initialize Lock Service
308
+ accessory.context.LockMechanism = accessory.context.LockMechanism ?? {};
309
+ this.LockMechanism = {
310
+ Name: accessory.context.LockMechanism.Name ?? accessory.displayName,
311
+ Service: accessory.getService(this.hap.Service.LockMechanism) ?? accessory.addService(this.hap.Service.LockMechanism) as Service,
312
+ On: accessory.context.On ?? false,
313
+ };
314
+ accessory.context.LockMechanism = this.LockMechanism as object;
315
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Lock`);
228
316
 
229
- // Add windowCoveringService
230
- const windowCoveringService = `${accessory.displayName} Window Covering`;
231
- (this.windowCoveringService = accessory.getService(this.hap.Service.WindowCovering)
232
- || accessory.addService(this.hap.Service.WindowCovering)), windowCoveringService;
233
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window Covering`);
234
-
235
- this.windowCoveringService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
236
- if (!this.windowCoveringService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
237
- this.windowCoveringService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
238
- }
239
- this.windowCoveringService
240
- .getCharacteristic(this.hap.Characteristic.TargetPosition)
241
- .setProps({
242
- validValues: [0, 100],
243
- minValue: 0,
244
- maxValue: 100,
245
- minStep: 100,
317
+ // Initialize Lock Characteristics
318
+ this.LockMechanism.Service
319
+ .setCharacteristic(this.hap.Characteristic.Name, this.LockMechanism.Name)
320
+ .getCharacteristic(this.hap.Characteristic.LockTargetState)
321
+ .onGet(() => {
322
+ return this.LockMechanism!.On;
246
323
  })
247
324
  .onSet(this.OnSet.bind(this));
248
- this.windowCoveringService.setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
249
- } else if (this.botDeviceType === 'lock') {
325
+
326
+ // Remove other services
250
327
  this.removeFanService(accessory);
251
328
  this.removeDoorService(accessory);
252
329
  this.removeOutletService(accessory);
@@ -256,19 +333,27 @@ export class Bot {
256
333
  this.removeGarageDoorService(accessory);
257
334
  this.removeWindowCoveringService(accessory);
258
335
  this.removeStatefulProgrammableSwitchService(accessory);
336
+ } else if (this.botDeviceType === 'faucet') {
337
+ // Initialize Faucet Service
338
+ accessory.context.Faucet = accessory.context.Faucet ?? {};
339
+ this.Faucet = {
340
+ Name: accessory.context.Faucet.Name ?? accessory.displayName,
341
+ Service: accessory.getService(this.hap.Service.Faucet) ?? accessory.addService(this.hap.Service.Faucet) as Service,
342
+ On: accessory.context.On ?? false,
343
+ };
344
+ accessory.context.Faucet = this.Faucet as object;
345
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Faucet`);
259
346
 
260
- // Add lockService
261
- const lockService = `${accessory.displayName} Lock`;
262
- (this.lockService = accessory.getService(this.hap.Service.LockMechanism)
263
- || accessory.addService(this.hap.Service.LockMechanism)), lockService;
264
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Lock`);
347
+ // Initialize Faucet Characteristics
348
+ this.Faucet.Service
349
+ .setCharacteristic(this.hap.Characteristic.Name, this.Faucet.Name)
350
+ .getCharacteristic(this.hap.Characteristic.Active)
351
+ .onGet(() => {
352
+ return this.Faucet!.On;
353
+ })
354
+ .onSet(this.OnSet.bind(this));
265
355
 
266
- this.lockService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
267
- if (!this.lockService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
268
- this.lockService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
269
- }
270
- this.lockService.getCharacteristic(this.hap.Characteristic.LockTargetState).onSet(this.OnSet.bind(this));
271
- } else if (this.botDeviceType === 'faucet') {
356
+ // Remove other services
272
357
  this.removeFanService(accessory);
273
358
  this.removeLockService(accessory);
274
359
  this.removeDoorService(accessory);
@@ -278,19 +363,27 @@ export class Bot {
278
363
  this.removeGarageDoorService(accessory);
279
364
  this.removeWindowCoveringService(accessory);
280
365
  this.removeStatefulProgrammableSwitchService(accessory);
366
+ } else if (this.botDeviceType === 'fan') {
367
+ // Initialize Fan Service
368
+ accessory.context.Fan = accessory.context.Fan ?? {};
369
+ this.Fan = {
370
+ Name: accessory.context.Fan.Name ?? accessory.displayName,
371
+ Service: accessory.getService(this.hap.Service.Fanv2) ?? accessory.addService(this.hap.Service.Fanv2) as Service,
372
+ On: accessory.context.On ?? false,
373
+ };
374
+ accessory.context.Fan = this.Fan as object;
375
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Fan`);
281
376
 
282
- // Add faucetService
283
- const faucetService = `${accessory.displayName} Faucet`;
284
- (this.faucetService = accessory.getService(this.hap.Service.Faucet)
285
- || accessory.addService(this.hap.Service.Faucet)), faucetService;
286
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Faucet`);
377
+ // Initialize Fan Characteristics
378
+ this.Fan.Service
379
+ .setCharacteristic(this.hap.Characteristic.Name, this.Fan.Name)
380
+ .getCharacteristic(this.hap.Characteristic.On)
381
+ .onGet(() => {
382
+ return this.Fan!.On;
383
+ })
384
+ .onSet(this.OnSet.bind(this));
287
385
 
288
- this.faucetService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
289
- if (!this.faucetService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
290
- this.faucetService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
291
- }
292
- this.faucetService.getCharacteristic(this.hap.Characteristic.Active).onSet(this.OnSet.bind(this));
293
- } else if (this.botDeviceType === 'fan') {
386
+ // Remove other services
294
387
  this.removeLockService(accessory);
295
388
  this.removeDoorService(accessory);
296
389
  this.removeFaucetService(accessory);
@@ -300,19 +393,28 @@ export class Bot {
300
393
  this.removeGarageDoorService(accessory);
301
394
  this.removeWindowCoveringService(accessory);
302
395
  this.removeStatefulProgrammableSwitchService(accessory);
396
+ } else if (this.botDeviceType === 'stateful') {
397
+ // Initialize StatefulProgrammableSwitch Service
398
+ accessory.context.StatefulProgrammableSwitch = accessory.context.StatefulProgrammableSwitch ?? {};
399
+ this.StatefulProgrammableSwitch = {
400
+ Name: accessory.context.StatefulProgrammableSwitch.Name ?? accessory.displayName,
401
+ Service: accessory.getService(this.hap.Service.StatefulProgrammableSwitch)
402
+ ?? accessory.addService(this.hap.Service.StatefulProgrammableSwitch) as Service,
403
+ On: accessory.context.On ?? false,
404
+ };
405
+ accessory.context.StatefulProgrammableSwitch = this.StatefulProgrammableSwitch as object;
406
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Stateful Programmable Switch`);
303
407
 
304
- // Add fanService
305
- const fanService = `${accessory.displayName} Fan`;
306
- (this.fanService = accessory.getService(this.hap.Service.Fan)
307
- || accessory.addService(this.hap.Service.Fan)), fanService;
308
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Fan`);
408
+ // Initialize StatefulProgrammableSwitch Characteristics
409
+ this.StatefulProgrammableSwitch.Service
410
+ .setCharacteristic(this.hap.Characteristic.Name, this.StatefulProgrammableSwitch.Name)
411
+ .getCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState)
412
+ .onGet(() => {
413
+ return this.StatefulProgrammableSwitch!.On;
414
+ })
415
+ .onSet(this.OnSet.bind(this));
309
416
 
310
- this.fanService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
311
- if (!this.fanService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
312
- this.fanService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
313
- }
314
- this.fanService.getCharacteristic(this.hap.Characteristic.On).onSet(this.OnSet.bind(this));
315
- } else if (this.botDeviceType === 'stateful') {
417
+ // Remove other services
316
418
  this.removeFanService(accessory);
317
419
  this.removeLockService(accessory);
318
420
  this.removeDoorService(accessory);
@@ -322,21 +424,27 @@ export class Bot {
322
424
  this.removeWindowService(accessory);
323
425
  this.removeGarageDoorService(accessory);
324
426
  this.removeWindowCoveringService(accessory);
427
+ } else {
428
+ // Initialize Switch property
429
+ accessory.context.Outlet = accessory.context.Outlet ?? {};
430
+ this.Outlet = {
431
+ Name: accessory.context.Outlet.Name ?? accessory.displayName,
432
+ Service: accessory.getService(this.hap.Service.Outlet) ?? accessory.addService(this.hap.Service.Outlet) as Service,
433
+ On: accessory.context.On ?? false,
434
+ };
435
+ accessory.context.Outlet = this.Outlet as object;
436
+ this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Outlet`);
325
437
 
326
- // Add statefulProgrammableSwitchService
327
- const statefulProgrammableSwitchService = `${accessory.displayName} Stateful Programmable Switch`;
328
- (this.statefulProgrammableSwitchService = accessory.getService(this.hap.Service.StatefulProgrammableSwitch) ||
329
- accessory.addService(this.hap.Service.StatefulProgrammableSwitch)), statefulProgrammableSwitchService;
330
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Stateful Programmable Switch`);
331
-
332
- this.statefulProgrammableSwitchService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
333
- if (!this.statefulProgrammableSwitchService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
334
- this.statefulProgrammableSwitchService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
335
- }
336
- this.statefulProgrammableSwitchService
337
- .getCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState)
438
+ // Initialize Outlet Characteristics
439
+ this.Outlet.Service
440
+ .setCharacteristic(this.hap.Characteristic.Name, this.Outlet.Name)
441
+ .getCharacteristic(this.hap.Characteristic.On)
442
+ .onGet(() => {
443
+ return this.Outlet!.On;
444
+ })
338
445
  .onSet(this.OnSet.bind(this));
339
- } else {
446
+
447
+ // Remove other services
340
448
  this.removeFanService(accessory);
341
449
  this.removeLockService(accessory);
342
450
  this.removeDoorService(accessory);
@@ -346,30 +454,10 @@ export class Bot {
346
454
  this.removeGarageDoorService(accessory);
347
455
  this.removeWindowCoveringService(accessory);
348
456
  this.removeStatefulProgrammableSwitchService(accessory);
349
-
350
- // Add outletService
351
- const outletService = `${accessory.displayName} Outlet`;
352
- (this.outletService = accessory.getService(this.hap.Service.Outlet)
353
- || accessory.addService(this.hap.Service.Outlet)), outletService;
354
- this.debugWarnLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Outlet`);
355
-
356
- this.outletService.setCharacteristic(this.hap.Characteristic.Name, accessory.displayName);
357
- if (!this.outletService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
358
- this.outletService.addCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName);
359
- }
360
- this.outletService.getCharacteristic(this.hap.Characteristic.On).onSet(this.OnSet.bind(this));
361
457
  }
362
458
 
363
- // batteryService
364
- const batteryService = `${accessory.displayName} Battery`;
365
- (this.batteryService = this.accessory.getService(this.hap.Service.Battery)
366
- || accessory.addService(this.hap.Service.Battery)), batteryService;
367
-
368
- this.batteryService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Battery`);
369
- if (!this.batteryService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
370
- this.batteryService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Battery`);
371
- }
372
- this.batteryService.setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
459
+ // Retrieve initial values and updateHomekit
460
+ this.refreshStatus();
373
461
 
374
462
  // Retrieve initial values and updateHomekit
375
463
  this.updateHomeKitCharacteristics();
@@ -382,19 +470,21 @@ export class Bot {
382
470
  });
383
471
 
384
472
  //regisiter webhook event handler
385
- if (this.device.webhook) {
386
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
473
+ if (device.webhook) {
474
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
387
475
  this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
388
476
  try {
389
477
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
390
478
  const { power, battery, deviceMode } = context;
391
- const { On, BatteryLevel, botMode } = this;
479
+ const { botMode } = this;
480
+ const On = await this.getOn();
481
+ const { BatteryLevel } = this.Battery;
392
482
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
393
483
  '(power, battery, deviceMode) = ' +
394
484
  `Webhook:(${power}, ${battery}, ${deviceMode}), ` +
395
485
  `current:(${On}, ${BatteryLevel}, ${botMode})`);
396
- this.On = power;
397
- this.BatteryLevel = battery;
486
+ await this.setOn(power);
487
+ this.Battery.BatteryLevel = battery;
398
488
  this.botMode = deviceMode;
399
489
  this.updateHomeKitCharacteristics();
400
490
  } catch (e: any) {
@@ -436,80 +526,82 @@ export class Bot {
436
526
  }
437
527
 
438
528
  /**
439
- * Parse the device status from the SwitchBot api
529
+ * Parse the device status from the SwitchBotBLE API
440
530
  */
441
- async parseStatus(): Promise<void> {
442
- if (!this.device.enableCloudService && this.OpenAPI) {
443
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`);
444
- } else if (this.BLE) {
445
- await this.BLEparseStatus();
446
- } else if (this.OpenAPI && this.platform.config.credentials?.token) {
447
- await this.openAPIparseStatus();
448
- } else {
449
- await this.offlineOff();
450
- this.debugWarnLog(
451
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`,
452
- );
453
- }
454
- }
455
-
456
- async BLEparseStatus(): Promise<void> {
531
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
457
532
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
458
533
  // BLEmode (true if Switch Mode) | (false if Press Mode)
459
- if (this.BLE_Mode) {
460
- this.accessory.context.On = this.On;
461
- if (this.On === undefined) {
462
- this.On = Boolean(this.BLE_On);
534
+ if (serviceData.mode) {
535
+ this.accessory.context.On = await this.getOn();
536
+ if (this.getOn() === undefined) {
537
+ this.setOn(Boolean(serviceData.state));
463
538
  }
464
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, mode: ${this.BLE_Mode}, On: ${this.On}`);
539
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode,`
540
+ + ` mode: ${serviceData.mode}, On: ${this.accessory.context.On}`);
465
541
  } else {
466
- this.On = false;
467
- this.accessory.context.On = this.On;
468
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Press Mode, mode: ${this.BLE_Mode}, On: ${this.On}`);
542
+ this.setOn(false);
543
+ this.accessory.context.On = await this.getOn();
544
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Press Mode,`
545
+ + ` mode: ${serviceData.mode}, On: ${this.accessory.context.On}`);
469
546
  }
470
547
 
471
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
472
- if (this.BatteryLevel < 10) {
473
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
548
+ this.Battery.BatteryLevel = Number(serviceData.battery);
549
+ if (this.Battery.BatteryLevel < 10) {
550
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
474
551
  } else {
475
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
552
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
476
553
  }
477
- if (Number.isNaN(this.BatteryLevel)) {
478
- this.BatteryLevel = 100;
554
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
555
+ this.Battery.BatteryLevel = 100;
479
556
  }
480
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},`
481
- + ` StatusLowBattery: ${this.StatusLowBattery}`);
557
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
558
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
482
559
  }
483
560
 
484
- async openAPIparseStatus(): Promise<void> {
561
+
562
+ /**
563
+ * Parse the device status from the SwitchBot OpenAPI
564
+ */
565
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
485
566
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
486
567
  if (this.botMode === 'press') {
487
- this.On = false;
488
- this.accessory.context.On = this.On;
568
+ this.setOn(false);
569
+ this.accessory.context.On = await this.getOn();
489
570
  } else {
490
- this.accessory.context.On = this.On;
491
- if (this.On === undefined) {
492
- this.On = false;
571
+ this.accessory.context.On = await this.getOn();
572
+ if (this.getOn() === undefined) {
573
+ this.setOn(false);
493
574
  }
494
575
  }
495
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
576
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.accessory.context.On}`);
496
577
 
497
578
  // Battery
498
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
499
- if (this.BatteryLevel < 10) {
500
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
579
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
580
+ if (this.Battery.BatteryLevel < 10) {
581
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
501
582
  } else {
502
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
583
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
584
+ }
585
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
586
+ this.Battery.BatteryLevel = 100;
587
+ }
588
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel},`
589
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
590
+
591
+ // Firmware Version
592
+ const version = deviceStatus.body.version?.toString();
593
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
594
+ if (deviceStatus.body.version) {
595
+ const deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
596
+ this.accessory
597
+ .getService(this.hap.Service.AccessoryInformation)!
598
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
599
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
600
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
601
+ .updateValue(deviceVersion);
602
+ this.accessory.context.deviceVersion = deviceVersion;
603
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
503
604
  }
504
- if (Number.isNaN(this.BatteryLevel)) {
505
- this.BatteryLevel = 100;
506
- }
507
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},`
508
- + ` StatusLowBattery: ${this.StatusLowBattery}`);
509
-
510
- // FirmwareRevision
511
- this.FirmwareRevision = this.OpenAPI_FirmwareRevision!;
512
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
513
605
  }
514
606
 
515
607
  /**
@@ -544,99 +636,43 @@ export class Bot {
544
636
  // Start to monitor advertisement packets
545
637
  (async () => {
546
638
  // Start to monitor advertisement packets
547
- await switchbot.startScan({
548
- model: 'H',
549
- id: this.device.bleMac,
550
- });
639
+ await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
551
640
  // Set an event handler
552
641
  switchbot.onadvertisement = (ad: any) => {
553
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
554
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
555
- if (this.device.bleMac === ad.address && ad.model === 'H') {
642
+ if (this.device.bleMac === ad.address && ad.model === this.device.bleModel) {
643
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
644
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
556
645
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
557
- this.BLE_Mode = ad.serviceData.mode;
558
- this.BLE_On = ad.serviceData.state;
559
- this.BLE_BatteryLevel = ad.serviceData.battery;
560
646
  } else {
561
647
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
562
648
  }
563
649
  };
564
- // Wait 1 seconds
650
+ // Wait 10 seconds
565
651
  await switchbot.wait(this.scanDuration * 1000);
566
652
  // Stop to monitor
567
653
  await switchbot.stopScan();
568
654
  // Update HomeKit
569
- await this.BLEparseStatus();
655
+ await this.BLEparseStatus(switchbot.onadvertisement.serviceData);
570
656
  await this.updateHomeKitCharacteristics();
571
657
  })();
572
- /*if (switchbot !== false) {
573
- switchbot
574
- .startScan({
575
- model: 'H',
576
- id: this.device.bleMac,
577
- })
578
- .then(async () => {
579
- // Set an event handler
580
- switchbot.onadvertisement = async (ad: ad) => {
581
- this.debugLog(
582
- `${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},` +
583
- ` BLE Address Found: ${ad.address}`,
584
- );
585
- this.BLE_Mode = ad.serviceData.mode;
586
- this.BLE_On = ad.serviceData.state;
587
- this.BLE_BatteryLevel = ad.serviceData.battery;
588
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
589
- this.debugLog(
590
- `${this.device.deviceType}: ${this.accessory.displayName}, model: ${ad.serviceData.model}, modelName: ` +
591
- `${ad.serviceData.modelName}, mode: ${ad.serviceData.mode}, state: ${ad.serviceData.state}, battery: ${ad.serviceData.battery}`,
592
- );
593
-
594
- if (ad.serviceData) {
595
- this.BLE_IsConnected = true;
596
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
597
- await this.stopScanning(switchbot);
598
- } else {
599
- this.BLE_IsConnected = false;
600
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.BLE_IsConnected}`);
601
- }
602
- };
603
- // Wait
604
- return await sleep(this.scanDuration * 1000);
605
- })
606
- .then(async () => {
607
- // Stop to monitor
608
- await this.stopScanning(switchbot);
609
- })
610
- .catch(async (e: any) => {
611
- this.apiError(e);
612
- this.errorLog(
613
- `${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}` +
614
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
615
- );
616
- await this.BLERefreshConnection(switchbot);
617
- });
618
- } else {
658
+ if (switchbot === undefined) {
619
659
  await this.BLERefreshConnection(switchbot);
620
- }*/
660
+ }
621
661
  }
622
662
 
623
663
  async openAPIRefreshStatus(): Promise<void> {
624
664
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
625
665
  try {
626
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
627
- headers: this.platform.generateHeaders(),
628
- });
666
+ const { body, statusCode } = await this.platform.retryRequest(this.deviceMaxRetries, this.deviceDelayBetweenRetries,
667
+ `${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders() });
629
668
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
630
669
  const deviceStatus: any = await body.json();
631
670
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
632
671
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
633
672
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
634
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
673
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
635
674
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
636
- this.OpenAPI_On = deviceStatus.body.power;
637
- this.OpenAPI_BatteryLevel = deviceStatus.body.battery;
638
- this.OpenAPI_FirmwareRevision = deviceStatus.body.version;
639
- this.openAPIparseStatus();
675
+ this.openAPIparseStatus(deviceStatus);
640
676
  this.updateHomeKitCharacteristics();
641
677
  } else {
642
678
  this.statusCode(statusCode);
@@ -682,8 +718,9 @@ export class Bot {
682
718
 
683
719
  async BLEpushChanges(): Promise<void> {
684
720
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
685
- if (this.On !== this.accessory.context.On || this.allowPush) {
686
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
721
+ const On = await this.getOn();
722
+ if (On !== this.accessory.context.On || this.allowPush) {
723
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${On} OnCached: ${this.accessory.context.On}`);
687
724
  const switchbot = await this.platform.connectBLE();
688
725
  // Convert to BLE Address
689
726
  this.device.bleMac = this.device
@@ -697,19 +734,21 @@ export class Bot {
697
734
  switchbot
698
735
  .discover({ model: 'H', quick: true, id: this.device.bleMac })
699
736
  .then(async (device_list: { press: (arg0: { id: string | undefined }) => any }[]) => {
700
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
737
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${On}`);
701
738
  return await device_list[0].press({ id: this.device.bleMac });
702
739
  })
703
740
  .then(() => {
704
741
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
705
- this.accessory.context.On = this.On;
742
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
743
+ + `On: ${On} sent over BLE, sent successfully`);
744
+ this.accessory.context.On = On;
706
745
  setTimeout(() => {
707
746
  if (this.botDeviceType === 'switch') {
708
- this.switchService?.getCharacteristic(this.hap.Characteristic.On).updateValue(this.On);
747
+ this.Switch?.Service.getCharacteristic(this.hap.Characteristic.On).updateValue(On);
709
748
  } else {
710
- this.outletService?.getCharacteristic(this.hap.Characteristic.On).updateValue(this.On);
749
+ this.Outlet?.Service.getCharacteristic(this.hap.Characteristic.On).updateValue(On);
711
750
  }
712
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}, Switch Timeout`);
751
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${On}, Switch Timeout`);
713
752
  }, 500);
714
753
  })
715
754
  .catch(async (e: any) => {
@@ -725,11 +764,11 @@ export class Bot {
725
764
  switchbot
726
765
  .discover({ model: 'H', quick: true, id: this.device.bleMac })
727
766
  .then(async (device_list: any) => {
728
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
729
- return await this.retry({
730
- max: this.maxRetry(),
767
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${On}`);
768
+ return await this.retryBLE({
769
+ max: await this.maxRetryBLE(),
731
770
  fn: async () => {
732
- if (this.On) {
771
+ if (On) {
733
772
  return await device_list[0].turnOn({ id: this.device.bleMac });
734
773
  } else {
735
774
  return await device_list[0].turnOff({ id: this.device.bleMac });
@@ -739,46 +778,43 @@ export class Bot {
739
778
  })
740
779
  .then(() => {
741
780
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
742
- this.accessory.context.On = this.On;
781
+ this.accessory.context.On = On;
743
782
  })
744
783
  .catch(async (e: any) => {
745
784
  this.apiError(e);
746
- this.errorLog(
747
- `${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}` +
748
- ` Connection & botMode: ${this.botMode}, Error Message: ${JSON.stringify(e.message)}`,
749
- );
785
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
786
+ + ` Connection & botMode: ${this.botMode}, Error Message: ${JSON.stringify(e.message)}`);
750
787
  await this.BLEPushConnection();
751
788
  });
752
789
  } else {
753
790
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
754
791
  }
755
792
  } else {
756
- this.debugLog(
757
- `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, ` + `OnCached: ${this.accessory.context.On}`,
758
- );
793
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, On: ${On}, OnCached: ${this.accessory.context.On}`);
759
794
  }
760
795
  }
761
796
 
762
797
  async openAPIpushChanges(): Promise<void> {
763
798
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
799
+ let On = await this.getOn();
764
800
  if (this.multiPressCount > 0) {
765
801
  this.debugLog(`${this.device.deviceType}: ${this.multiPressCount} request(s) queued.`);
766
- this.On = true;
802
+ On = true;
767
803
  }
768
- if (this.On !== this.accessory.context.On || this.allowPush || this.multiPressCount > 0) {
804
+ if (On !== this.accessory.context.On || this.allowPush || this.multiPressCount > 0) {
769
805
  let command = '';
770
- if (this.botMode === 'switch' && this.On) {
806
+ if (this.botMode === 'switch' && On) {
771
807
  command = 'turnOn';
772
- this.On = true;
773
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
774
- } else if (this.botMode === 'switch' && !this.On) {
808
+ On = true;
809
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, Turning ${On}`);
810
+ } else if (this.botMode === 'switch' && !On) {
775
811
  command = 'turnOff';
776
- this.On = false;
777
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
812
+ On = false;
813
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, Turning ${On}`);
778
814
  } else if (this.botMode === 'press' || this.botMode === 'multipress') {
779
815
  command = 'press';
780
816
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Press Mode`);
781
- this.On = false;
817
+ On = false;
782
818
  } else {
783
819
  throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Device Parameters not set for this Bot.`);
784
820
  }
@@ -800,8 +836,10 @@ export class Bot {
800
836
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus body: ${JSON.stringify(deviceStatus.body)}`);
801
837
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
802
838
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
803
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
839
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
804
840
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
841
+ this.successLog(`${this.device.deviceType}: ${this.accessory.displayName} `
842
+ + `request to SwitchBot API, body: ${JSON.stringify(JSON.parse(bodyChange))} sent successfully`);
805
843
  } else {
806
844
  this.statusCode(statusCode);
807
845
  this.statusCode(deviceStatus.statusCode);
@@ -810,23 +848,18 @@ export class Bot {
810
848
  this.multiPressCount--;
811
849
  if (this.multiPressCount > 0) {
812
850
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Multi Press Count: ${this.multiPressCount}`);
813
- this.On = true;
851
+ On = true;
814
852
  this.openAPIpushChanges();
815
853
  }
816
854
  }
817
855
  } catch (e: any) {
818
856
  this.apiError(e);
819
- this.errorLog(
820
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}` +
821
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
822
- );
857
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
858
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
823
859
  }
824
860
  } else {
825
- this.debugLog(
826
- `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` +
827
- `On: ${this.On}, ` +
828
- `OnCached: ${this.accessory.context.On}`,
829
- );
861
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges,`
862
+ + ` On: ${On}, OnCached: ${this.accessory.context.On}`);
830
863
  }
831
864
  }
832
865
 
@@ -835,53 +868,105 @@ export class Bot {
835
868
  */
836
869
  async OnSet(value: CharacteristicValue): Promise<void> {
837
870
  if (this.botDeviceType === 'garagedoor') {
838
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetDoorState: ${value}`);
839
- if (value === this.hap.Characteristic.TargetDoorState.CLOSED) {
840
- this.On = false;
841
- } else {
842
- this.On = true;
871
+ if (this.GarageDoor) {
872
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetDoorState: ${value}`);
873
+ if (value === this.hap.Characteristic.TargetDoorState.CLOSED) {
874
+ await this.setOn(false);
875
+ this.GarageDoor.On = false;
876
+ } else {
877
+ await this.setOn(true);
878
+ this.GarageDoor.On = true;
879
+ }
843
880
  }
844
- } else if (
845
- this.botDeviceType === 'door' ||
846
- this.botDeviceType === 'window' ||
847
- this.botDeviceType === 'windowcovering'
848
- ) {
849
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
850
- if (value === 0) {
851
- this.On = false;
852
- } else {
853
- this.On = true;
881
+ } else if (this.botDeviceType === 'door') {
882
+ if (this.Door) {
883
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
884
+ if (value === 0) {
885
+ await this.setOn(false);
886
+ this.Door.On = false;
887
+ } else {
888
+ await this.setOn(true);
889
+ this.Door.On = true;
890
+ }
891
+ }
892
+ } else if (this.botDeviceType === 'window') {
893
+ if (this.Window) {
894
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
895
+ if (value === 0) {
896
+ await this.setOn(false);
897
+ this.Window.On = false;
898
+ } else {
899
+ await this.setOn(true);
900
+ this.Window.On = true;
901
+ }
902
+ }
903
+ } else if (this.botDeviceType === 'windowcovering') {
904
+ if (this.WindowCovering) {
905
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
906
+ if (value === 0) {
907
+ await this.setOn(false);
908
+ this.WindowCovering.On = false;
909
+ } else {
910
+ await this.setOn(true);
911
+ this.WindowCovering.On = true;
912
+ }
854
913
  }
855
914
  } else if (this.botDeviceType === 'lock') {
856
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set LockTargetState: ${value}`);
857
- if (value === this.hap.Characteristic.LockTargetState.SECURED) {
858
- this.On = false;
859
- } else {
860
- this.On = true;
915
+ if (this.LockMechanism) {
916
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set LockTargetState: ${value}`);
917
+ if (value === this.hap.Characteristic.LockTargetState.SECURED) {
918
+ await this.setOn(false);
919
+ this.LockMechanism.On = false;
920
+ } else {
921
+ await this.setOn(true);
922
+ this.LockMechanism.On = true;
923
+ }
861
924
  }
862
925
  } else if (this.botDeviceType === 'faucet') {
863
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Active: ${value}`);
864
- if (value === this.hap.Characteristic.Active.INACTIVE) {
865
- this.On = false;
866
- } else {
867
- this.On = true;
926
+ if (this.Faucet) {
927
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Active: ${value}`);
928
+ if (value === this.hap.Characteristic.Active.INACTIVE) {
929
+ await this.setOn(false);
930
+ this.Faucet.On = false;
931
+ } else {
932
+ await this.setOn(true);
933
+ this.Faucet.On = true;
934
+ }
868
935
  }
869
936
  } else if (this.botDeviceType === 'stateful') {
870
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set ProgrammableSwitchOutputState: ${value}`);
871
- if (value === 0) {
872
- this.On = false;
873
- } else {
874
- this.On = true;
937
+ if (this.StatefulProgrammableSwitch) {
938
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set ProgrammableSwitchOutputState: ${value}`);
939
+ if (value === 0) {
940
+ await this.setOn(false);
941
+ this.StatefulProgrammableSwitch.On = false;
942
+ } else {
943
+ await this.setOn(true);
944
+ this.StatefulProgrammableSwitch.On = true;
945
+ }
875
946
  }
876
- } else {
877
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
878
- if (this.device.bot?.mode === 'multipress') {
879
- if (value === true) {
880
- this.multiPressCount++;
881
- this.debugLog(`${this.device.deviceType} set to Multi-Press. Multi-Press count: ${this.multiPressCount}`);
947
+ } else if (this.botDeviceType === 'switch') {
948
+ if (this.Switch) {
949
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set ProgrammableSwitchOutputState: ${value}`);
950
+ if (value === 0) {
951
+ await this.setOn(false);
952
+ this.Switch.On = false;
953
+ } else {
954
+ await this.setOn(true);
955
+ this.Switch.On = true;
882
956
  }
883
957
  }
884
- this.On = value;
958
+ } else {
959
+ if (this.Outlet) {
960
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
961
+ await this.setOn(Boolean(value));
962
+ this.Outlet.On = value;
963
+ }
964
+ }
965
+ if (this.device.bot?.mode === 'multipress') {
966
+ if (value === true) {
967
+ this.multiPressCount++;
968
+ this.debugLog(`${this.device.deviceType} set to Multi-Press. Multi-Press count: ${this.multiPressCount}`);
969
+ }
885
970
  }
886
971
  this.doBotUpdate.next();
887
972
  }
@@ -892,536 +977,352 @@ export class Bot {
892
977
  async updateHomeKitCharacteristics(): Promise<void> {
893
978
  // State
894
979
  if (this.botDeviceType === 'garagedoor') {
895
- if (this.On === undefined) {
896
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
980
+ if (this.GarageDoor?.On === undefined) {
981
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.GarageDoor?.On}`);
897
982
  } else {
898
- if (this.On) {
899
- this.garageDoorService?.updateCharacteristic(
900
- this.hap.Characteristic.TargetDoorState,
901
- this.hap.Characteristic.TargetDoorState.OPEN,
902
- );
903
- this.garageDoorService?.updateCharacteristic(
904
- this.hap.Characteristic.CurrentDoorState,
905
- this.hap.Characteristic.CurrentDoorState.OPEN,
906
- );
907
- this.debugLog(
908
- `${this.device.deviceType}: ` + `${this.accessory.displayName} updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open`,
909
- );
983
+ if (this.GarageDoor.On) {
984
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.TargetDoorState, this.hap.Characteristic.TargetDoorState.OPEN);
985
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, this.hap.Characteristic.CurrentDoorState.OPEN);
986
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
987
+ + ` TargetDoorState: Open, CurrentDoorState: Open (${this.GarageDoor.On})`);
910
988
  } else {
911
- this.garageDoorService?.updateCharacteristic(
912
- this.hap.Characteristic.TargetDoorState,
913
- this.hap.Characteristic.TargetDoorState.CLOSED,
914
- );
915
- this.garageDoorService?.updateCharacteristic(
916
- this.hap.Characteristic.CurrentDoorState,
917
- this.hap.Characteristic.CurrentDoorState.CLOSED,
918
- );
919
- this.debugLog(
920
- `${this.device.deviceType}: ` + `${this.accessory.displayName} updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open`,
921
- );
989
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.TargetDoorState, this.hap.Characteristic.TargetDoorState.CLOSED);
990
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, this.hap.Characteristic.CurrentDoorState.CLOSED);
991
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristicc`
992
+ + ` TargetDoorState: Open, CurrentDoorState: Open (${this.GarageDoor.On})`);
922
993
  }
923
994
  }
924
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Garage Door On: ${this.On}`);
995
+ await this.setOn(Boolean(this.GarageDoor?.On));
996
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Garage Door On: ${this.GarageDoor?.On}`);
925
997
  } else if (this.botDeviceType === 'door') {
926
- if (this.On === undefined) {
927
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
998
+ if (this.Door?.On === undefined) {
999
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.Door?.On}`);
928
1000
  } else {
929
- if (this.On) {
930
- this.doorService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
931
- this.doorService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
932
- this.doorService?.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
933
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 100, CurrentPosition: 100`);
1001
+ if (this.Door.On) {
1002
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
1003
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
1004
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1005
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristicc`
1006
+ + ` TargetPosition: 100, CurrentPosition: 100 (${this.Door.On})`);
934
1007
  } else {
935
- this.doorService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
936
- this.doorService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
937
- this.doorService?.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
938
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 0, CurrentPosition: 0`);
1008
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
1009
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
1010
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1011
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristicc`
1012
+ + ` TargetPosition: 0, CurrentPosition: 0 (${this.Door.On})`);
939
1013
  }
940
1014
  }
941
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Door On: ${this.On}`);
1015
+ await this.setOn(Boolean(this.Door?.On));
1016
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Door On: ${this.Door?.On}`);
942
1017
  } else if (this.botDeviceType === 'window') {
943
- if (this.On === undefined) {
944
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
1018
+ if (this.Window?.On === undefined) {
1019
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.Window?.On}`);
945
1020
  } else {
946
- if (this.On) {
947
- this.windowService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
948
- this.windowService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
949
- this.windowService?.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
950
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 100, CurrentPosition: 100`);
1021
+ if (this.Window.On) {
1022
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
1023
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
1024
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1025
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristicc`
1026
+ + ` TargetPosition: 100, CurrentPosition: 100 (${this.Window.On})`);
951
1027
  } else {
952
- this.windowService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
953
- this.windowService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
954
- this.windowService?.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
955
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 0, CurrentPosition: 0`);
1028
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
1029
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
1030
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1031
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristicc`
1032
+ + ` TargetPosition: 0, CurrentPosition: 0 (${this.Window.On})`);
956
1033
  }
957
1034
  }
958
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Window On: ${this.On}`);
1035
+ await this.setOn(Boolean(this.Window?.On));
1036
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Window On: ${this.Window?.On}`);
959
1037
  } else if (this.botDeviceType === 'windowcovering') {
960
- if (this.On === undefined) {
961
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
1038
+ if (this.WindowCovering?.On === undefined) {
1039
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.WindowCovering?.On}`);
962
1040
  } else {
963
- if (this.On) {
964
- this.windowCoveringService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
965
- this.windowCoveringService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
966
- this.windowCoveringService?.updateCharacteristic(
967
- this.hap.Characteristic.PositionState,
968
- this.hap.Characteristic.PositionState.STOPPED,
969
- );
970
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 100, CurrentPosition: 100`);
1041
+ if (this.WindowCovering.On) {
1042
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100);
1043
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100);
1044
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1045
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristicc`
1046
+ + ` TargetPosition: 100, CurrentPosition: 100 (${this.WindowCovering.On})`);
971
1047
  } else {
972
- this.windowCoveringService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
973
- this.windowCoveringService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
974
- this.windowCoveringService?.updateCharacteristic(
975
- this.hap.Characteristic.PositionState,
976
- this.hap.Characteristic.PositionState.STOPPED,
977
- );
978
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 0, CurrentPosition: 0`);
1048
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
1049
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
1050
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1051
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristicc`
1052
+ + ` TargetPosition: 0, CurrentPosition: 0 (${this.WindowCovering.On})`);
979
1053
  }
980
1054
  }
981
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Window Covering On: ${this.On}`);
1055
+ await this.setOn(Boolean(this.WindowCovering?.On));
1056
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Window Covering On: ${this.WindowCovering?.On}`);
982
1057
  } else if (this.botDeviceType === 'lock') {
983
- if (this.On === undefined) {
984
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
1058
+ if (this.LockMechanism?.On === undefined) {
1059
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LockMechanism?.On}`);
985
1060
  } else {
986
- if (this.On) {
987
- this.lockService?.updateCharacteristic(
988
- this.hap.Characteristic.LockTargetState,
989
- this.hap.Characteristic.LockTargetState.UNSECURED,
990
- );
991
- this.lockService?.updateCharacteristic(
992
- this.hap.Characteristic.LockCurrentState,
993
- this.hap.Characteristic.LockCurrentState.UNSECURED,
994
- );
995
- this.debugLog(
996
- `${this.device.deviceType}: ` +
997
- `${this.accessory.displayName} updateCharacteristic LockTargetState: UNSECURED, LockCurrentState: UNSECURED`,
998
- );
1061
+ if (this.LockMechanism.On) {
1062
+ this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockTargetState,
1063
+ this.hap.Characteristic.LockTargetState.UNSECURED);
1064
+ this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockCurrentState,
1065
+ this.hap.Characteristic.LockCurrentState.UNSECURED);
1066
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristicc`
1067
+ + ` LockTargetState: UNSECURED, LockCurrentState: UNSECURED (${this.LockMechanism.On})`);
999
1068
  } else {
1000
- this.lockService?.updateCharacteristic(this.hap.Characteristic.LockTargetState, this.hap.Characteristic.LockTargetState.SECURED);
1001
- this.lockService?.updateCharacteristic(
1002
- this.hap.Characteristic.LockCurrentState,
1003
- this.hap.Characteristic.LockCurrentState.SECURED,
1004
- );
1005
- this.debugLog(
1006
- `${this.device.deviceType}: ` + `${this.accessory.displayName} updateCharacteristic LockTargetState: SECURED, LockCurrentState: SECURED`,
1007
- );
1069
+ this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockTargetState,
1070
+ this.hap.Characteristic.LockTargetState.SECURED);
1071
+ this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockCurrentState,
1072
+ this.hap.Characteristic.LockCurrentState.SECURED);
1073
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
1074
+ + ` LockTargetState: SECURED, LockCurrentState: SECURED (${this.LockMechanism.On})`);
1008
1075
  }
1009
1076
  }
1010
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Lock On: ${this.On}`);
1077
+ await this.setOn(Boolean(this.LockMechanism?.On));
1078
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Lock On: ${this.LockMechanism?.On}`);
1011
1079
  } else if (this.botDeviceType === 'faucet') {
1012
- if (this.On === undefined) {
1013
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
1080
+ if (this.Faucet?.On === undefined) {
1081
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.Faucet?.On}`);
1014
1082
  } else {
1015
- if (this.On) {
1016
- this.faucetService?.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.ACTIVE);
1017
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Active: ${this.On}`);
1083
+ if (this.Faucet.On) {
1084
+ this.Faucet.Service.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.ACTIVE);
1085
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Active: ${this.Faucet.On}`);
1018
1086
  } else {
1019
- this.faucetService?.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.INACTIVE);
1020
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Active: ${this.On}`);
1087
+ this.Faucet.Service.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.INACTIVE);
1088
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Active: ${this.Faucet.On}`);
1021
1089
  }
1022
1090
  }
1023
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Faucet On: ${this.On}`);
1091
+ await this.setOn(Boolean(this.Faucet?.On));
1092
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Faucet On: ${this.Faucet?.On}`);
1024
1093
  } else if (this.botDeviceType === 'fan') {
1025
- if (this.On === undefined) {
1026
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
1094
+ if (this.Fan?.On === undefined) {
1095
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.Fan?.On}`);
1027
1096
  } else {
1028
- if (this.On) {
1029
- this.fanService?.updateCharacteristic(this.hap.Characteristic.On, this.On);
1030
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
1097
+ if (this.Fan.On) {
1098
+ this.Fan.Service.updateCharacteristic(this.hap.Characteristic.On, this.Fan.On);
1099
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.Fan.On}`);
1031
1100
  } else {
1032
- this.fanService?.updateCharacteristic(this.hap.Characteristic.On, this.On);
1033
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
1101
+ this.Fan.Service.updateCharacteristic(this.hap.Characteristic.On, this.Fan.On);
1102
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.Fan.On}`);
1034
1103
  }
1035
1104
  }
1036
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Fan On: ${this.On}`);
1105
+ await this.setOn(Boolean(this.Fan?.On));
1106
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Fan On: ${this.Fan?.On}`);
1037
1107
  } else if (this.botDeviceType === 'stateful') {
1038
- if (this.On === undefined) {
1039
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
1108
+ if (this.StatefulProgrammableSwitch?.On === undefined) {
1109
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.StatefulProgrammableSwitch?.On}`);
1040
1110
  } else {
1041
- if (this.On) {
1042
- this.statefulProgrammableSwitchService?.updateCharacteristic(
1043
- this.hap.Characteristic.ProgrammableSwitchEvent,
1044
- this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
1045
- );
1046
- this.statefulProgrammableSwitchService?.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, 1);
1047
- this.debugLog(
1048
- `${this.device.deviceType}: ` +
1049
- `${this.accessory.displayName} updateCharacteristic ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 1`,
1050
- );
1111
+ if (this.StatefulProgrammableSwitch.On) {
1112
+ this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent,
1113
+ this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS);
1114
+ this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, 1);
1115
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
1116
+ + ` ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 1 (${this.StatefulProgrammableSwitch.On})`);
1051
1117
  } else {
1052
- this.statefulProgrammableSwitchService?.updateCharacteristic(
1053
- this.hap.Characteristic.ProgrammableSwitchEvent,
1054
- this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
1055
- );
1056
- this.statefulProgrammableSwitchService?.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, 0);
1057
- this.debugLog(
1058
- `${this.device.deviceType}: ` +
1059
- `${this.accessory.displayName} updateCharacteristic ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 0`,
1060
- );
1118
+ this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent,
1119
+ this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS);
1120
+ this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, 0);
1121
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
1122
+ + ` ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 0 (${this.StatefulProgrammableSwitch.On})`);
1061
1123
  }
1062
1124
  }
1063
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatefulProgrammableSwitch On: ${this.On}`);
1125
+ await this.setOn(Boolean(this.StatefulProgrammableSwitch?.On));
1126
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatefulProgrammableSwitch On: ${this.StatefulProgrammableSwitch?.On}`);
1064
1127
  } else if (this.botDeviceType === 'switch') {
1065
- if (this.On === undefined) {
1066
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
1128
+ if (this.Switch?.On === undefined) {
1129
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.Switch?.On}`);
1067
1130
  } else {
1068
- this.switchService?.updateCharacteristic(this.hap.Characteristic.On, this.On);
1069
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
1131
+ this.Switch.Service.updateCharacteristic(this.hap.Characteristic.On, this.Switch.On);
1132
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.Switch.On}`);
1070
1133
  }
1134
+ await this.setOn(Boolean(this.Switch?.On));
1071
1135
  } else {
1072
- if (this.On === undefined) {
1073
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
1136
+ if (this.Outlet?.On === undefined) {
1137
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.Outlet?.On}`);
1074
1138
  } else {
1075
- this.outletService?.updateCharacteristic(this.hap.Characteristic.On, this.On);
1076
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
1139
+ this.Outlet.Service.updateCharacteristic(this.hap.Characteristic.On, this.Outlet.On);
1140
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.Outlet.On}`);
1077
1141
  }
1142
+ await this.setOn(Boolean(this.Outlet?.On));
1078
1143
  }
1079
- this.accessory.context.On = this.On;
1144
+ this.accessory.context.On = await this.getOn();
1080
1145
  // BatteryLevel
1081
- if (this.BatteryLevel === undefined) {
1082
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
1146
+ if (this.Battery.BatteryLevel === undefined) {
1147
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
1083
1148
  } else {
1084
- this.accessory.context.BatteryLevel = this.BatteryLevel;
1085
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.BatteryLevel);
1086
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
1149
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
1150
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
1151
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
1087
1152
  }
1088
1153
  // StatusLowBattery
1089
- if (this.StatusLowBattery === undefined) {
1090
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
1154
+ if (this.Battery.StatusLowBattery === undefined) {
1155
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
1091
1156
  } else {
1092
- this.accessory.context.StatusLowBattery = this.StatusLowBattery;
1093
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.StatusLowBattery);
1094
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
1157
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
1158
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
1159
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
1160
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
1095
1161
  }
1096
1162
  }
1097
1163
 
1098
1164
  async removeOutletService(accessory: PlatformAccessory): Promise<void> {
1099
1165
  // If outletService still present, then remove first
1100
- this.outletService = this.accessory.getService(this.hap.Service.Outlet);
1101
- if (this.outletService) {
1166
+ if (this.Outlet?.Service) {
1167
+ this.Outlet.Service = this.accessory.getService(this.hap.Service.Outlet) as Service;
1102
1168
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Outlet Service`);
1169
+ accessory.removeService(this.Outlet.Service);
1103
1170
  }
1104
- accessory.removeService(this.outletService!);
1105
1171
  }
1106
1172
 
1107
1173
  async removeGarageDoorService(accessory: PlatformAccessory): Promise<void> {
1108
1174
  // If garageDoorService still present, then remove first
1109
- this.garageDoorService = this.accessory.getService(this.hap.Service.GarageDoorOpener);
1110
- if (this.garageDoorService) {
1175
+ if (this.GarageDoor?.Service) {
1176
+ this.GarageDoor.Service = this.accessory.getService(this.hap.Service.GarageDoorOpener) as Service;
1111
1177
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Garage Door Service`);
1178
+ accessory.removeService(this.GarageDoor.Service);
1112
1179
  }
1113
- accessory.removeService(this.garageDoorService!);
1114
1180
  }
1115
1181
 
1116
1182
  async removeDoorService(accessory: PlatformAccessory): Promise<void> {
1117
1183
  // If doorService still present, then remove first
1118
- this.doorService = this.accessory.getService(this.hap.Service.Door);
1119
- if (this.doorService) {
1184
+ if (this.Door?.Service) {
1185
+ this.Door.Service = this.accessory.getService(this.hap.Service.Door) as Service;
1120
1186
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Door Service`);
1187
+ accessory.removeService(this.Door.Service);
1121
1188
  }
1122
- accessory.removeService(this.doorService!);
1123
1189
  }
1124
1190
 
1125
1191
  async removeLockService(accessory: PlatformAccessory): Promise<void> {
1126
1192
  // If lockService still present, then remove first
1127
- this.lockService = this.accessory.getService(this.hap.Service.LockMechanism);
1128
- if (this.lockService) {
1193
+ if (this.LockMechanism?.Service) {
1194
+ this.LockMechanism.Service = this.accessory.getService(this.hap.Service.LockMechanism) as Service;
1129
1195
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Lock Service`);
1196
+ accessory.removeService(this.LockMechanism.Service);
1130
1197
  }
1131
- accessory.removeService(this.lockService!);
1132
1198
  }
1133
1199
 
1134
1200
  async removeFaucetService(accessory: PlatformAccessory): Promise<void> {
1135
1201
  // If faucetService still present, then remove first
1136
- this.faucetService = this.accessory.getService(this.hap.Service.Faucet);
1137
- if (this.faucetService) {
1202
+ if (this.Faucet?.Service) {
1203
+ this.Faucet.Service = this.accessory.getService(this.hap.Service.Faucet) as Service;
1138
1204
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Faucet Service`);
1205
+ accessory.removeService(this.Faucet.Service);
1139
1206
  }
1140
- accessory.removeService(this.faucetService!);
1141
1207
  }
1142
1208
 
1143
1209
  async removeFanService(accessory: PlatformAccessory): Promise<void> {
1144
1210
  // If fanService still present, then remove first
1145
- this.fanService = this.accessory.getService(this.hap.Service.Fan);
1146
- if (this.fanService) {
1211
+ if (this.Fan?.Service) {
1212
+ this.Fan.Service = this.accessory.getService(this.hap.Service.Fanv2) as Service;
1147
1213
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Fan Service`);
1214
+ accessory.removeService(this.Fan.Service);
1148
1215
  }
1149
- accessory.removeService(this.fanService!);
1150
1216
  }
1151
1217
 
1152
1218
  async removeWindowService(accessory: PlatformAccessory): Promise<void> {
1153
1219
  // If windowService still present, then remove first
1154
- this.windowService = this.accessory.getService(this.hap.Service.Window);
1155
- if (this.windowService) {
1220
+ if (this.Window?.Service) {
1221
+ this.Window.Service = this.accessory.getService(this.hap.Service.Window) as Service;
1156
1222
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Window Service`);
1223
+ accessory.removeService(this.Window.Service);
1157
1224
  }
1158
- accessory.removeService(this.windowService!);
1159
1225
  }
1160
1226
 
1161
1227
  async removeWindowCoveringService(accessory: PlatformAccessory): Promise<void> {
1162
1228
  // If windowCoveringService still present, then remove first
1163
- this.windowCoveringService = this.accessory.getService(this.hap.Service.WindowCovering);
1164
- if (this.windowCoveringService) {
1229
+ if (this.WindowCovering?.Service) {
1230
+ this.WindowCovering.Service = this.accessory.getService(this.hap.Service.WindowCovering) as Service;
1165
1231
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Window Covering Service`);
1232
+ accessory.removeService(this.WindowCovering.Service);
1166
1233
  }
1167
- accessory.removeService(this.windowCoveringService!);
1168
1234
  }
1169
1235
 
1170
1236
  async removeStatefulProgrammableSwitchService(accessory: PlatformAccessory): Promise<void> {
1171
1237
  // If statefulProgrammableSwitchService still present, then remove first
1172
- this.statefulProgrammableSwitchService = this.accessory.getService(this.hap.Service.StatefulProgrammableSwitch);
1173
- if (this.statefulProgrammableSwitchService) {
1238
+ if (this.StatefulProgrammableSwitch?.Service) {
1239
+ this.StatefulProgrammableSwitch.Service = this.accessory.getService(this.hap.Service.StatefulProgrammableSwitch) as Service;
1174
1240
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Stateful Programmable Switch Service`);
1241
+ accessory.removeService(this.StatefulProgrammableSwitch.Service);
1175
1242
  }
1176
- accessory.removeService(this.statefulProgrammableSwitchService!);
1177
1243
  }
1178
1244
 
1179
1245
  async removeSwitchService(accessory: PlatformAccessory): Promise<void> {
1180
1246
  // If switchService still present, then remove first
1181
- this.switchService = this.accessory.getService(this.hap.Service.Switch);
1182
- if (this.switchService) {
1247
+ if (this.Switch?.Service) {
1248
+ this.Switch.Service = this.accessory.getService(this.hap.Service.Switch) as Service;
1183
1249
  this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Switch Service`);
1250
+ accessory.removeService(this.Switch.Service);
1184
1251
  }
1185
- accessory.removeService(this.switchService!);
1186
1252
  }
1187
1253
 
1188
- private DoublePress(device: device & devicesConfig) {
1189
- if (device.bot?.doublePress) {
1190
- this.doublePress = device.bot?.doublePress;
1191
- this.accessory.context.doublePress = this.doublePress;
1192
- } else {
1193
- this.doublePress = 1;
1194
- }
1195
- }
1196
-
1197
- async stopScanning(switchbot: any) {
1198
- switchbot.stopScan();
1199
- if (this.BLE_IsConnected) {
1200
- await this.BLEparseStatus();
1201
- await this.updateHomeKitCharacteristics();
1202
- } else {
1203
- await this.BLERefreshConnection(switchbot);
1204
- }
1205
- }
1206
-
1207
- async getCustomBLEAddress(switchbot: any) {
1208
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
1209
- (async () => {
1210
- // Start to monitor advertisement packets
1211
- await switchbot.startScan({
1212
- model: 'H',
1213
- });
1214
- // Set an event handler
1215
- switchbot.onadvertisement = (ad: any) => {
1216
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
1217
- };
1218
- await sleep(10000);
1219
- // Stop to monitor
1220
- switchbot.stopScan();
1221
- })();
1222
- }
1223
- }
1224
-
1225
- async BLEPushConnection() {
1226
- if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
1227
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Push Changes`);
1228
- await this.openAPIpushChanges();
1229
- }
1230
- }
1231
-
1232
- async BLERefreshConnection(switchbot: any): Promise<void> {
1233
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot:`
1234
- + ` ${JSON.stringify(switchbot)}`);
1235
- if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
1236
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Refresh Status`);
1237
- await this.openAPIRefreshStatus();
1238
- }
1239
- }
1240
-
1241
- async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
1242
- return fn().catch(async (e: any) => {
1243
- if (max === 0) {
1244
- throw e;
1245
- }
1246
- this.infoLog(e);
1247
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Retrying`);
1248
- await sleep(1000);
1249
- return this.retry({ max: max - 1, fn });
1250
- });
1251
- }
1252
-
1253
- maxRetry(): number {
1254
- if (this.device.maxRetry) {
1255
- return this.device.maxRetry;
1256
- } else {
1257
- return 5;
1258
- }
1259
- }
1260
-
1261
- async PressOrSwitch(device: device & devicesConfig): Promise<void> {
1262
- if (!device.bot?.mode) {
1263
- this.botMode = 'switch';
1264
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} does not have bot mode set in the Plugin's SwitchBot Device Settings,`);
1265
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} is defaulting to "${this.botMode}" mode, you may experience issues.`);
1266
- } else if (device.bot?.mode === 'switch') {
1267
- this.botMode = 'switch';
1268
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
1269
- } else if (device.bot?.mode === 'press') {
1270
- this.botMode = 'press';
1271
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
1272
- } else if (device.bot?.mode === 'multipress') {
1273
- this.botMode = 'multipress';
1274
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
1275
- } else {
1276
- throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
1277
- }
1278
- }
1279
-
1280
- async allowPushChanges(device: device & devicesConfig): Promise<void> {
1281
- if (device.bot?.allowPush) {
1282
- this.allowPush = true;
1283
- } else {
1284
- this.allowPush = false;
1285
- }
1286
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Allowing Push Changes: ${this.allowPush}`);
1287
- }
1288
-
1289
- async scan(device: device & devicesConfig): Promise<void> {
1290
- if (device.scanDuration) {
1291
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
1292
- if (this.BLE) {
1293
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
1294
- }
1254
+ async getOn(): Promise<boolean> {
1255
+ let On: boolean;
1256
+ if (this.botDeviceType === 'garagedoor') {
1257
+ On = this.GarageDoor?.On ? true : false;
1258
+ } else if (this.botDeviceType === 'door') {
1259
+ On = this.Door?.On ? true : false;
1260
+ } else if (this.botDeviceType === 'window') {
1261
+ On = this.Window?.On ? true : false;
1262
+ } else if (this.botDeviceType === 'windowcovering') {
1263
+ On = this.WindowCovering?.On ? true : false;
1264
+ } else if (this.botDeviceType === 'lock') {
1265
+ On = this.LockMechanism?.On ? true : false;
1266
+ } else if (this.botDeviceType === 'faucet') {
1267
+ On = this.Faucet?.On ? true : false;
1268
+ } else if (this.botDeviceType === 'fan') {
1269
+ On = this.Fan?.On ? true : false;
1270
+ } else if (this.botDeviceType === 'stateful') {
1271
+ On = this.StatefulProgrammableSwitch?.On ? true : false;
1272
+ } else if (this.botDeviceType === 'switch') {
1273
+ On = this.Switch?.On ? true : false;
1295
1274
  } else {
1296
- this.scanDuration = this.accessory.context.scanDuration = 1;
1297
- if (this.BLE) {
1298
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
1299
- }
1300
- }
1301
- }
1302
-
1303
- async statusCode(statusCode: number): Promise<void> {
1304
- switch (statusCode) {
1305
- case 151:
1306
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
1307
- break;
1308
- case 152:
1309
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
1310
- break;
1311
- case 160:
1312
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
1313
- break;
1314
- case 161:
1315
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
1316
- this.offlineOff();
1317
- break;
1318
- case 171:
1319
- this.errorLog(
1320
- `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` +
1321
- `Hub: ${this.device.hubDeviceId}`,
1322
- );
1323
- this.offlineOff();
1324
- break;
1325
- case 190:
1326
- this.errorLog(
1327
- `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
1328
- ` Or command format is invalid, statusCode: ${statusCode}`,
1329
- );
1330
- break;
1331
- case 100:
1332
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
1333
- break;
1334
- case 200:
1335
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
1336
- break;
1337
- case 400:
1338
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bad Request, The client has issued an invalid request. `
1339
- + `This is commonly used to specify validation errors in a request payload, statusCode: ${statusCode}`);
1340
- break;
1341
- case 401:
1342
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unauthorized, Authorization for the API is required, `
1343
- + `but the request has not been authenticated, statusCode: ${statusCode}`);
1344
- break;
1345
- case 403:
1346
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Forbidden, The request has been authenticated but does not `
1347
- + `have appropriate permissions, or a requested resource is not found, statusCode: ${statusCode}`);
1348
- break;
1349
- case 404:
1350
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Found, Specifies the requested path does not exist, `
1351
- + `statusCode: ${statusCode}`);
1352
- break;
1353
- case 406:
1354
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Acceptable, The client has requested a MIME type via `
1355
- + `the Accept header for a value not supported by the server, statusCode: ${statusCode}`);
1356
- break;
1357
- case 415:
1358
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unsupported Media Type, The client has defined a contentType `
1359
- + `header that is not supported by the server, statusCode: ${statusCode}`);
1360
- break;
1361
- case 422:
1362
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unprocessable Entity, The client has made a valid request, `
1363
- + `but the server cannot process it. This is often used for APIs for which certain limits have been exceeded, statusCode: ${statusCode}`);
1364
- break;
1365
- case 429:
1366
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Too Many Requests, The client has exceeded the number of `
1367
- + `requests allowed for a given time window, statusCode: ${statusCode}`);
1368
- break;
1369
- case 500:
1370
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Internal Server Error, An unexpected error on the SmartThings `
1371
- + `servers has occurred. These errors should be rare, statusCode: ${statusCode}`);
1372
- break;
1373
- default:
1374
- this.infoLog(
1375
- `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` +
1376
- `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`,
1377
- );
1378
- }
1379
- }
1380
-
1381
- async offlineOff(): Promise<void> {
1382
- if (this.device.offline) {
1383
- await this.deviceContext();
1384
- await this.updateHomeKitCharacteristics();
1275
+ On = this.Outlet?.On ? true : false;
1385
1276
  }
1277
+ return On;
1386
1278
  }
1387
1279
 
1388
- async apiError(e: any): Promise<void> {
1280
+ async setOn(On: boolean): Promise<void> {
1389
1281
  if (this.botDeviceType === 'garagedoor') {
1390
- this.garageDoorService?.updateCharacteristic(this.hap.Characteristic.TargetDoorState, e);
1391
- this.garageDoorService?.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, e);
1392
- this.garageDoorService?.updateCharacteristic(this.hap.Characteristic.ObstructionDetected, e);
1282
+ if (this.GarageDoor) {
1283
+ this.GarageDoor.On = On;
1284
+ }
1393
1285
  } else if (this.botDeviceType === 'door') {
1394
- this.doorService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
1395
- this.doorService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
1396
- this.doorService?.updateCharacteristic(this.hap.Characteristic.PositionState, e);
1286
+ if (this.Door) {
1287
+ this.Door.On = On;
1288
+ }
1397
1289
  } else if (this.botDeviceType === 'window') {
1398
- this.windowService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
1399
- this.windowService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
1400
- this.windowService?.updateCharacteristic(this.hap.Characteristic.PositionState, e);
1290
+ if (this.Window) {
1291
+ this.Window.On = On;
1292
+ }
1401
1293
  } else if (this.botDeviceType === 'windowcovering') {
1402
- this.windowCoveringService?.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
1403
- this.windowCoveringService?.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
1404
- this.windowCoveringService?.updateCharacteristic(this.hap.Characteristic.PositionState, e);
1294
+ if (this.WindowCovering) {
1295
+ this.WindowCovering.On = On;
1296
+ }
1405
1297
  } else if (this.botDeviceType === 'lock') {
1406
- this.doorService?.updateCharacteristic(this.hap.Characteristic.LockTargetState, e);
1407
- this.doorService?.updateCharacteristic(this.hap.Characteristic.LockCurrentState, e);
1298
+ if (this.LockMechanism) {
1299
+ this.LockMechanism.On = On;
1300
+ }
1408
1301
  } else if (this.botDeviceType === 'faucet') {
1409
- this.faucetService?.updateCharacteristic(this.hap.Characteristic.Active, e);
1302
+ if (this.Faucet) {
1303
+ this.Faucet.On = On;
1304
+ }
1410
1305
  } else if (this.botDeviceType === 'fan') {
1411
- this.fanService?.updateCharacteristic(this.hap.Characteristic.On, e);
1306
+ if (this.Fan) {
1307
+ this.Fan.On = On;
1308
+ }
1412
1309
  } else if (this.botDeviceType === 'stateful') {
1413
- this.statefulProgrammableSwitchService?.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent, e);
1414
- this.statefulProgrammableSwitchService?.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, e);
1310
+ if (this.StatefulProgrammableSwitch) {
1311
+ this.StatefulProgrammableSwitch.On = On;
1312
+ }
1415
1313
  } else if (this.botDeviceType === 'switch') {
1416
- this.switchService?.updateCharacteristic(this.hap.Characteristic.On, e);
1314
+ if (this.Switch) {
1315
+ this.Switch.On = On;
1316
+ }
1417
1317
  } else {
1418
- this.outletService?.updateCharacteristic(this.hap.Characteristic.On, e);
1318
+ if (this.Outlet) {
1319
+ this.Outlet.On = On;
1320
+ }
1419
1321
  }
1420
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
1421
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
1422
1322
  }
1423
1323
 
1424
- async deviceType(device: device & devicesConfig): Promise<void> {
1324
+ async getBotConfigSettings(device: device & devicesConfig) {
1325
+ //Bot Device Type
1425
1326
  if (!device.bot?.deviceType && this.accessory.context.deviceType) {
1426
1327
  this.botDeviceType = this.accessory.context.deviceType;
1427
1328
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Type: ${this.botDeviceType}, from Accessory Cache.`);
@@ -1435,41 +1336,33 @@ export class Bot {
1435
1336
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} No Device Type Set, deviceType: ${this.device.bot?.deviceType}`);
1436
1337
  this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using default deviceType: ${this.botDeviceType}`);
1437
1338
  }
1438
- }
1439
-
1440
- async deviceContext() {
1441
- if (this.On === undefined) {
1442
- this.On = false;
1443
- this.accessory.context.On = this.On;
1444
- } else {
1445
- this.On = this.accessory.context.On;
1446
- }
1447
- if (this.BatteryLevel === undefined) {
1448
- this.BatteryLevel = 100;
1339
+ // Bot Mode
1340
+ if (!device.bot?.mode) {
1341
+ this.botMode = 'switch';
1342
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} does not have bot mode set in the Plugin's SwitchBot Device Settings,`);
1343
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} is defaulting to "${this.botMode}" mode, you may experience issues.`);
1344
+ } else if (device.bot?.mode === 'switch') {
1345
+ this.botMode = 'switch';
1346
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
1347
+ } else if (device.bot?.mode === 'press') {
1348
+ this.botMode = 'press';
1349
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
1350
+ } else if (device.bot?.mode === 'multipress') {
1351
+ this.botMode = 'multipress';
1352
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
1449
1353
  } else {
1450
- this.BatteryLevel = this.accessory.context.BatteryLevel;
1354
+ throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
1451
1355
  }
1452
- if (this.StatusLowBattery === undefined) {
1453
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
1454
- this.accessory.context.StatusLowBattery = this.StatusLowBattery;
1356
+
1357
+ // Bot Double Press
1358
+ if (device.bot?.doublePress) {
1359
+ this.doublePress = device.bot?.doublePress;
1360
+ this.accessory.context.doublePress = this.doublePress;
1455
1361
  } else {
1456
- this.StatusLowBattery = this.accessory.context.StatusLowBattery;
1457
- }
1458
- if (this.FirmwareRevision === undefined) {
1459
- this.FirmwareRevision = this.platform.version;
1460
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
1362
+ this.doublePress = 1;
1461
1363
  }
1462
- }
1463
1364
 
1464
- async refreshRate(device: device & devicesConfig): Promise<void> {
1465
- if (device.refreshRate) {
1466
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
1467
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
1468
- } else if (this.platform.config.options!.refreshRate) {
1469
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
1470
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
1471
- }
1472
- // pushRatePress
1365
+ // Bot Press PushRate
1473
1366
  if (device?.bot?.pushRatePress) {
1474
1367
  this.pushRatePress = device?.bot?.pushRatePress;
1475
1368
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Bot pushRatePress: ${this.pushRatePress}`);
@@ -1477,106 +1370,144 @@ export class Bot {
1477
1370
  this.pushRatePress = 15;
1478
1371
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default Bot pushRatePress: ${this.pushRatePress}`);
1479
1372
  }
1480
- }
1481
-
1482
- async deviceConfig(device: device & devicesConfig): Promise<void> {
1483
- let config = {};
1484
- if (device.bot) {
1485
- config = device.bot;
1486
- }
1487
- if (device.connectionType !== undefined) {
1488
- config['connectionType'] = device.connectionType;
1489
- }
1490
- if (device.external !== undefined) {
1491
- config['external'] = device.external;
1492
- }
1493
- if (device.logging !== undefined) {
1494
- config['logging'] = device.logging;
1495
- }
1496
- if (device.refreshRate !== undefined) {
1497
- config['refreshRate'] = device.refreshRate;
1498
- }
1499
- if (device.scanDuration !== undefined) {
1500
- config['scanDuration'] = device.scanDuration;
1501
- }
1502
- if (device.offline !== undefined) {
1503
- config['offline'] = device.offline;
1504
- }
1505
- if (device.maxRetry !== undefined) {
1506
- config['maxRetry'] = device.maxRetry;
1507
- }
1508
- if (device.webhook !== undefined) {
1509
- config['webhook'] = device.webhook;
1510
- }
1511
- if (Object.entries(config).length !== 0) {
1512
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
1513
- }
1514
- }
1515
1373
 
1516
- async deviceLogs(device: device & devicesConfig): Promise<void> {
1517
- if (this.platform.debugMode) {
1518
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
1519
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
1520
- } else if (device.logging) {
1521
- this.deviceLogging = this.accessory.context.logging = device.logging;
1522
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
1523
- } else if (this.platform.config.options?.logging) {
1524
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
1525
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
1374
+ // Bot Allow Push
1375
+ if (device.bot?.allowPush) {
1376
+ this.allowPush = true;
1526
1377
  } else {
1527
- this.deviceLogging = this.accessory.context.logging = 'standard';
1528
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
1378
+ this.allowPush = false;
1529
1379
  }
1380
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Allowing Push Changes: ${this.allowPush}`);
1381
+ // Bot Multi Press Count
1382
+ this.multiPressCount = 0;
1530
1383
  }
1531
1384
 
1532
- /**
1533
- * Logging for Device
1534
- */
1535
- infoLog(...log: any[]): void {
1536
- if (this.enablingDeviceLogging()) {
1537
- this.platform.log.info(String(...log));
1385
+ async BLEPushConnection() {
1386
+ if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
1387
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Push Changes`);
1388
+ await this.openAPIpushChanges();
1538
1389
  }
1539
1390
  }
1540
1391
 
1541
- warnLog(...log: any[]): void {
1542
- if (this.enablingDeviceLogging()) {
1543
- this.platform.log.warn(String(...log));
1392
+ async BLERefreshConnection(switchbot: any): Promise<void> {
1393
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot:`
1394
+ + ` ${JSON.stringify(switchbot)}`);
1395
+ if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
1396
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Refresh Status`);
1397
+ await this.openAPIRefreshStatus();
1544
1398
  }
1545
1399
  }
1546
1400
 
1547
- debugWarnLog(...log: any[]): void {
1548
- if (this.enablingDeviceLogging()) {
1549
- if (this.deviceLogging?.includes('debug')) {
1550
- this.platform.log.warn('[DEBUG]', String(...log));
1401
+ async offlineOff(): Promise<void> {
1402
+ if (this.device.offline) {
1403
+ if (this.botDeviceType === 'garagedoor') {
1404
+ if (this.GarageDoor) {
1405
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.TargetDoorState, this.hap.Characteristic.TargetDoorState.CLOSED);
1406
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, this.hap.Characteristic.CurrentDoorState.CLOSED);
1407
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.ObstructionDetected, false);
1408
+ }
1409
+ } else if (this.botDeviceType === 'door') {
1410
+ if (this.Door) {
1411
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
1412
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
1413
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1414
+ }
1415
+ } else if (this.botDeviceType === 'window') {
1416
+ if (this.Window) {
1417
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
1418
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
1419
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1420
+ }
1421
+ } else if (this.botDeviceType === 'windowcovering') {
1422
+ if (this.WindowCovering) {
1423
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0);
1424
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0);
1425
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED);
1426
+ }
1427
+ } else if (this.botDeviceType === 'lock') {
1428
+ if (this.LockMechanism) {
1429
+ this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockTargetState, this.hap.Characteristic.LockTargetState.SECURED);
1430
+ this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockCurrentState, this.hap.Characteristic.LockCurrentState.SECURED);
1431
+ }
1432
+ } else if (this.botDeviceType === 'faucet') {
1433
+ if (this.Faucet) {
1434
+ this.Faucet.Service.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.INACTIVE);
1435
+ }
1436
+ } else if (this.botDeviceType === 'fan') {
1437
+ if (this.Fan) {
1438
+ this.Fan.Service.updateCharacteristic(this.hap.Characteristic.On, false);
1439
+ }
1440
+ } else if (this.botDeviceType === 'stateful') {
1441
+ if (this.StatefulProgrammableSwitch) {
1442
+ this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent,
1443
+ this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS);
1444
+ this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, 0);
1445
+ }
1446
+ } else if (this.botDeviceType === 'switch') {
1447
+ if (this.Switch) {
1448
+ this.Switch.Service.updateCharacteristic(this.hap.Characteristic.On, false);
1449
+ }
1450
+ } else {
1451
+ if (this.Outlet) {
1452
+ this.Outlet.Service.updateCharacteristic(this.hap.Characteristic.On, false);
1453
+ }
1551
1454
  }
1552
1455
  }
1553
1456
  }
1554
1457
 
1555
- errorLog(...log: any[]): void {
1556
- if (this.enablingDeviceLogging()) {
1557
- this.platform.log.error(String(...log));
1558
- }
1559
- }
1560
-
1561
- debugErrorLog(...log: any[]): void {
1562
- if (this.enablingDeviceLogging()) {
1563
- if (this.deviceLogging?.includes('debug')) {
1564
- this.platform.log.error('[DEBUG]', String(...log));
1458
+ async apiError(e: any): Promise<void> {
1459
+ if (this.botDeviceType === 'garagedoor') {
1460
+ if (this.GarageDoor) {
1461
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.TargetDoorState, e);
1462
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, e);
1463
+ this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.ObstructionDetected, e);
1565
1464
  }
1566
- }
1567
- }
1568
-
1569
- debugLog(...log: any[]): void {
1570
- if (this.enablingDeviceLogging()) {
1571
- if (this.deviceLogging === 'debug') {
1572
- this.platform.log.info('[DEBUG]', String(...log));
1573
- } else {
1574
- this.platform.log.debug(String(...log));
1465
+ } else if (this.botDeviceType === 'door') {
1466
+ if (this.Door) {
1467
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
1468
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
1469
+ this.Door.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e);
1470
+ }
1471
+ } else if (this.botDeviceType === 'window') {
1472
+ if (this.Window) {
1473
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
1474
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
1475
+ this.Window.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e);
1476
+ }
1477
+ } else if (this.botDeviceType === 'windowcovering') {
1478
+ if (this.WindowCovering) {
1479
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e);
1480
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e);
1481
+ this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e);
1482
+ }
1483
+ } else if (this.botDeviceType === 'lock') {
1484
+ if (this.LockMechanism) {
1485
+ this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockTargetState, e);
1486
+ this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockCurrentState, e);
1487
+ }
1488
+ } else if (this.botDeviceType === 'faucet') {
1489
+ if (this.Faucet) {
1490
+ this.Faucet.Service.updateCharacteristic(this.hap.Characteristic.Active, e);
1491
+ }
1492
+ } else if (this.botDeviceType === 'fan') {
1493
+ if (this.Fan) {
1494
+ this.Fan.Service.updateCharacteristic(this.hap.Characteristic.On, e);
1495
+ }
1496
+ } else if (this.botDeviceType === 'stateful') {
1497
+ if (this.StatefulProgrammableSwitch) {
1498
+ this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent, e);
1499
+ this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, e);
1500
+ }
1501
+ } else if (this.botDeviceType === 'switch') {
1502
+ if (this.Switch) {
1503
+ this.Switch.Service.updateCharacteristic(this.hap.Characteristic.On, e);
1504
+ }
1505
+ } else {
1506
+ if (this.Outlet) {
1507
+ this.Outlet.Service.updateCharacteristic(this.hap.Characteristic.On, e);
1575
1508
  }
1576
1509
  }
1577
- }
1578
-
1579
- enablingDeviceLogging(): boolean {
1580
- return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
1510
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
1511
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
1581
1512
  }
1582
1513
  }