@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.
- package/.vscode/settings.json +4 -1
- package/CHANGELOG.md +4 -1
- package/config.schema.json +170 -26
- package/dist/device/blindtilt.d.ts +21 -96
- package/dist/device/blindtilt.d.ts.map +1 -1
- package/dist/device/blindtilt.js +439 -817
- package/dist/device/blindtilt.js.map +1 -1
- package/dist/device/bot.d.ts +27 -72
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +835 -865
- package/dist/device/bot.js.map +1 -1
- package/dist/device/ceilinglight.d.ts +15 -69
- package/dist/device/ceilinglight.d.ts.map +1 -1
- package/dist/device/ceilinglight.js +287 -653
- package/dist/device/ceilinglight.js.map +1 -1
- package/dist/device/colorbulb.d.ts +15 -76
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +354 -732
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +14 -66
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +268 -576
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +18 -89
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +431 -851
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/device.d.ts +60 -0
- package/dist/device/device.d.ts.map +1 -0
- package/dist/device/device.js +739 -0
- package/dist/device/device.js.map +1 -0
- package/dist/device/fan.d.ts +63 -0
- package/dist/device/fan.d.ts.map +1 -0
- package/dist/device/fan.js +698 -0
- package/dist/device/fan.js.map +1 -0
- package/dist/device/hub.d.ts +15 -60
- package/dist/device/hub.d.ts.map +1 -1
- package/dist/device/hub.js +257 -631
- package/dist/device/hub.js.map +1 -1
- package/dist/device/humidifier.d.ts +11 -66
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +266 -629
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/iosensor.d.ts +12 -64
- package/dist/device/iosensor.d.ts.map +1 -1
- package/dist/device/iosensor.js +215 -615
- package/dist/device/iosensor.js.map +1 -1
- package/dist/device/lightstrip.d.ts +12 -70
- package/dist/device/lightstrip.d.ts.map +1 -1
- package/dist/device/lightstrip.js +336 -645
- package/dist/device/lightstrip.js.map +1 -1
- package/dist/device/lock.d.ts +17 -63
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +290 -595
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +15 -64
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +211 -608
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +15 -65
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +205 -615
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +12 -69
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +202 -563
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +10 -57
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +125 -484
- package/dist/device/plug.js.map +1 -1
- package/dist/device/robotvacuumcleaner.d.ts +13 -63
- package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
- package/dist/device/robotvacuumcleaner.js +233 -549
- package/dist/device/robotvacuumcleaner.js.map +1 -1
- package/dist/device/waterdetector.d.ts +11 -63
- package/dist/device/waterdetector.d.ts.map +1 -1
- package/dist/device/waterdetector.js +170 -493
- package/dist/device/waterdetector.js.map +1 -1
- package/dist/homebridge-ui/public/index.html +22 -16
- package/dist/homebridge-ui/server.js +1 -1
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +10 -50
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +340 -468
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +8 -39
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +105 -319
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +7 -36
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +44 -285
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +7 -43
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +92 -350
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/irdevice.d.ts +40 -0
- package/dist/irdevice/irdevice.d.ts.map +1 -0
- package/dist/irdevice/irdevice.js +369 -0
- package/dist/irdevice/irdevice.js.map +1 -0
- package/dist/irdevice/light.d.ts +12 -45
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +118 -362
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +19 -48
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +438 -570
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +8 -40
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +91 -339
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +7 -36
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +45 -285
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +7 -36
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +47 -291
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +22 -8
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +342 -191
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +64 -17
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +16 -552
- package/dist/settings.js.map +1 -1
- package/dist/utils.d.ts +77 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +638 -1
- package/dist/utils.js.map +1 -1
- package/eslint.config.js +96 -0
- package/package.json +20 -16
- package/src/custom.d.ts +2 -1
- package/src/device/blindtilt.ts +472 -888
- package/src/device/bot.ts +893 -968
- package/src/device/ceilinglight.ts +304 -709
- package/src/device/colorbulb.ts +370 -803
- package/src/device/contact.ts +301 -611
- package/src/device/curtain.ts +460 -908
- package/src/device/device.ts +755 -0
- package/src/device/fan.ts +749 -0
- package/src/device/hub.ts +294 -664
- package/src/device/humidifier.ts +299 -696
- package/src/device/iosensor.ts +251 -644
- package/src/device/lightstrip.ts +362 -712
- package/src/device/lock.ts +328 -653
- package/src/device/meter.ts +247 -637
- package/src/device/meterplus.ts +240 -644
- package/src/device/motion.ts +230 -598
- package/src/device/plug.ts +139 -525
- package/src/device/robotvacuumcleaner.ts +258 -593
- package/src/device/waterdetector.ts +191 -522
- package/src/homebridge-ui/public/index.html +22 -16
- package/src/homebridge-ui/server.ts +1 -1
- package/src/index.ts +4 -3
- package/src/irdevice/airconditioner.ts +370 -527
- package/src/irdevice/airpurifier.ts +132 -356
- package/src/irdevice/camera.ts +58 -311
- package/src/irdevice/fan.ts +109 -379
- package/src/irdevice/irdevice.ts +382 -0
- package/src/irdevice/light.ts +157 -412
- package/src/irdevice/other.ts +507 -648
- package/src/irdevice/tv.ts +121 -375
- package/src/irdevice/vacuumcleaner.ts +59 -311
- package/src/irdevice/waterheater.ts +61 -320
- package/src/platform.ts +395 -259
- package/src/settings.ts +118 -609
- package/src/utils.ts +642 -1
- package/.github/npm-version-script.cjs +0 -81
- package/src/device/waterdetector.json +0 -11
|
@@ -1,132 +1,110 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import
|
|
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
|
-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
41
|
+
readonly platform: SwitchBotPlatform,
|
|
42
|
+
accessory: PlatformAccessory,
|
|
43
|
+
device: device & devicesConfig,
|
|
69
44
|
) {
|
|
70
|
-
|
|
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
|
-
//
|
|
91
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
.
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
121
|
-
|
|
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
|
-
|
|
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(
|
|
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.
|
|
195
|
-
|
|
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(
|
|
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.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
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
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
|
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
|
|
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.
|
|
241
|
+
this.debugSuccessLog(`${this.device.deviceType}: ${this.accessory.displayName} `
|
|
294
242
|
+ `statusCode: ${statusCode} & deviceStatus StatusCode: ${deviceStatus.statusCode}`);
|
|
295
|
-
this.
|
|
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
|
-
|
|
308
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
352
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic
|
|
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 (
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
this.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
601
|
-
|
|
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
|
}
|