@switchbot/homebridge-switchbot 3.5.0-beta.9 → 3.5.1-beta.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 (177) hide show
  1. package/.vscode/settings.json +4 -1
  2. package/CHANGELOG.md +4 -1
  3. package/config.schema.json +164 -22
  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 +457 -866
  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 +851 -913
  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 +316 -742
  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 +380 -833
  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 +267 -602
  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 +469 -897
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/device.d.ts +76 -0
  29. package/dist/device/device.d.ts.map +1 -0
  30. package/dist/device/device.js +846 -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 +645 -0
  35. package/dist/device/fan.js.map +1 -0
  36. package/dist/device/hub.d.ts +19 -58
  37. package/dist/device/hub.d.ts.map +1 -1
  38. package/dist/device/hub.js +304 -640
  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 +300 -710
  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 +225 -643
  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 +371 -742
  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 +309 -642
  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 +223 -638
  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 +216 -644
  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 +209 -588
  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 +141 -532
  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 +252 -609
  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 +179 -521
  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 +337 -482
  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 +108 -333
  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 +47 -299
  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 +95 -364
  102. package/dist/irdevice/fan.js.map +1 -1
  103. package/dist/irdevice/irdevice.d.ts +46 -0
  104. package/dist/irdevice/irdevice.d.ts.map +1 -0
  105. package/dist/irdevice/irdevice.js +393 -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 +121 -376
  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 +441 -584
  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 +94 -353
  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 +48 -299
  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 +50 -305
  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 +66 -18
  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 +95 -0
  136. package/dist/utils.d.ts.map +1 -1
  137. package/dist/utils.js +657 -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 +488 -937
  143. package/src/device/bot.ts +907 -1016
  144. package/src/device/ceilinglight.ts +330 -798
  145. package/src/device/colorbulb.ts +394 -904
  146. package/src/device/contact.ts +298 -637
  147. package/src/device/curtain.ts +496 -954
  148. package/src/device/device.ts +872 -0
  149. package/src/device/fan.ts +692 -0
  150. package/src/device/hub.ts +338 -671
  151. package/src/device/humidifier.ts +330 -777
  152. package/src/device/iosensor.ts +258 -671
  153. package/src/device/lightstrip.ts +394 -809
  154. package/src/device/lock.ts +345 -700
  155. package/src/device/meter.ts +256 -666
  156. package/src/device/meterplus.ts +248 -672
  157. package/src/device/motion.ts +234 -622
  158. package/src/device/plug.ts +152 -572
  159. package/src/device/robotvacuumcleaner.ts +273 -653
  160. package/src/device/waterdetector.ts +198 -549
  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 +368 -540
  165. package/src/irdevice/airpurifier.ts +134 -369
  166. package/src/irdevice/camera.ts +60 -324
  167. package/src/irdevice/fan.ts +111 -392
  168. package/src/irdevice/irdevice.ts +406 -0
  169. package/src/irdevice/light.ts +159 -425
  170. package/src/irdevice/other.ts +509 -661
  171. package/src/irdevice/tv.ts +123 -388
  172. package/src/irdevice/vacuumcleaner.ts +61 -324
  173. package/src/irdevice/waterheater.ts +63 -333
  174. package/src/platform.ts +395 -259
  175. package/src/settings.ts +120 -610
  176. package/src/utils.ts +661 -1
  177. package/src/device/waterdetector.json +0 -11
@@ -1,132 +1,109 @@
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
7
  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';
