@switchbot/homebridge-switchbot 3.5.0-beta.8 → 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 +170 -26
  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,132 +1,110 @@
1
- import { hostname } from 'os';
2
- import { request } from 'undici';
3
- import { sleep } from '../utils.js';
4
- import { MqttClient } from 'mqtt';
5
- import asyncmqtt from 'async-mqtt';
1
+ /* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
+ *
3
+ * waterdetector.ts: @switchbot/homebridge-switchbot.
4
+ */
5
+ import { deviceBase } from './device.js';
6
6
  import { interval, Subject } from 'rxjs';
7
+ import { Devices } from '../settings.js';
7
8
  import { skipWhile } from 'rxjs/operators';
8
- import { SwitchBotPlatform } from '../platform.js';
9
- import { Service, PlatformAccessory, CharacteristicValue, API, Logging, HAP } from 'homebridge';
10
- import { device, devicesConfig, serviceData, deviceStatus, Devices, SwitchBotPlatformConfig } from '../settings.js';
9
+
10
+ import type { SwitchBotPlatform } from '../platform.js';
11
+ import type { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
12
+ import type { device, devicesConfig, serviceData, deviceStatus } from '../settings.js';
11
13
 
12
14
  /**
13
15
  * Platform Accessory
14
16
  * An instance of this class is created for each accessory your platform registers
15
17
  * Each accessory may expose multiple services of different service types.
16
18
  */
17
- export class WaterDetector {
18
- public readonly api: API;
19
- public readonly log: Logging;
20
- public readonly config!: SwitchBotPlatformConfig;
21
- protected readonly hap: HAP;
19
+ export class WaterDetector extends deviceBase {
22
20
  // Services
23
- leakService?: Service;
24
- batteryService: Service;
25
-
26
- // Characteristic Values
27
- StatusActive!: CharacteristicValue;
28
- LeakDetected!: CharacteristicValue;
29
- BatteryLevel!: CharacteristicValue;
30
- ChargingState!: CharacteristicValue;
31
- StatusLowBattery!: CharacteristicValue;
32
- FirmwareRevision!: CharacteristicValue;
33
-
34
- // OpenAPI Status
35
- OpenAPI_BatteryLevel: deviceStatus['battery'];
36
- OpenAPI_FirmwareRevision: deviceStatus['version'];
37
- OpenAPI_LeakDetected: deviceStatus['status'];
38
-
39
- // BLE Status
40
- BLE_BatteryLevel!: serviceData['battery'];
41
- BLE_LeakDetected!: number;//serviceData['status'];
42
-
43
- // BLE Others
44
- BLE_IsConnected?: boolean;
45
-
46
- //MQTT stuff
47
- mqttClient: MqttClient | null = null;
48
-
49
- // EVE history service handler
50
- historyService?: any;
51
-
52
- // Config
53
- scanDuration!: number;
54
- deviceLogging!: string;
55
- deviceRefreshRate!: number;
21
+ private Battery: {
22
+ Name: CharacteristicValue
23
+ Service: Service;
24
+ BatteryLevel: CharacteristicValue;
25
+ StatusLowBattery: CharacteristicValue;
26
+ ChargingState: CharacteristicValue;
27
+ };
28
+
29
+ private LeakSensor?: {
30
+ Name: CharacteristicValue;
31
+ Service: Service;
32
+ StatusActive: CharacteristicValue;
33
+ LeakDetected: CharacteristicValue;
34
+ };
56
35
 
57
36
  // Updates
58
37
  WaterDetectorUpdateInProgress!: boolean;
59
38
  doWaterDetectorUpdate: Subject<void>;
60
39
 
61
- // Connection
62
- private readonly OpenAPI: boolean;
63
- private readonly BLE: boolean;
64
-
65
40
  constructor(
66
- private readonly platform: SwitchBotPlatform,
67
- private accessory: PlatformAccessory,
68
- public device: device & devicesConfig,
41
+ readonly platform: SwitchBotPlatform,
42
+ accessory: PlatformAccessory,
43
+ device: device & devicesConfig,
69
44
  ) {
70
- this.api = this.platform.api;
71
- this.log = this.platform.log;
72
- this.config = this.platform.config;
73
- this.hap = this.api.hap;
74
- // Connection
75
- this.BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI';
76
- this.OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI';
77
- // default placeholders
78
- this.deviceLogs(device);
79
- this.scan(device);
80
- this.refreshRate(device);
81
- this.deviceContext();
82
- this.setupHistoryService(device);
83
- this.setupMqtt(device);
84
- this.deviceConfig(device);
45
+ super(platform, accessory, device);
85
46
 
86
47
  // this is subject we use to track when we need to POST changes to the SwitchBot API
87
48
  this.doWaterDetectorUpdate = new Subject();
88
49
  this.WaterDetectorUpdateInProgress = false;
89
50
 
90
- // Retrieve initial values and updateHomekit
91
- this.refreshStatus();
51
+ // Initialize Battery Service
52
+ accessory.context.Battery = accessory.context.Battery ?? {};
53
+ this.Battery = {
54
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
55
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
56
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
57
+ StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
58
+ ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGEABLE,
59
+ };
60
+ accessory.context.Battery = this.Battery as object;
61
+
62
+ // Initialize Battery Characteristic
63
+ this.Battery.Service
64
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
65
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE)
66
+ .getCharacteristic(this.hap.Characteristic.BatteryLevel)
67
+ .onGet(() => {
68
+ return this.Battery.StatusLowBattery;
69
+ });
92
70
 
93
- // set accessory information
94
- accessory
95
- .getService(this.hap.Service.AccessoryInformation)!
96
- .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
97
- .setCharacteristic(this.hap.Characteristic.Model, 'WoWaterDetector')
98
- .setCharacteristic(this.hap.Characteristic.SerialNumber, device.deviceId)
99
- .setCharacteristic(this.hap.Characteristic.FirmwareRevision, accessory.context.FirmwareRevision);
71
+ this.Battery.Service
72
+ .getCharacteristic(this.hap.Characteristic.StatusLowBattery)
73
+ .onGet(() => {
74
+ return this.Battery.StatusLowBattery;
75
+ });
100
76
 
101
- // Leak Sensor Service
77
+ // Initialize Leak Sensor Service
102
78
  if (device.waterdetector?.hide_leak) {
103
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leak Sensor Service`);
104
- this.leakService = this.accessory.getService(this.hap.Service.LeakSensor);
105
- accessory.removeService(this.leakService!);
106
- } else if (!this.leakService) {
107
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Leak Sensor Service`);
108
- const leakService = `${accessory.displayName} Leak Sensor`;
109
- (this.leakService = this.accessory.getService(this.hap.Service.LeakSensor)
110
- || this.accessory.addService(this.hap.Service.LeakSensor)), leakService;
111
-
112
- this.leakService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Leak Sensor`);
113
- if (!this.leakService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
114
- this.leakService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Leak Sensor`);
79
+ if (this.LeakSensor) {
80
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leak Sensor Service`);
81
+ this.LeakSensor.Service = this.accessory.getService(this.hap.Service.LeakSensor) as Service;
82
+ accessory.removeService(this.LeakSensor.Service);
83
+ } else {
84
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Leak Sensor Service Not Found`);
115
85
  }
116
86
  } else {
117
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Leak Sensor Service Not Added`);
87
+ accessory.context.LeakSensor = accessory.context.LeakSensor ?? {};
88
+ this.LeakSensor = {
89
+ Name: accessory.context.LeakSensor.Name ?? `${accessory.displayName} Leak Sensor`,
90
+ Service: accessory.getService(this.hap.Service.LeakSensor) ?? this.accessory.addService(this.hap.Service.LeakSensor) as Service,
91
+ StatusActive: accessory.context.StatusActive ?? false,
92
+ LeakDetected: accessory.context.LeakDetected ?? this.hap.Characteristic.LeakDetected.LEAK_NOT_DETECTED,
93
+ };
94
+ accessory.context.LeakSensor = this.LeakSensor as object;
95
+
96
+ // Initialize LeakSensor Characteristic
97
+ this.LeakSensor!.Service
98
+ .setCharacteristic(this.hap.Characteristic.Name, this.LeakSensor.Name)
99
+ .setCharacteristic(this.hap.Characteristic.StatusActive, true)
100
+ .getCharacteristic(this.hap.Characteristic.LeakDetected)
101
+ .onGet(() => {
102
+ return this.LeakSensor!.LeakDetected;
103
+ });
118
104
  }
119
105
 
120
- // Battery Service
121
- const batteryService = `${accessory.displayName} Battery`;
122
- (this.batteryService = this.accessory.getService(this.hap.Service.Battery)
123
- || accessory.addService(this.hap.Service.Battery)), batteryService;
124
-
125
- this.batteryService.setCharacteristic(this.hap.Characteristic.Name, `${accessory.displayName} Battery`);
126
- if (!this.batteryService.testCharacteristic(this.hap.Characteristic.ConfiguredName)) {
127
- this.batteryService.addCharacteristic(this.hap.Characteristic.ConfiguredName, `${accessory.displayName} Battery`);
128
- }
129
- this.batteryService.setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
106
+ // Retrieve initial values and updateHomekit
107
+ this.refreshStatus();
130
108
 
131
109
  // Retrieve initial values and updateHomekit
132
110
  this.updateHomeKitCharacteristics();
@@ -139,91 +117,66 @@ export class WaterDetector {
139
117
  });
140
118
 
141
119
  //regisiter webhook event handler
142
- if (this.device.webhook) {
143
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
144
- this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
145
- try {
146
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
147
- const { status } = context;
148
- const { LeakDetected } = this;
149
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
150
- '(status) = ' +
151
- `Webhook:(${status}), ` +
152
- `current:(${LeakDetected})`);
153
- this.LeakDetected = status;
154
- this.updateHomeKitCharacteristics();
155
- } catch (e: any) {
156
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
157
- + `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
158
- }
159
- };
160
- }
161
- }
162
-
163
- /**
164
- * Parse the device status from the SwitchBot api
165
- */
166
- async parseStatus(): Promise<void> {
167
- if (!this.device.enableCloudService && this.OpenAPI) {
168
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} parseStatus enableCloudService: ${this.device.enableCloudService}`);
169
- } else if (this.BLE) {
170
- await this.BLEparseStatus();
171
- } else if (this.OpenAPI && this.platform.config.credentials?.token) {
172
- await this.openAPIparseStatus();
173
- } else {
174
- await this.offlineOff();
175
- this.debugWarnLog(
176
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`,
177
- );
178
- }
120
+ this.registerWebhook(accessory, device);
179
121
  }
