@switchbot/homebridge-switchbot 3.5.0-beta.9 → 3.5.0

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