8
+
9
+ import type { SwitchBotPlatform } from '../platform.js';
10
+ import type { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
11
+ import type { device, devicesConfig, serviceData, deviceStatus } from '../settings.js';
11
12
 
12
13
  /**
13
14
  * Platform Accessory
14
15
  * An instance of this class is created for each accessory your platform registers
15
16
  * Each accessory may expose multiple services of different service types.
16
17
  */
17
- export class WaterDetector {
18
- public readonly api: API;
19
- public readonly log: Logging;
20
- public readonly config!: SwitchBotPlatformConfig;
21
- protected readonly hap: HAP;
18
+ export class WaterDetector extends deviceBase {
22
19
  // 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;
20
+ private Battery: {
21
+ Name: CharacteristicValue
22
+ Service: Service;
23
+ BatteryLevel: CharacteristicValue;
24
+ StatusLowBattery: CharacteristicValue;
25
+ ChargingState: CharacteristicValue;
26
+ };
27
+
28
+ private LeakSensor?: {
29
+ Name: CharacteristicValue;
30
+ Service: Service;
31
+ StatusActive: CharacteristicValue;
32
+ LeakDetected: CharacteristicValue;
33
+ };
56
34
 
57
35
  // Updates
58
36
  WaterDetectorUpdateInProgress!: boolean;
59
37
  doWaterDetectorUpdate: Subject<void>;
60
38
 
61
- // Connection
62
- private readonly OpenAPI: boolean;
63
- private readonly BLE: boolean;
64
-
65
39
  constructor(
66
- private readonly platform: SwitchBotPlatform,
67
- private accessory: PlatformAccessory,
68
- public device: device & devicesConfig,
40
+ readonly platform: SwitchBotPlatform,
41
+ accessory: PlatformAccessory,
42
+ device: device & devicesConfig,
69
43
  ) {
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);
44
+ super(platform, accessory, device);
85
45
 
86
46
  // this is subject we use to track when we need to POST changes to the SwitchBot API
87
47
  this.doWaterDetectorUpdate = new Subject();
88
48
  this.WaterDetectorUpdateInProgress = false;
89
49
 
90
- // Retrieve initial values and updateHomekit
91
- this.refreshStatus();
50
+ // Initialize Battery Service
51
+ accessory.context.Battery = accessory.context.Battery ?? {};
52
+ this.Battery = {
53
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
54
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
55
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
56
+ StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
57
+ ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGEABLE,
58
+ };
59
+ accessory.context.Battery = this.Battery as object;
60
+
61
+ // Initialize Battery Characteristic
62
+ this.Battery.Service
63
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
64
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE)
65
+ .getCharacteristic(this.hap.Characteristic.BatteryLevel)
66
+ .onGet(() => {
67
+ return this.Battery.StatusLowBattery;
68
+ });
92
69
 
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);
70
+ this.Battery.Service
71
+ .getCharacteristic(this.hap.Characteristic.StatusLowBattery)
72
+ .onGet(() => {
73
+ return this.Battery.StatusLowBattery;
74
+ });
100
75
 
101
- // Leak Sensor Service
76
+ // Initialize Leak Sensor Service
102
77
  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`);
78
+ if (this.LeakSensor) {
79
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leak Sensor Service`);
80
+ this.LeakSensor.Service = this.accessory.getService(this.hap.Service.LeakSensor) as Service;
81
+ accessory.removeService(this.LeakSensor.Service);
82
+ } else {
83
+ this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Leak Sensor Service Not Found`);
115
84
  }
116
85
  } else {
117
- this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Leak Sensor Service Not Added`);
86
+ accessory.context.LeakSensor = accessory.context.LeakSensor ?? {};
87
+ this.LeakSensor = {
88
+ Name: accessory.context.LeakSensor.Name ?? `${accessory.displayName} Leak Sensor`,
89
+ Service: accessory.getService(this.hap.Service.LeakSensor) ?? this.accessory.addService(this.hap.Service.LeakSensor) as Service,
90
+ StatusActive: accessory.context.StatusActive ?? false,
91
+ LeakDetected: accessory.context.LeakDetected ?? this.hap.Characteristic.LeakDetected.LEAK_NOT_DETECTED,
92
+ };
93
+ accessory.context.LeakSensor = this.LeakSensor as object;
94
+
95
+ // Initialize LeakSensor Characteristic
96
+ this.LeakSensor!.Service
97
+ .setCharacteristic(this.hap.Characteristic.Name, this.LeakSensor.Name)
98
+ .setCharacteristic(this.hap.Characteristic.StatusActive, true)
99
+ .getCharacteristic(this.hap.Characteristic.LeakDetected)
100
+ .onGet(() => {
101
+ return this.LeakSensor!.LeakDetected;
102
+ });
118
103
  }
119
104
 
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);
105
+ // Retrieve initial values and updateHomekit
106
+ this.refreshStatus();
130
107
 
131
108
  // Retrieve initial values and updateHomekit
132
109
  this.updateHomeKitCharacteristics();