180
122
 
181
- async BLEparseStatus(): Promise<void> {
123
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
182
124
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
183
-
184
125
  // Battery
185
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
186
- if (this.BatteryLevel < 15) {
187
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
126
+ this.Battery.BatteryLevel = Number(serviceData.battery);
127
+ if (this.Battery.BatteryLevel < 15) {
128
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
188
129
  } else {
189
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
130
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
190
131
  }
191
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
132
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}, StatusLowBattery: ${this.Battery.StatusLowBattery}`);
192
133
 
193
134
  // LeakDetected
194
- this.LeakDetected = this.BLE_LeakDetected!;
195
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakDetected}`);
135
+ if (this.device.waterdetector?.hide_leak) {
136
+ this.LeakSensor!.LeakDetected = serviceData.status!;
137
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakSensor!.LeakDetected}`);
138
+ }
196
139
  }
197
140
 
198
- async openAPIparseStatus(): Promise<void> {
141
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
199
142
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
200
143
  // StatusLowBattery
201
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
202
- if (this.BatteryLevel < 10) {
203
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
144
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
145
+ if (this.Battery.BatteryLevel < 10) {
146
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
204
147
  } else {
205
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
148
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
206
149
  }
207
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
150
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}, StatusLowBattery: ${this.Battery.StatusLowBattery}`);
208
151
 
