@switchbot/homebridge-switchbot 2.0.0-beta.19 → 2.0.0-beta.20
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/CHANGELOG.md +6 -1
- package/README.md +1 -2
- package/config.schema.json +51 -32
- package/dist/device/bot.d.ts +32 -29
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +549 -575
- package/dist/device/bot.js.map +1 -1
- package/dist/device/colorbulb.d.ts +33 -15
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +426 -341
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +16 -9
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +246 -208
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +21 -18
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +449 -449
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/humidifier.d.ts +22 -20
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +346 -324
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/lock.d.ts +22 -10
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +257 -178
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +21 -14
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +287 -239
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +23 -10
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +308 -190
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +17 -10
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +225 -193
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +24 -17
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +270 -267
- package/dist/device/plug.js.map +1 -1
- package/dist/device/striplight.d.ts +36 -14
- package/dist/device/striplight.d.ts.map +1 -1
- package/dist/device/striplight.js +447 -299
- package/dist/device/striplight.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +7 -14
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +177 -169
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +3 -5
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +72 -57
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +3 -4
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +47 -33
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +3 -4
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +66 -48
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/light.d.ts +3 -4
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +48 -47
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +3 -4
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +47 -33
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +10 -11
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +64 -48
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +7 -12
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +52 -41
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +6 -11
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +52 -42
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +0 -4
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +44 -66
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +3 -3
- package/dist/settings.d.ts.map +1 -1
- package/package.json +7 -6
- package/src/device/bot.ts +551 -589
- package/src/device/colorbulb.ts +441 -375
- package/src/device/contact.ts +249 -213
- package/src/device/curtain.ts +452 -461
- package/src/device/humidifier.ts +358 -365
- package/src/device/lock.ts +263 -179
- package/src/device/meter.ts +302 -253
- package/src/device/meterplus.ts +319 -194
- package/src/device/motion.ts +230 -199
- package/src/device/plug.ts +273 -274
- package/src/device/striplight.ts +460 -316
- package/src/irdevice/airconditioner.ts +181 -183
- package/src/irdevice/airpurifier.ts +70 -60
- package/src/irdevice/camera.ts +46 -36
- package/src/irdevice/fan.ts +64 -49
- package/src/irdevice/light.ts +47 -51
- package/src/irdevice/other.ts +46 -36
- package/src/irdevice/tv.ts +64 -51
- package/src/irdevice/vacuumcleaner.ts +52 -45
- package/src/irdevice/waterheater.ts +50 -45
- package/src/platform.ts +44 -68
- package/src/settings.ts +3 -3
package/src/device/plug.ts
CHANGED
|
@@ -35,7 +35,6 @@ export class Plug {
|
|
|
35
35
|
currentPower: serviceData['currentPower'];
|
|
36
36
|
|
|
37
37
|
// Config
|
|
38
|
-
OpenAPI?: boolean;
|
|
39
38
|
scanDuration!: number;
|
|
40
39
|
deviceLogging!: string;
|
|
41
40
|
deviceRefreshRate!: number;
|
|
@@ -44,17 +43,17 @@ export class Plug {
|
|
|
44
43
|
plugUpdateInProgress!: boolean;
|
|
45
44
|
doPlugUpdate!: Subject<void>;
|
|
46
45
|
|
|
46
|
+
// Connection
|
|
47
|
+
private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'Both');
|
|
48
|
+
private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'Both');
|
|
49
|
+
|
|
47
50
|
constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
|
|
48
51
|
// default placeholders
|
|
49
52
|
this.logs(device);
|
|
50
53
|
this.scan(device);
|
|
51
54
|
this.refreshRate(device);
|
|
52
55
|
this.config(device);
|
|
53
|
-
|
|
54
|
-
this.On = false;
|
|
55
|
-
} else {
|
|
56
|
-
this.On = this.accessory.context.On;
|
|
57
|
-
}
|
|
56
|
+
this.context();
|
|
58
57
|
|
|
59
58
|
// this is subject we use to track when we need to POST changes to the SwitchBot API
|
|
60
59
|
this.doPlugUpdate = new Subject();
|
|
@@ -90,7 +89,7 @@ export class Plug {
|
|
|
90
89
|
// see https://developers.homebridge.io/#/service/Outlet
|
|
91
90
|
|
|
92
91
|
// create handlers for required characteristics
|
|
93
|
-
this.outletService.getCharacteristic(this.platform.Characteristic.On).onSet(this.
|
|
92
|
+
this.outletService.getCharacteristic(this.platform.Characteristic.On).onSet(this.OnSet.bind(this));
|
|
94
93
|
|
|
95
94
|
// Update Homekit
|
|
96
95
|
this.updateHomeKitCharacteristics();
|
|
@@ -115,27 +114,31 @@ export class Plug {
|
|
|
115
114
|
try {
|
|
116
115
|
await this.pushChanges();
|
|
117
116
|
} catch (e: any) {
|
|
118
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges`);
|
|
119
|
-
if (this.deviceLogging.includes('debug')) {
|
|
120
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges,`
|
|
121
|
-
+ ` Error Message: ${superStringify(e.message)}`);
|
|
122
|
-
}
|
|
123
117
|
this.apiError(e);
|
|
118
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
|
|
119
|
+
+ ` Error Message: ${superStringify(e.message)}`);
|
|
124
120
|
}
|
|
125
121
|
this.plugUpdateInProgress = false;
|
|
126
122
|
});
|
|
127
123
|
}
|
|
128
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Parse the device status from the SwitchBot api
|
|
127
|
+
*/
|
|
129
128
|
async parseStatus(): Promise<void> {
|
|
130
|
-
if (this.
|
|
129
|
+
if (this.BLE && !this.SwitchToOpenAPI) {
|
|
130
|
+
await this.BLEparseStatus();
|
|
131
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
132
|
+
this.SwitchToOpenAPI = false;
|
|
131
133
|
await this.openAPIparseStatus();
|
|
132
134
|
} else {
|
|
133
|
-
|
|
135
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
136
|
+
+ ` ${this.device.connectionType}, parseStatus will not happen.`);
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
139
|
|
|
137
140
|
async BLEparseStatus(): Promise<void> {
|
|
138
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}
|
|
141
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
|
|
139
142
|
// State
|
|
140
143
|
switch (this.state) {
|
|
141
144
|
case 'on':
|
|
@@ -148,6 +151,7 @@ export class Plug {
|
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
async openAPIparseStatus() {
|
|
154
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
|
|
151
155
|
switch (this.power) {
|
|
152
156
|
case 'on':
|
|
153
157
|
this.On = true;
|
|
@@ -158,16 +162,22 @@ export class Plug {
|
|
|
158
162
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
159
163
|
}
|
|
160
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Asks the SwitchBot API for the latest device information
|
|
167
|
+
*/
|
|
161
168
|
async refreshStatus(): Promise<void> {
|
|
162
|
-
if (this.
|
|
169
|
+
if (this.BLE) {
|
|
163
170
|
await this.BLERefreshStatus();
|
|
164
|
-
} else {
|
|
171
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
165
172
|
await this.openAPIRefreshStatus();
|
|
173
|
+
} else {
|
|
174
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
175
|
+
+ ` ${this.device.connectionType}, refreshStatus will not happen.`);
|
|
166
176
|
}
|
|
167
177
|
}
|
|
168
178
|
|
|
169
179
|
async BLERefreshStatus(): Promise<void> {
|
|
170
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}
|
|
180
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
|
|
171
181
|
const switchbot = await this.platform.connectBLE();
|
|
172
182
|
// Convert to BLE Address
|
|
173
183
|
this.device.bleMac = this.device
|
|
@@ -230,117 +240,66 @@ export class Plug {
|
|
|
230
240
|
}
|
|
231
241
|
})
|
|
232
242
|
.catch(async (e: any) => {
|
|
233
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
|
|
234
|
-
if (this.deviceLogging.includes('debug')) {
|
|
235
|
-
this.errorLog(
|
|
236
|
-
`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
|
|
237
|
-
+ ` Error Message: ${superStringify(e.message)}`,
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
if (this.platform.config.credentials?.token) {
|
|
241
|
-
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
242
|
-
this.SwitchToOpenAPI = true;
|
|
243
|
-
await this.openAPIRefreshStatus();
|
|
244
|
-
}
|
|
245
243
|
this.apiError(e);
|
|
244
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
|
|
245
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
246
|
+
await this.BLEconnection(switchbot);
|
|
246
247
|
});
|
|
247
248
|
} else {
|
|
248
249
|
await this.BLEconnection(switchbot);
|
|
249
250
|
}
|
|
250
251
|
}
|
|
251
252
|
|
|
252
|
-
BLEmodel(): 'g' | 'j' {
|
|
253
|
-
if (this.device.deviceType === 'Plug Mini (US)') {
|
|
254
|
-
return 'g';
|
|
255
|
-
} else {
|
|
256
|
-
return 'j';
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
async getCustomBLEAddress(switchbot: any) {
|
|
261
|
-
if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
|
|
262
|
-
(async () => {
|
|
263
|
-
// Start to monitor advertisement packets
|
|
264
|
-
await switchbot.startScan({
|
|
265
|
-
model: this.BLEmodel(),
|
|
266
|
-
});
|
|
267
|
-
// Set an event handler
|
|
268
|
-
switchbot.onadvertisement = (ad: any) => {
|
|
269
|
-
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
|
|
270
|
-
};
|
|
271
|
-
await switchbot.wait(10000);
|
|
272
|
-
// Stop to monitor
|
|
273
|
-
switchbot.stopScan();
|
|
274
|
-
})();
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
async BLEconnection(switchbot: any): Promise<void> {
|
|
279
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
|
|
280
|
-
if (this.platform.config.credentials?.token) {
|
|
281
|
-
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
282
|
-
this.SwitchToOpenAPI = true;
|
|
283
|
-
await this.openAPIRefreshStatus();
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
253
|
async openAPIRefreshStatus() {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
});
|
|
316
|
-
res.on('end', () => {
|
|
317
|
-
try {
|
|
318
|
-
this.deviceStatus = JSON.parse(rawData);
|
|
319
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
|
|
320
|
-
this.power = this.deviceStatus.body.power;
|
|
321
|
-
this.parseStatus();
|
|
322
|
-
this.updateHomeKitCharacteristics();
|
|
323
|
-
} catch (e: any) {
|
|
324
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
325
|
-
}
|
|
326
|
-
});
|
|
254
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
|
|
255
|
+
try {
|
|
256
|
+
const t = Date.now();
|
|
257
|
+
const nonce = 'requestID';
|
|
258
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
259
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
260
|
+
const sign = signTerm.toString('base64');
|
|
261
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
262
|
+
const options = {
|
|
263
|
+
hostname: HostDomain,
|
|
264
|
+
port: 443,
|
|
265
|
+
path: `${DevicePath}/${this.device.deviceId}/status`,
|
|
266
|
+
method: 'GET',
|
|
267
|
+
headers: {
|
|
268
|
+
Authorization: this.platform.config.credentials?.token,
|
|
269
|
+
sign: sign,
|
|
270
|
+
nonce: nonce,
|
|
271
|
+
t: t,
|
|
272
|
+
'Content-Type': 'application/json',
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
const req = https.request(options, (res) => {
|
|
276
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
|
|
277
|
+
this.statusCode({ res });
|
|
278
|
+
let rawData = '';
|
|
279
|
+
res.on('data', (d) => {
|
|
280
|
+
rawData += d;
|
|
281
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
327
282
|
});
|
|
328
|
-
|
|
329
|
-
|
|
283
|
+
res.on('end', () => {
|
|
284
|
+
try {
|
|
285
|
+
this.deviceStatus = JSON.parse(rawData);
|
|
286
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${superStringify(this.deviceStatus)}`);
|
|
287
|
+
this.power = this.deviceStatus.body.power;
|
|
288
|
+
this.parseStatus();
|
|
289
|
+
this.updateHomeKitCharacteristics();
|
|
290
|
+
} catch (e: any) {
|
|
291
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
292
|
+
}
|
|
330
293
|
});
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
this.apiError(e);
|
|
341
|
-
}
|
|
342
|
-
} else {
|
|
343
|
-
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, commands will not be sent.`);
|
|
294
|
+
});
|
|
295
|
+
req.on('error', (e: any) => {
|
|
296
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
297
|
+
});
|
|
298
|
+
req.end();
|
|
299
|
+
} catch (e: any) {
|
|
300
|
+
this.apiError(e);
|
|
301
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
|
|
302
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
344
303
|
}
|
|
345
304
|
}
|
|
346
305
|
|
|
@@ -355,74 +314,67 @@ export class Plug {
|
|
|
355
314
|
*/
|
|
356
315
|
|
|
357
316
|
async pushChanges(): Promise<void> {
|
|
358
|
-
if (this.
|
|
317
|
+
if (this.BLE) {
|
|
359
318
|
await this.BLEpushChanges();
|
|
360
|
-
} else {
|
|
319
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
361
320
|
await this.openAPIpushChanges();
|
|
321
|
+
} else {
|
|
322
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
323
|
+
+ ` ${this.device.connectionType}, pushChanges will not happen.`);
|
|
362
324
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE pushChanges`);
|
|
368
|
-
const switchbot = await this.platform.connectBLE();
|
|
369
|
-
// Convert to BLE Address
|
|
370
|
-
this.device.bleMac = this.device
|
|
371
|
-
.deviceId!.match(/.{1,2}/g)!
|
|
372
|
-
.join(':')
|
|
373
|
-
.toLowerCase();
|
|
374
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
|
|
375
|
-
switchbot
|
|
376
|
-
.discover({
|
|
377
|
-
model: this.BLEmodel(),
|
|
378
|
-
id: this.device.bleMac,
|
|
379
|
-
})
|
|
380
|
-
.then((device_list: any) => {
|
|
381
|
-
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
382
|
-
return this.turnOnOff(device_list);
|
|
383
|
-
})
|
|
384
|
-
.then(() => {
|
|
385
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
|
|
386
|
-
this.On = false;
|
|
387
|
-
})
|
|
388
|
-
.catch(async (e: any) => {
|
|
389
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
|
|
390
|
-
if (this.deviceLogging.includes('debug')) {
|
|
391
|
-
this.errorLog(
|
|
392
|
-
`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
|
|
393
|
-
+ ` Error Message: ${superStringify(e.message)}`,
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
if (this.platform.debugMode) {
|
|
397
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
|
|
398
|
-
+ ` Error: ${superStringify(e)}`);
|
|
399
|
-
}
|
|
400
|
-
if (this.platform.config.credentials?.token) {
|
|
401
|
-
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
402
|
-
await this.openAPIpushChanges();
|
|
403
|
-
}
|
|
404
|
-
this.apiError(e);
|
|
325
|
+
interval(5000)
|
|
326
|
+
.pipe(take(1))
|
|
327
|
+
.subscribe(async () => {
|
|
328
|
+
await this.refreshStatus();
|
|
405
329
|
});
|
|
406
330
|
}
|
|
407
331
|
|
|
408
|
-
async
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
332
|
+
async BLEpushChanges(): Promise<void> {
|
|
333
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
|
|
334
|
+
if (this.On !== this.accessory.context.On) {
|
|
335
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
|
|
336
|
+
const switchbot = await this.platform.connectBLE();
|
|
337
|
+
// Convert to BLE Address
|
|
338
|
+
this.device.bleMac = this.device
|
|
339
|
+
.deviceId!.match(/.{1,2}/g)!
|
|
340
|
+
.join(':')
|
|
341
|
+
.toLowerCase();
|
|
342
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
|
|
343
|
+
switchbot
|
|
344
|
+
.discover({
|
|
345
|
+
model: this.BLEmodel(),
|
|
346
|
+
id: this.device.bleMac,
|
|
347
|
+
})
|
|
348
|
+
.then((device_list: any) => {
|
|
349
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
350
|
+
return this.turnOnOff(device_list);
|
|
351
|
+
})
|
|
352
|
+
.then(() => {
|
|
353
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
|
|
354
|
+
this.On = false;
|
|
355
|
+
})
|
|
356
|
+
.catch(async (e: any) => {
|
|
357
|
+
this.apiError(e);
|
|
358
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
|
|
359
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
360
|
+
if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
|
|
361
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
362
|
+
await this.openAPIpushChanges();
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
} else {
|
|
366
|
+
this.debugLog(
|
|
367
|
+
`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, `
|
|
368
|
+
+`OnCached: ${this.accessory.context.On}`,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
419
371
|
}
|
|
420
372
|
|
|
421
373
|
async openAPIpushChanges() {
|
|
422
|
-
|
|
374
|
+
try {
|
|
423
375
|
if (this.On !== this.accessory.context.On) {
|
|
424
376
|
// Make Push On request to the API
|
|
425
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}
|
|
377
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
|
|
426
378
|
const t = Date.now();
|
|
427
379
|
const nonce = 'requestID';
|
|
428
380
|
const data = this.platform.config.credentials?.token + t + nonce;
|
|
@@ -459,7 +411,7 @@ export class Plug {
|
|
|
459
411
|
},
|
|
460
412
|
};
|
|
461
413
|
const req = https.request(options, res => {
|
|
462
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
414
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
|
|
463
415
|
this.statusCode({ res });
|
|
464
416
|
res.on('data', d => {
|
|
465
417
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
@@ -471,17 +423,30 @@ export class Plug {
|
|
|
471
423
|
req.write(body);
|
|
472
424
|
req.end();
|
|
473
425
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${superStringify(req)}`);
|
|
426
|
+
} else {
|
|
427
|
+
this.debugLog(
|
|
428
|
+
`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, `
|
|
429
|
+
+`OnCached: ${this.accessory.context.On}`,
|
|
430
|
+
);
|
|
474
431
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
} else {
|
|
481
|
-
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, commands will not be sent.`);
|
|
432
|
+
} catch (e: any) {
|
|
433
|
+
this.apiError(e);
|
|
434
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
|
|
435
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`,
|
|
436
|
+
);
|
|
482
437
|
}
|
|
483
438
|
}
|
|
484
439
|
|
|
440
|
+
/**
|
|
441
|
+
* Handle requests to set the value of the "On" characteristic
|
|
442
|
+
*/
|
|
443
|
+
async OnSet(value: CharacteristicValue): Promise<void> {
|
|
444
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
|
|
445
|
+
|
|
446
|
+
this.On = value;
|
|
447
|
+
this.doPlugUpdate.next();
|
|
448
|
+
}
|
|
449
|
+
|
|
485
450
|
async updateHomeKitCharacteristics(): Promise<void> {
|
|
486
451
|
if (this.On === undefined) {
|
|
487
452
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
@@ -492,9 +457,100 @@ export class Plug {
|
|
|
492
457
|
}
|
|
493
458
|
}
|
|
494
459
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
460
|
+
BLEmodel(): 'g' | 'j' {
|
|
461
|
+
if (this.device.deviceType === 'Plug Mini (US)') {
|
|
462
|
+
return 'g';
|
|
463
|
+
} else {
|
|
464
|
+
return 'j';
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async getCustomBLEAddress(switchbot: any) {
|
|
469
|
+
if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
|
|
470
|
+
(async () => {
|
|
471
|
+
// Start to monitor advertisement packets
|
|
472
|
+
await switchbot.startScan({
|
|
473
|
+
model: this.BLEmodel(),
|
|
474
|
+
});
|
|
475
|
+
// Set an event handler
|
|
476
|
+
switchbot.onadvertisement = (ad: any) => {
|
|
477
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
|
|
478
|
+
};
|
|
479
|
+
await switchbot.wait(10000);
|
|
480
|
+
// Stop to monitor
|
|
481
|
+
switchbot.stopScan();
|
|
482
|
+
})();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
async BLEconnection(switchbot: any): Promise<void> {
|
|
487
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
|
|
488
|
+
if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
|
|
489
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
490
|
+
this.SwitchToOpenAPI = true;
|
|
491
|
+
await this.openAPIRefreshStatus();
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
async turnOnOff(device_list: any): Promise<any> {
|
|
496
|
+
return await this.retry({
|
|
497
|
+
max: await this.maxRetry(),
|
|
498
|
+
fn: () => {
|
|
499
|
+
if (this.On) {
|
|
500
|
+
return device_list[0].turnOn({ id: this.device.bleMac });
|
|
501
|
+
} else {
|
|
502
|
+
return device_list[0].turnOff({ id: this.device.bleMac });
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
|
|
509
|
+
return fn().catch(async (err: any) => {
|
|
510
|
+
if (max === 0) {
|
|
511
|
+
throw err;
|
|
512
|
+
}
|
|
513
|
+
this.infoLog(err);
|
|
514
|
+
this.infoLog('Retrying');
|
|
515
|
+
await this.switchbot.wait(1000);
|
|
516
|
+
return this.retry({ max: max - 1, fn });
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
async maxRetry(): Promise<number> {
|
|
521
|
+
let maxRetry: number;
|
|
522
|
+
if (this.device.bot?.maxRetry) {
|
|
523
|
+
maxRetry = this.device.bot?.maxRetry;
|
|
524
|
+
} else {
|
|
525
|
+
maxRetry = 5;
|
|
526
|
+
}
|
|
527
|
+
return maxRetry;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
model(device: device & devicesConfig): string {
|
|
531
|
+
let model: string;
|
|
532
|
+
if (device.deviceType === 'Plug Mini (US)') {
|
|
533
|
+
model = 'W1901400';
|
|
534
|
+
} else if (device.deviceType === 'Plug Mini (JP)') {
|
|
535
|
+
model = 'W2001400';
|
|
536
|
+
} else {
|
|
537
|
+
model = 'SP11';
|
|
538
|
+
}
|
|
539
|
+
return model;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
async scan(device: device & devicesConfig): Promise<void> {
|
|
543
|
+
if (device.scanDuration) {
|
|
544
|
+
this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
|
|
545
|
+
if (this.BLE) {
|
|
546
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
|
|
547
|
+
}
|
|
548
|
+
} else {
|
|
549
|
+
this.scanDuration = this.accessory.context.scanDuration = 1;
|
|
550
|
+
if (this.BLE) {
|
|
551
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
498
554
|
}
|
|
499
555
|
|
|
500
556
|
async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
|
|
@@ -534,51 +590,46 @@ export class Plug {
|
|
|
534
590
|
if (this.device.offline) {
|
|
535
591
|
this.On = false;
|
|
536
592
|
this.outletService.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
|
|
593
|
+
await this.updateHomeKitCharacteristics();
|
|
537
594
|
}
|
|
538
595
|
}
|
|
539
596
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
*/
|
|
543
|
-
async handleOnSet(value: CharacteristicValue): Promise<void> {
|
|
544
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} - Set On: ${value}`);
|
|
545
|
-
|
|
546
|
-
this.On = value;
|
|
547
|
-
this.doPlugUpdate.next();
|
|
597
|
+
async apiError(e: any): Promise<void> {
|
|
598
|
+
this.outletService.updateCharacteristic(this.platform.Characteristic.On, e);
|
|
548
599
|
}
|
|
549
600
|
|
|
550
|
-
|
|
551
|
-
let
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
601
|
+
FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
|
|
602
|
+
let FirmwareRevision: string;
|
|
603
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
|
|
604
|
+
+` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
|
|
605
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
|
|
606
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
|
|
607
|
+
if (accessory.context.FirmwareRevision) {
|
|
608
|
+
FirmwareRevision = accessory.context.FirmwareRevision;
|
|
609
|
+
} else if (device.firmware) {
|
|
610
|
+
FirmwareRevision = device.firmware;
|
|
556
611
|
} else {
|
|
557
|
-
|
|
612
|
+
FirmwareRevision = this.platform.version;
|
|
558
613
|
}
|
|
559
|
-
return
|
|
614
|
+
return FirmwareRevision;
|
|
560
615
|
}
|
|
561
616
|
|
|
562
|
-
async
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
this.infoLog('Retrying');
|
|
569
|
-
await this.switchbot.wait(1000);
|
|
570
|
-
return this.retry({ max: max - 1, fn });
|
|
571
|
-
});
|
|
617
|
+
async context() {
|
|
618
|
+
if (this.On === undefined) {
|
|
619
|
+
this.On = false;
|
|
620
|
+
} else {
|
|
621
|
+
this.On = this.accessory.context.On;
|
|
622
|
+
}
|
|
572
623
|
}
|
|
573
624
|
|
|
574
|
-
async
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
} else {
|
|
579
|
-
|
|
625
|
+
async refreshRate(device: device & devicesConfig): Promise<void> {
|
|
626
|
+
if (device.refreshRate) {
|
|
627
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
|
|
628
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
|
|
629
|
+
} else if (this.platform.config.options!.refreshRate) {
|
|
630
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
631
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
580
632
|
}
|
|
581
|
-
return maxRetry;
|
|
582
633
|
}
|
|
583
634
|
|
|
584
635
|
async config(device: device & devicesConfig): Promise<void> {
|
|
@@ -586,11 +637,8 @@ export class Plug {
|
|
|
586
637
|
if (device.plug) {
|
|
587
638
|
config = device.plug;
|
|
588
639
|
}
|
|
589
|
-
if (device.
|
|
590
|
-
config['
|
|
591
|
-
}
|
|
592
|
-
if (device.openAPI !== undefined) {
|
|
593
|
-
config['openAPI'] = device.openAPI;
|
|
640
|
+
if (device.connectionType !== undefined) {
|
|
641
|
+
config['connectionType'] = device.connectionType;
|
|
594
642
|
}
|
|
595
643
|
if (device.logging !== undefined) {
|
|
596
644
|
config['logging'] = device.logging;
|
|
@@ -609,39 +657,6 @@ export class Plug {
|
|
|
609
657
|
}
|
|
610
658
|
}
|
|
611
659
|
|
|
612
|
-
async refreshRate(device: device & devicesConfig): Promise<void> {
|
|
613
|
-
if (device.refreshRate) {
|
|
614
|
-
this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
|
|
615
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
|
|
616
|
-
} else if (this.platform.config.options!.refreshRate) {
|
|
617
|
-
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
618
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
async openAPI() {
|
|
623
|
-
if (!this.device.openAPI) {
|
|
624
|
-
this.OpenAPI = true;
|
|
625
|
-
} else {
|
|
626
|
-
this.OpenAPI = this.device.openAPI;
|
|
627
|
-
}
|
|
628
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI: ${this.OpenAPI}`);
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
async scan(device: device & devicesConfig): Promise<void> {
|
|
632
|
-
if (device.scanDuration) {
|
|
633
|
-
this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
|
|
634
|
-
if (device.ble) {
|
|
635
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
|
|
636
|
-
}
|
|
637
|
-
} else {
|
|
638
|
-
this.scanDuration = this.accessory.context.scanDuration = 1;
|
|
639
|
-
if (this.device.ble) {
|
|
640
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
660
|
async logs(device: device & devicesConfig): Promise<void> {
|
|
646
661
|
if (this.platform.debugMode) {
|
|
647
662
|
this.deviceLogging = this.accessory.context.logging = 'debugMode';
|
|
@@ -658,22 +673,6 @@ export class Plug {
|
|
|
658
673
|
}
|
|
659
674
|
}
|
|
660
675
|
|
|
661
|
-
FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
|
|
662
|
-
let FirmwareRevision: string;
|
|
663
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
|
|
664
|
-
+` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
|
|
665
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
|
|
666
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
|
|
667
|
-
if (accessory.context.FirmwareRevision) {
|
|
668
|
-
FirmwareRevision = accessory.context.FirmwareRevision;
|
|
669
|
-
} else if (device.firmware) {
|
|
670
|
-
FirmwareRevision = device.firmware;
|
|
671
|
-
} else {
|
|
672
|
-
FirmwareRevision = this.platform.version;
|
|
673
|
-
}
|
|
674
|
-
return FirmwareRevision;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
676
|
/**
|
|
678
677
|
* Logging for Device
|
|
679
678
|
*/
|