@@ -139,91 +116,66 @@ export class WaterDetector {
139
116
  });
140
117
 
141
118
  //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
- }
119
+ this.registerWebhook(accessory, device);
179
120
  }
180
121
 
181
- async BLEparseStatus(): Promise<void> {
122
+ async BLEparseStatus(serviceData: serviceData): Promise<void> {
182
123
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
183
-
184
124
  // Battery
185
- this.BatteryLevel = Number(this.BLE_BatteryLevel);
186
- if (this.BatteryLevel < 15) {
187
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
125
+ this.Battery.BatteryLevel = Number(serviceData.battery);
126
+ if (this.Battery.BatteryLevel < 15) {
127
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
188
128
  } else {
189
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
129
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
190
130
  }
191
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
131
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}, StatusLowBattery: ${this.Battery.StatusLowBattery}`);
192
132
 
193
133
  // LeakDetected
194
- this.LeakDetected = this.BLE_LeakDetected!;
195
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakDetected}`);
134
+ if (this.device.waterdetector?.hide_leak) {
135
+ this.LeakSensor!.LeakDetected = serviceData.status!;
136
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakSensor!.LeakDetected}`);
137
+ }
196
138
  }
197
139
 
198
- async openAPIparseStatus(): Promise<void> {
140
+ async openAPIparseStatus(deviceStatus: deviceStatus): Promise<void> {
199
141
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
200
142
  // StatusLowBattery
201
- this.BatteryLevel = Number(this.OpenAPI_BatteryLevel);
202
- if (this.BatteryLevel < 10) {
203
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
143
+ this.Battery.BatteryLevel = Number(deviceStatus.body.battery);
144
+ if (this.Battery.BatteryLevel < 10) {
145
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
204
146
  } else {
205
- this.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
147
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
206
148
  }
207
- this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
149
+ this.debugLog(`${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}, StatusLowBattery: ${this.Battery.StatusLowBattery}`);
208
150
 
209
151
  // BatteryLevel
210
- if (Number.isNaN(this.BatteryLevel)) {
211
- this.BatteryLevel = 100;
152
+ if (Number.isNaN(this.Battery.BatteryLevel)) {
153
+ this.Battery.BatteryLevel = 100;
212
154
  }
213
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
155
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
214
156
 
215
157
  // 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;
158
+ if (!this.device.waterdetector?.hide_leak) {
159
+ this.LeakSensor!.LeakDetected = deviceStatus.body.status!;
160
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakSensor!.LeakDetected}`);
161
+ }
162
+
163
+ // Firmware Version
164
+ const version = deviceStatus.body.version?.toString();
165
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Firmware Version: ${version?.replace(/^V|-.*$/g, '')}`);
166
+ if (deviceStatus.body.version) {
167
+ const deviceVersion = version?.replace(/^V|-.*$/g, '') ?? '0.0.0';
168
+ this.accessory
169
+ .getService(this.hap.Service.AccessoryInformation)!
170
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
171
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
172
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
173
+ .updateValue(deviceVersion);
174
+ this.accessory.context.deviceVersion = deviceVersion;
175
+ this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceVersion: ${this.accessory.context.deviceVersion}`);
176
+ }
222
177
  }
223
178
 