209
152
  // BatteryLevel
210
- if (Number.isNaN(this.BatteryLevel)) {
211
- this.BatteryLevel = 100;
153
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
154
+ this.Battery.BatteryLevel = 100;
212
155
  }
213
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
156
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
214
157
 
215
158
  // LeakDetected
216
- this.LeakDetected = this.OpenAPI_LeakDetected!;
217
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakDetected}`);
218
-
219
- // FirmwareRevision
220
- this.FirmwareRevision = this.OpenAPI_FirmwareRevision!;
221
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
159
+ if (!this.device.waterdetector?.hide_leak) {
160
+ this.LeakSensor!.LeakDetected = deviceStatus.body.status!;
161
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakSensor!.LeakDetected}`);
162
+ }
163
+
164
+ // Firmware Version
165
+ const version = deviceStatus.body.version?.toString();
166
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
167
+ if (deviceStatus.body.version) {
168
+ const deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
169
+ this.accessory
170
+ .getService(this.hap.Service.AccessoryInformation)!
171
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
172
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
173
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
174
+ .updateValue(deviceVersion);
175
+ this.accessory.context.deviceVersion = deviceVersion;
176
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
177
+ }
222
178
  }
223
179
 
224
- /**
225
- * Asks the SwitchBot API for the latest device information
226
- */
227
180
  async refreshStatus(): Promise<void> {
228
181
  if (!this.device.enableCloudService && this.OpenAPI) {
229
182
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus enableCloudService: ${this.device.enableCloudService}`);
@@ -233,10 +186,8 @@ export class WaterDetector {
233
186
  await this.openAPIRefreshStatus();
234
187
  } else {
235
188
  await this.offlineOff();
236
- this.debugWarnLog(
237
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` +
238
- ` ${this.device.connectionType}, refreshStatus will not happen.`,
239
- );
189
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
190
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
240
191
  }
