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

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