224
- /**
225
- * Asks the SwitchBot API for the latest device information
226
- */
227
179
  async refreshStatus(): Promise<void> {
228
180
  if (!this.device.enableCloudService && this.OpenAPI) {
229
181
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus enableCloudService: ${this.device.enableCloudService}`);
@@ -233,80 +185,76 @@ export class WaterDetector {
233
185
  await this.openAPIRefreshStatus();
234
186
  } else {
235
187
  await this.offlineOff();
236
- this.debugWarnLog(
237
- `${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` +
238
- ` ${this.device.connectionType}, refreshStatus will not happen.`,
239
- );
188
+ this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
189
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
240
190
  }
241
191
  }
242
192
 
243
193
  async BLERefreshStatus(): Promise<void> {
244
194
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
245
- const switchbot = await this.platform.connectBLE();
246
- // Convert to BLE Address
247
- this.device.bleMac = this.device
248
- .deviceId!.match(/.{1,2}/g)!
249
- .join(':')
250
- .toLowerCase();
251
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
252
- this.getCustomBLEAddress(switchbot);
195
+ const switchbot = await this.switchbotBLE();
196
+
197
+ if (switchbot === undefined) {
198
+ await this.BLERefreshConnection(switchbot);
199
+ } else {
253
200
  // Start to monitor advertisement packets
254
- (async () => {
201
+ (async () => {
255
202
  // Start to monitor advertisement packets
256
- await switchbot.startScan({
257
- model: 'l',
258
- id: this.device.bleMac,
259
- });
260
- // Set an event handler
261
- 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') {
265
- 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;
203
+ const serviceData: serviceData = await this.monitorAdvertisementPackets(switchbot);
204
+ // Update HomeKit
205
+ if (serviceData.model !== '' && serviceData.modelName !== '') {
206
+ await this.BLEparseStatus(serviceData);
207
+ await this.updateHomeKitCharacteristics();
268
208
  } else {
269
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
209
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed to get serviceData, serviceData: ${serviceData}`);
210
+ await this.BLERefreshConnection(switchbot);
270
211
  }
271
- };
272
- // Wait 1 seconds
273
- await switchbot.wait(this.scanDuration * 1000);
274
- // Stop to monitor
275
- await switchbot.stopScan();
276
- // Update HomeKit
277
- await this.BLEparseStatus();
278
- await this.updateHomeKitCharacteristics();
279
- })();
212
+ })();
213
+ }
280
214
  }
281
215
 
282
216
  async openAPIRefreshStatus(): Promise<void> {
283
217
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
284
218
  try {
285
- const { body, statusCode } = await request(`${Devices}/${this.device.deviceId}/status`, {
286
- headers: this.platform.generateHeaders(),
287
- });
288
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${statusCode}`);
219
+ const { body, statusCode } = await this.deviceRefreshStatus();
289
220
  const deviceStatus: any = await body.json();
290
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus: ${JSON.stringify(deviceStatus)}`);
291
- this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} deviceStatus statusCode: ${deviceStatus.statusCode}`);
221
+ await this.refreshStatusCodes(statusCode, deviceStatus);
292
222
  if ((statusCode === 200 || statusCode === 100) && (deviceStatus.statusCode === 200 || deviceStatus.statusCode === 100)) {
293
- this.debugErrorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
294
- + `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();
299
- this.updateHomeKitCharacteristics();
223
+ await this.successfulRefreshStatus(statusCode, deviceStatus);
224
+ await this.openAPIparseStatus(deviceStatus);
225
+ await this.updateHomeKitCharacteristics();
300
226
  } else {
301
- this.statusCode(statusCode);
302
- this.statusCode(deviceStatus.statusCode);
227
+ await this.statusCodes(statusCode, deviceStatus);
303
228
  }