241
192
  }
242
193
 
@@ -253,49 +204,43 @@ export class WaterDetector {
253
204
  // Start to monitor advertisement packets
254
205
  (async () => {
255
206
  // Start to monitor advertisement packets
256
- await switchbot.startScan({
257
- model: 'l',
258
- id: this.device.bleMac,
259
- });
207
+ await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
260
208
  // Set an event handler
261
209
  switchbot.onadvertisement = (ad: any) => {
262
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
263
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.serviceData.model}`);
264
- if (this.device.bleMac === ad.address && ad.serviceData.model === 'l') {
210
+ if (this.device.bleMac === ad.address && ad.model === this.device.bleModel) {
211
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ${JSON.stringify(ad, null, ' ')}`);
212
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} address: ${ad.address}, model: ${ad.model}`);
265
213
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
266
- this.BLE_LeakDetected = ad.serviceData.status;
267
- this.BLE_BatteryLevel = ad.serviceData.battery;
268
214
  } else {
269
215
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
270
216
  }
271
217
  };
272
- // Wait 1 seconds
218
+ // Wait 10 seconds
273
219
  await switchbot.wait(this.scanDuration * 1000);
274
220
  // Stop to monitor
275
221
  await switchbot.stopScan();
276
222
  // Update HomeKit
277
- await this.BLEparseStatus();
223
+ await this.BLEparseStatus(switchbot.onadvertisement.serviceData);
278
224
  await this.updateHomeKitCharacteristics();
279
225
  })();
226
+ if (switchbot === undefined) {
227
+ await this.BLERefreshConnection(switchbot);
228
+ }
280
229
  }
281
230
 
282
231
  async openAPIRefreshStatus(): Promise<void> {
283
232
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
284
233
  try {
285
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
286
- headers: this.platform.generateHeaders(),
287
- });
234
+ const { body, statusCode } = await this.platform.retryRequest(this.deviceMaxRetries, this.deviceDelayBetweenRetries,
235
+ `${Devices}/${this.device.deviceId}/status`, { headers: this.platform.generateHeaders() });
288
236
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
289
237
  const deviceStatus: any = await body.json();
290
238
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
291
239
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
292
240
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
293
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
241
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
294
242
  + `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
295
- this.OpenAPI_LeakDetected = deviceStatus.body.status;
296
- this.OpenAPI_BatteryLevel = deviceStatus.body.battery;
297
- this.OpenAPI_FirmwareRevision = deviceStatus.body.version;
298
- this.openAPIparseStatus();
243
+ this.openAPIparseStatus(deviceStatus);
299
244
  this.updateHomeKitCharacteristics();
300
245
  } else {
301
246
  this.statusCode(statusCode);
@@ -303,10 +248,33 @@ export class WaterDetector {
303
248
  }
304
249
  } catch (e: any) {
305
250
  this.apiError(e);
306
- this.errorLog(
307
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` +
308
- ` Connection, Error Message: ${JSON.stringify(e.message)}`,
309
- );
251
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
252
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
253
+ }
254
+ }
255
+
256
+ async registerWebhook(accessory: PlatformAccessory, device: device & devicesConfig) {
257
+ if (device.webhook) {
258
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is listening webhook.`);
259
+ this.platform.webhookEventHandler[device.deviceId] = async (context) => {
260
+ try {
261
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
262
+ const { detectionState, battery } = context;
263
+ const { LeakDetected } = this.LeakSensor ? this.LeakSensor : { LeakDetected: undefined };
264
+ const { BatteryLevel } = this.Battery ? this.Battery : { BatteryLevel: undefined };
265
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} (detectionState, battery) = Webhook: (${detectionState}, ${battery}), `
266
+ + `current: (${LeakDetected}, ${BatteryLevel})`);
267
+ if (!device.waterdetector?.hide_leak) {
268
+ this.LeakSensor!.LeakDetected = detectionState;
269
+ }
270
+ this.Battery.BatteryLevel = battery;
271
+ this.updateHomeKitCharacteristics();
272
+ } catch (e: any) {
273
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
274
+ }
275
+ };
276
+ } else {
277
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is not listening webhook.`);
310
278
  }