304
229
  } catch (e: any) {
305
230
  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
- );
231
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
232
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
233
+ }
234
+ }
235
+
236
+ async registerWebhook(accessory: PlatformAccessory, device: device & devicesConfig) {
237
+ if (device.webhook) {
238
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is listening webhook.`);
239
+ this.platform.webhookEventHandler[device.deviceId] = async (context) => {
240
+ try {
241
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
242
+ const { detectionState, battery } = context;
243
+ const { LeakDetected } = this.LeakSensor ? this.LeakSensor : { LeakDetected: undefined };
244
+ const { BatteryLevel } = this.Battery ? this.Battery : { BatteryLevel: undefined };
245
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} (detectionState, battery) = Webhook: (${detectionState}, ${battery}), `
246
+ + `current: (${LeakDetected}, ${BatteryLevel})`);
247
+ if (!device.waterdetector?.hide_leak) {
248
+ this.LeakSensor!.LeakDetected = detectionState;
249
+ }
250
+ this.Battery.BatteryLevel = battery;
251
+ this.updateHomeKitCharacteristics();
252
+ } catch (e: any) {
253
+ this.errorLog(`${device.deviceType}: ${accessory.displayName} failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
254
+ }
255
+ };
256
+ } else {
257
+ this.debugLog(`${device.deviceType}: ${accessory.displayName} is not listening webhook.`);
310
258
  }
311
259
  }
312
260
 
@@ -317,129 +265,54 @@ export class WaterDetector {
317
265
  const mqttmessage: string[] = [];
318
266
  const entry = { time: Math.round(new Date().valueOf() / 1000) };
319
267
  if (!this.device.waterdetector?.hide_leak) {
320
- if (this.LeakDetected === undefined) {
321
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakDetected}`);
268
+ if (this.LeakSensor!.LeakDetected === undefined) {
269
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LeakDetected: ${this.LeakSensor!.LeakDetected}`);
322
270
  } else {
323
271
  if (this.device.mqttURL) {
324
- mqttmessage.push(`"LeakDetected": ${this.LeakDetected}`);
272
+ mqttmessage.push(`"LeakDetected": ${this.LeakSensor!.LeakDetected}`);
325
273
  }
326
274
  if (this.device.history) {
327
- entry['leak'] = this.LeakDetected;
275
+ entry['leak'] = this.LeakSensor!.LeakDetected;
328
276
  }
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}`);
277
+ this.accessory.context.LeakDetected = this.LeakSensor!.LeakDetected;
278
+ this.LeakSensor!.Service.updateCharacteristic(this.hap.Characteristic.LeakDetected, this.LeakSensor!.LeakDetected);
279
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic LeakDetected: ${this.LeakSensor!.LeakDetected}`);
332
280
  }
333
281
  }
334
- if (this.BatteryLevel === undefined) {
335
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
282
+ if (this.Battery.BatteryLevel === undefined) {
283
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.Battery.BatteryLevel}`);
336
284
  } else {
337
285
  if (this.device.mqttURL) {
338
- mqttmessage.push(`"battery": ${this.BatteryLevel}`);
286
+ mqttmessage.push(`"battery": ${this.Battery.BatteryLevel}`);
339
287
  }
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}`);
288
+ this.accessory.context.BatteryLevel = this.Battery.BatteryLevel;
289
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel);
290
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.Battery.BatteryLevel}`);
343
291
  }
344
- if (this.StatusLowBattery === undefined) {
345
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
292
+ if (this.Battery.StatusLowBattery === undefined) {
293
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.Battery.StatusLowBattery}`);
346
294
  } else {
347
295
  if (this.device.mqttURL) {
348
- mqttmessage.push(`"lowBattery": ${this.StatusLowBattery}`);
296
+ mqttmessage.push(`"lowBattery": ${this.Battery.StatusLowBattery}`);
349
297
  }
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}`);
298
+ this.accessory.context.StatusLowBattery = this.Battery.StatusLowBattery;
299
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery);
300
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
301
+ + ` StatusLowBattery: ${this.Battery.StatusLowBattery}`);
353
302
  }
354
303
  if (this.device.mqttURL) {
355
304
  this.mqttPublish(`{${mqttmessage.join(',')}}`);
356
305
  }
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}`);
306
+ if (!this.device.waterdetector?.hide_leak) {
307
+ if (Number(this.LeakSensor!.LeakDetected) > 0) {
308
+ // reject unreliable data
309
+ if (this.device.history) {
310
+ this.historyService?.addEntry(entry);
311
+ }
394
312
  }
395
313
  }
396
314
  }
397
315
 
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
316
  async BLERefreshConnection(switchbot: any): Promise<void> {
444
317
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot:`
445
318
  + ` ${JSON.stringify(switchbot)}`);
@@ -449,241 +322,17 @@ export class WaterDetector {
449
322
  }
450
323
  }
451
324
 
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
325
  async offlineOff(): Promise<void> {
545
- if (this.device.offline) {
546
- await this.deviceContext();
547
- await this.updateHomeKitCharacteristics();
326
+ if (this.device.offline && !this.device.waterdetector?.hide_leak) {
327
+ this.LeakSensor!.Service.updateCharacteristic(this.hap.Characteristic.LeakDetected, this.hap.Characteristic.LeakDetected.LEAK_NOT_DETECTED);
548
328
  }
549
329
  }
550
330
 
551
331
  async apiError(e: any): Promise<void> {
552
332
  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;
333
+ this.LeakSensor!.Service.updateCharacteristic(this.hap.Characteristic.LeakDetected, e);
599
334
  }
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';
335
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e);
336
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e);
688
337
  }
689
338
  }