311
279
  }
312
280
 
@@ -317,129 +285,54 @@ export class WaterDetector {
317
285
  const mqttmessage: string[] = [];
318
286
  const entry = { time: Math.round(new Date().valueOf() / 1000) };
319
287
  if (!this.device.waterdetector?.hide_leak) {
320
- if (this.LeakDetected === undefined) {
321
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakDetected}`);
288
+ if (this.LeakSensor!.LeakDetected === undefined) {
289
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakSensor!.LeakDetected}`);
322
290
  } else {
323
291
  if (this.device.mqttURL) {
324
- mqttmessage.push(`"LeakDetected": ${this.LeakDetected}`);
292
+ mqttmessage.push(`"LeakDetected": ${this.LeakSensor!.LeakDetected}`);
325
293
  }
326
294
  if (this.device.history) {
327
- entry['leak'] = this.LeakDetected;
295
+ entry['leak'] = this.LeakSensor!.LeakDetected;
328
296
  }
329
- this.accessory.context.LeakDetected = this.LeakDetected;
330
- this.leakService?.updateCharacteristic(this.hap.Characteristic.LeakDetected, this.LeakDetected);
331
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic LeakDetected: ${this.LeakDetected}`);
297
+ this.accessory.context.LeakDetected = this.LeakSensor!.LeakDetected;
298
+ this.LeakSensor!.Service.updateCharacteristic(this.hap.Characteristic.LeakDetected, this.LeakSensor!.LeakDetected);
299
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic LeakDetected: ${this.LeakSensor!.LeakDetected}`);
332
300
  }
333
301
  }
334
- if (this.BatteryLevel === undefined) {
335
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
302
+ if (this.Battery.BatteryLevel === undefined) {
303
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
336
304
  } else {
337
305
  if (this.device.mqttURL) {
338
- mqttmessage.push(`"battery": ${this.BatteryLevel}`);
306
+ mqttmessage.push(`"battery": ${this.Battery.BatteryLevel}`);
339
307
  }
340
- this.accessory.context.BatteryLevel = this.BatteryLevel;
341
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.BatteryLevel);
342
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
308
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
309
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
310
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
343
311
  }
344
- if (this.StatusLowBattery === undefined) {
345
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
312
+ if (this.Battery.StatusLowBattery === undefined) {
313
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
346
314
  } else {
347
315
  if (this.device.mqttURL) {
348
- mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`);
316
+ mqttmessage.push(`"lowBattery": ${this.Battery.StatusLowBattery}`);
349
317
  }
350
- this.accessory.context.StatusLowBattery = this.StatusLowBattery;
351
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.StatusLowBattery);
352
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
318
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
319
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
320
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
321
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
353
322
  }
354
323
  if (this.device.mqttURL) {
355
324
  this.mqttPublish(`{${mqttmessage.join(',')}}`);
356
325
  }
357
- if (Number(this.LeakDetected) > 0) {
358
- // reject unreliable data
359
- if (this.device.history) {
360
- this.historyService?.addEntry(entry);
361
- }
362
- }
363
- }
364
-
365
- /*
366
- * Publish MQTT message for topics of
367
- * 'homebridge-switchbot/meter/xx:xx:xx:xx:xx:xx'
368
- */
369
- mqttPublish(message: any) {
370
- const mac = this.device.deviceId
371
- ?.toLowerCase()
372
- .match(/[\s\S]{1,2}/g)
373
- ?.join(':');
374
- const options = this.device.mqttPubOptions || {};
375
- this.mqttClient?.publish(`homebridge-switchbot/meter/${mac}`, `${message}`, options);
376
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT message: ${message} options:${JSON.stringify(options)}`);
377
- }
378
-
379
- /*
380
- * Setup MQTT hadler if URL is specified.
381
- */
382
- async setupMqtt(device: device & devicesConfig): Promise<void> {
383
- if (device.mqttURL) {
384
- try {
385
- const { connectAsync } = asyncmqtt;
386
- this.mqttClient = await connectAsync(device.mqttURL, device.mqttOptions || {});
387
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT connection has been established successfully.`);
388
- this.mqttClient.on('error', (e: Error) => {
389
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to publish MQTT messages. ${e}`);
390
- });
391
- } catch (e) {
392
- this.mqttClient = null;
393
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to establish MQTT connection. ${e}`);
326
+ if (!this.device.waterdetector?.hide_leak) {
327
+ if (Number(this.LeakSensor!.LeakDetected) > 0) {
328
+ // reject unreliable data
329
+ if (this.device.history) {
330
+ this.historyService?.addEntry(entry);
331
+ }
394
332
  }
395
333
  }
396
334
  }
397
335
 
398
- /*
399
- * Setup EVE history graph feature if enabled.
400
- */
401
- async setupHistoryService(device: device & devicesConfig): Promise<void> {
402
- const mac = this.device
403
- .deviceId!.match(/.{1,2}/g)!
404
- .join(':')
405
- .toLowerCase();
406
- this.historyService = device.history
407
- ? new this.platform.fakegatoAPI('room', this.accessory, {
408
- log: this.platform.log,
409
- storage: 'fs',
410
- filename: `${hostname().split('.')[0]}_${mac}_persist.json`,
411
- })
412
- : null;
413
- }
414
-
415
- async stopScanning(switchbot: any) {
416
- switchbot.stopScan();
417
- if (this.BLE_IsConnected) {
418
- await this.BLEparseStatus();
419
- await this.updateHomeKitCharacteristics();
420
- } else {
421
- await this.BLERefreshConnection(switchbot);
422
- }
423
- }
424
-
425
- async getCustomBLEAddress(switchbot: any) {
426
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
427
- (async () => {
428
- // Start to monitor advertisement packets
429
- await switchbot.startScan({
430
- model: 'i',
431
- });
432
- // Set an event handler
433
- switchbot.onadvertisement = (ad: any) => {
434
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
435
- };
436
- await sleep(10000);
437
- // Stop to monitor
438
- switchbot.stopScan();
439
- })();
440
- }
441
- }
442
-
443
336
  async BLERefreshConnection(switchbot: any): Promise<void> {
444
337
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot:`
445
338
  + ` ${JSON.stringify(switchbot)}`);
@@ -449,241 +342,17 @@ export class WaterDetector {
449
342
  }
450
343
  }
451
344
 
452
- async scan(device: device & devicesConfig): Promise<void> {
453
- if (device.scanDuration) {
454
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
455
- if (this.BLE) {
456
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
457
- }
458
- } else {
459
- this.scanDuration = this.accessory.context.scanDuration = 1;
460
- if (this.BLE) {
461
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
462
- }
463
- }
464
- }
465
-
466
- async statusCode(statusCode: number): Promise<void> {
467
- switch (statusCode) {
468
- case 151:
469
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
470
- break;
471
- case 152:
472
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
473
- break;
474
- case 160:
475
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
476
- break;
477
- case 161:
478
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
479
- this.offlineOff();
480
- break;
481
- case 171:
482
- this.errorLog(
483
- `${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. ` +
484
- `Hub: ${this.device.hubDeviceId}`,
485
- );
486
- this.offlineOff();
487
- break;
488
- case 190:
489
- this.errorLog(
490
- `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
491
- ` Or command format is invalid, statusCode: ${statusCode}`,
492
- );
493
- break;
494
- case 100:
495
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
496
- break;
497
- case 200:
498
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
499
- break;
500
- case 400:
501
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bad Request, The client has issued an invalid request. `
502
- + `This is commonly used to specify validation errors in a request payload, statusCode: ${statusCode}`);
503
- break;
504
- case 401:
505
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unauthorized, Authorization for the API is required, `
506
- + `but the request has not been authenticated, statusCode: ${statusCode}`);
507
- break;
508
- case 403:
509
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Forbidden, The request has been authenticated but does not `
510
- + `have appropriate permissions, or a requested resource is not found, statusCode: ${statusCode}`);
511
- break;
512
- case 404:
513
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Found, Specifies the requested path does not exist, `
514
- + `statusCode: ${statusCode}`);
515
- break;
516
- case 406:
517
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Not Acceptable, The client has requested a MIME type via `
518
- + `the Accept header for a value not supported by the server, statusCode: ${statusCode}`);
519
- break;
520
- case 415:
521
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unsupported Media Type, The client has defined a contentType `
522
- + `header that is not supported by the server, statusCode: ${statusCode}`);
523
- break;
524
- case 422:
525
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Unprocessable Entity, The client has made a valid request, `
526
- + `but the server cannot process it. This is often used for APIs for which certain limits have been exceeded, statusCode: ${statusCode}`);
527
- break;
528
- case 429:
529
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Too Many Requests, The client has exceeded the number of `
530
- + `requests allowed for a given time window, statusCode: ${statusCode}`);
531
- break;
532
- case 500:
533
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Internal Server Error, An unexpected error on the SmartThings `
534
- + `servers has occurred. These errors should be rare, statusCode: ${statusCode}`);
535
- break;
536
- default:
537
- this.infoLog(
538
- `${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: ` +
539
- `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`,
540
- );
541
- }
542
- }
543
-
544
345
  async offlineOff(): Promise<void> {
545
- if (this.device.offline) {
546
- await this.deviceContext();
547
- await this.updateHomeKitCharacteristics();
346
+ if (this.device.offline && !this.device.waterdetector?.hide_leak) {
347
+ this.LeakSensor!.Service.updateCharacteristic(this.hap.Characteristic.LeakDetected, this.hap.Characteristic.LeakDetected.LEAK_NOT_DETECTED);
548
348
  }
549
349
  }
550
350
 
551
351
  async apiError(e: any): Promise<void> {
552
352
  if (!this.device.waterdetector?.hide_leak) {
553
- this.leakService?.updateCharacteristic(this.hap.Characteristic.LeakDetected, e);
554
- }
555
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
556
- this.batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
557
- }
558
-
559
- async deviceContext() {
560
- if (this.LeakDetected === undefined) {
561
- this.LeakDetected = 0;
562
- } else {
563
- this.LeakDetected = this.accessory.context.LeakDetected;
564
- }
565
- if (this.BatteryLevel === undefined) {
566
- this.BatteryLevel = 100;
567
- } else {
568
- this.BatteryLevel = this.accessory.context.BatteryLevel;
569
- }
570
- if (this.StatusLowBattery === undefined) {
571
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
572
- this.accessory.context.StatusLowBattery = this.StatusLowBattery;
573
- } else {
574
- this.StatusLowBattery = this.accessory.context.StatusLowBattery;
575
- }
576
- if (this.FirmwareRevision === undefined) {
577
- this.FirmwareRevision = this.platform.version;
578
- this.accessory.context.FirmwareRevision = this.FirmwareRevision;
579
- }
580
- }
581
-
582
- async refreshRate(device: device & devicesConfig): Promise<void> {
583
- if (device.refreshRate) {
584
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
585
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
586
- } else if (this.platform.config.options!.refreshRate) {
587
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
588
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
589
- }
590
- }
591
-
592
- async deviceConfig(device: device & devicesConfig): Promise<void> {
593
- let config = {};
594
- if (device.waterdetector) {
595
- config = device.waterdetector;
596
- }
597
- if (device.connectionType !== undefined) {
598
- config['connectionType'] = device.connectionType;
353
+ this.LeakSensor!.Service.updateCharacteristic(this.hap.Characteristic.LeakDetected, e);
599
354
  }
600
- if (device.external !== undefined) {
601
- config['external'] = device.external;
602
- }
603
- if (device.mqttURL !== undefined) {
604
- config['mqttURL'] = device.mqttURL;
605
- }
606
- if (device.logging !== undefined) {
607
- config['logging'] = device.logging;
608
- }
609
- if (device.refreshRate !== undefined) {
610
- config['refreshRate'] = device.refreshRate;
611
- }
612
- if (device.scanDuration !== undefined) {
613
- config['scanDuration'] = device.scanDuration;
614
- }
615
- if (device.webhook !== undefined) {
616
- config['webhook'] = device.webhook;
617
- }
618
- if (Object.entries(config).length !== 0) {
619
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
620
- }
621
- }
622
-
623
- async deviceLogs(device: device & devicesConfig): Promise<void> {
624
- if (this.platform.debugMode) {
625
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
626
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
627
- } else if (device.logging) {
628
- this.deviceLogging = this.accessory.context.logging = device.logging;
629
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
630
- } else if (this.platform.config.options?.logging) {
631
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
632
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
633
- } else {
634
- this.deviceLogging = this.accessory.context.logging = 'standard';
635
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
636
- }
637
- }
638
-
639
- /**
640
- * Logging for Device
641
- */
642
- infoLog(...log: any[]): void {
643
- if (this.enablingDeviceLogging()) {
644
- this.platform.log.info(String(...log));
645
- }
646
- }
647
-
648
- warnLog(...log: any[]): void {
649
- if (this.enablingDeviceLogging()) {
650
- this.platform.log.warn(String(...log));
651
- }
652
- }
653
-
654
- debugWarnLog(...log: any[]): void {
655
- if (this.enablingDeviceLogging()) {
656
- if (this.deviceLogging?.includes('debug')) {
657
- this.platform.log.warn('[DEBUG]', String(...log));
658
- }
659
- }
660
- }
661
-
662
- errorLog(...log: any[]): void {
663
- if (this.enablingDeviceLogging()) {
664
- this.platform.log.error(String(...log));
665
- }
666
- }
667
-
668
- debugErrorLog(...log: any[]): void {
669
- if (this.enablingDeviceLogging()) {
670
- if (this.deviceLogging?.includes('debug')) {
671
- this.platform.log.error('[DEBUG]', String(...log));
672
- }
673
- }
674
- }
675
-
676
- debugLog(...log: any[]): void {
677
- if (this.enablingDeviceLogging()) {
678
- if (this.deviceLogging === 'debug') {
679
- this.platform.log.info('[DEBUG]', String(...log));
680
- } else {
681
- this.platform.log.debug(String(...log));
682
- }
683
- }
684
- }
685
-
686
- enablingDeviceLogging(): boolean {
687
- return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
355
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
356
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
688
357
  }
689
358
  }