@switchbot/homebridge-switchbot 2.0.0-beta.2 → 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 +8 -1
- package/README.md +1 -2
- package/config.schema.json +75 -20
- package/dist/device/bot.d.ts +32 -28
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +646 -648
- package/dist/device/bot.js.map +1 -1
- package/dist/device/colorbulb.d.ts +34 -19
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +429 -304
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +16 -7
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +288 -230
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +21 -16
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +519 -489
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/humidifier.d.ts +22 -18
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +415 -360
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/lock.d.ts +22 -8
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +253 -147
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +21 -16
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +325 -255
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +23 -12
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +346 -208
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +17 -8
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +261 -209
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +24 -16
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +267 -242
- package/dist/device/plug.js.map +1 -1
- package/dist/device/striplight.d.ts +51 -16
- package/dist/device/striplight.d.ts.map +1 -1
- package/dist/device/striplight.js +527 -185
- package/dist/device/striplight.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +7 -12
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +261 -230
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +3 -3
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +137 -104
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +9 -8
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +116 -86
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +8 -7
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +143 -109
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/light.d.ts +9 -8
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +120 -103
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +9 -8
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +128 -98
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +10 -9
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +126 -93
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +7 -10
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +115 -89
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +6 -9
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +115 -89
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +3 -5
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +203 -200
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +15 -11
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js.map +1 -1
- package/package.json +12 -10
- package/src/device/bot.ts +641 -657
- package/src/device/colorbulb.ts +440 -339
- package/src/device/contact.ts +289 -233
- package/src/device/curtain.ts +523 -503
- package/src/device/humidifier.ts +421 -396
- package/src/device/lock.ts +257 -147
- package/src/device/meter.ts +335 -268
- package/src/device/meterplus.ts +354 -213
- package/src/device/motion.ts +264 -213
- package/src/device/plug.ts +270 -251
- package/src/device/striplight.ts +552 -207
- package/src/irdevice/airconditioner.ts +263 -241
- package/src/irdevice/airpurifier.ts +132 -103
- package/src/irdevice/camera.ts +112 -85
- package/src/irdevice/fan.ts +138 -106
- package/src/irdevice/light.ts +116 -103
- package/src/irdevice/other.ts +124 -97
- package/src/irdevice/tv.ts +123 -93
- package/src/irdevice/vacuumcleaner.ts +112 -89
- package/src/irdevice/waterheater.ts +111 -89
- package/src/platform.ts +195 -216
- package/src/settings.ts +15 -11
package/src/device/lock.ts
CHANGED
|
@@ -3,6 +3,7 @@ import crypto from 'crypto';
|
|
|
3
3
|
import { Context } from 'vm';
|
|
4
4
|
import { IncomingMessage } from 'http';
|
|
5
5
|
import { interval, Subject } from 'rxjs';
|
|
6
|
+
import superStringify from 'super-stringify';
|
|
6
7
|
import { SwitchBotPlatform } from '../platform';
|
|
7
8
|
import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
|
|
8
9
|
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
@@ -32,17 +33,17 @@ export class Lock {
|
|
|
32
33
|
lockUpdateInProgress!: boolean;
|
|
33
34
|
doLockUpdate!: Subject<void>;
|
|
34
35
|
|
|
36
|
+
// Connection
|
|
37
|
+
private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'Both');
|
|
38
|
+
private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'Both');
|
|
39
|
+
|
|
35
40
|
constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
|
|
36
41
|
// default placeholders
|
|
37
42
|
this.logs(device);
|
|
38
43
|
this.scan(device);
|
|
39
44
|
this.refreshRate(device);
|
|
40
45
|
this.config(device);
|
|
41
|
-
|
|
42
|
-
this.LockTargetState = false;
|
|
43
|
-
} else {
|
|
44
|
-
this.LockTargetState = this.accessory.context.On;
|
|
45
|
-
}
|
|
46
|
+
this.conext();
|
|
46
47
|
|
|
47
48
|
// this is subject we use to track when we need to POST changes to the SwitchBot API
|
|
48
49
|
this.doLockUpdate = new Subject();
|
|
@@ -82,18 +83,18 @@ export class Lock {
|
|
|
82
83
|
|
|
83
84
|
// Contact Sensor Service
|
|
84
85
|
if (device.lock?.hide_contactsensor) {
|
|
85
|
-
this.debugLog(
|
|
86
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Contact Sensor Service`);
|
|
86
87
|
this.contactSensorService = this.accessory.getService(this.platform.Service.ContactSensor);
|
|
87
88
|
accessory.removeService(this.contactSensorService!);
|
|
88
89
|
} else if (!this.contactSensorService) {
|
|
89
|
-
this.debugLog(
|
|
90
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Contact Sensor Service`);
|
|
90
91
|
(this.contactSensorService =
|
|
91
92
|
this.accessory.getService(this.platform.Service.ContactSensor) || this.accessory.addService(this.platform.Service.ContactSensor)),
|
|
92
93
|
`${accessory.displayName} Contact Sensor`;
|
|
93
94
|
|
|
94
95
|
this.contactSensorService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Contact Sensor`);
|
|
95
96
|
} else {
|
|
96
|
-
this.debugLog(
|
|
97
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Contact Sensor Service Not Added`);
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
// Update Homekit
|
|
@@ -119,19 +120,33 @@ export class Lock {
|
|
|
119
120
|
try {
|
|
120
121
|
await this.pushChanges();
|
|
121
122
|
} catch (e: any) {
|
|
122
|
-
this.errorLog(`Lock: ${this.accessory.displayName} failed pushChanges`);
|
|
123
|
-
if (this.deviceLogging.includes('debug')) {
|
|
124
|
-
this.errorLog(`Lock: ${this.accessory.displayName} failed pushChanges,` + ` Error Message: ${JSON.stringify(e.message)}`);
|
|
125
|
-
}
|
|
126
123
|
this.apiError(e);
|
|
124
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
|
|
125
|
+
+ ` Error Message: ${superStringify(e.message)}`);
|
|
127
126
|
}
|
|
128
127
|
this.lockUpdateInProgress = false;
|
|
129
128
|
});
|
|
130
129
|
}
|
|
131
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Parse the device status from the SwitchBot api
|
|
133
|
+
*/
|
|
134
|
+
async parseStatus(): Promise<void> {
|
|
135
|
+
/*if (this.BLE && !this.SwitchToOpenAPI) {
|
|
136
|
+
await this.BLEparseStatus();
|
|
137
|
+
} else*/ if (this.OpenAPI) {
|
|
138
|
+
//this.SwitchToOpenAPI = false;
|
|
139
|
+
await this.openAPIparseStatus();
|
|
140
|
+
} else {
|
|
141
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
142
|
+
+ ` ${this.device.connectionType}, parseStatus will not happen.`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
132
146
|
//{"deviceId":"DBDC23B53139","deviceType":"Smart Lock","hubDeviceId":"E68B14109DA2","lockState":"locked","doorState":"opened","calibrate":true}
|
|
133
147
|
|
|
134
|
-
async
|
|
148
|
+
async openAPIparseStatus(): Promise<void> {
|
|
149
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
|
|
135
150
|
switch (this.lockState) {
|
|
136
151
|
case 'locked':
|
|
137
152
|
this.LockCurrentState = this.platform.Characteristic.LockCurrentState.SECURED;
|
|
@@ -148,17 +163,32 @@ export class Lock {
|
|
|
148
163
|
default:
|
|
149
164
|
this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
|
|
150
165
|
}
|
|
151
|
-
this.debugLog(
|
|
166
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.LockTargetState}`);
|
|
152
167
|
}
|
|
153
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Asks the SwitchBot API for the latest device information
|
|
171
|
+
*/
|
|
154
172
|
async refreshStatus(): Promise<void> {
|
|
173
|
+
/*if (this.BLE) {
|
|
174
|
+
await this.BLERefreshStatus();
|
|
175
|
+
} else*/ if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
176
|
+
await this.openAPIRefreshStatus();
|
|
177
|
+
} else {
|
|
178
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
179
|
+
+ ` ${this.device.connectionType}, refreshStatus will not happen.`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async openAPIRefreshStatus(): Promise<void> {
|
|
184
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
|
|
155
185
|
try {
|
|
156
186
|
const t = Date.now();
|
|
157
187
|
const nonce = 'requestID';
|
|
158
188
|
const data = this.platform.config.credentials?.token + t + nonce;
|
|
159
189
|
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
160
190
|
const sign = signTerm.toString('base64');
|
|
161
|
-
this.debugLog(
|
|
191
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
162
192
|
const options = {
|
|
163
193
|
hostname: HostDomain,
|
|
164
194
|
port: 443,
|
|
@@ -173,37 +203,33 @@ export class Lock {
|
|
|
173
203
|
},
|
|
174
204
|
};
|
|
175
205
|
const req = https.request(options, (res) => {
|
|
176
|
-
this.debugLog(
|
|
206
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
|
|
177
207
|
let rawData = '';
|
|
178
208
|
res.on('data', (d) => {
|
|
179
209
|
rawData += d;
|
|
180
|
-
this.debugLog(
|
|
210
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
181
211
|
});
|
|
182
212
|
res.on('end', () => {
|
|
183
213
|
try {
|
|
184
214
|
this.deviceStatus = JSON.parse(rawData);
|
|
185
|
-
this.debugLog(
|
|
215
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${superStringify(this.deviceStatus)}`);
|
|
186
216
|
this.lockState = this.deviceStatus.body.lockState;
|
|
187
217
|
this.doorState = this.deviceStatus.body.doorState;
|
|
188
218
|
this.parseStatus();
|
|
189
219
|
this.updateHomeKitCharacteristics();
|
|
190
220
|
} catch (e: any) {
|
|
191
|
-
this.errorLog(
|
|
221
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
192
222
|
}
|
|
193
223
|
});
|
|
194
224
|
});
|
|
195
225
|
req.on('error', (e: any) => {
|
|
196
|
-
this.errorLog(
|
|
226
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
197
227
|
});
|
|
198
228
|
req.end();
|
|
199
229
|
} catch (e: any) {
|
|
200
|
-
this.errorLog(`Lock: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
|
|
201
|
-
if (this.deviceLogging.includes('debug')) {
|
|
202
|
-
this.errorLog(
|
|
203
|
-
`Lock: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
230
|
this.apiError(e);
|
|
231
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
|
|
232
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
207
233
|
}
|
|
208
234
|
}
|
|
209
235
|
|
|
@@ -214,55 +240,14 @@ export class Lock {
|
|
|
214
240
|
* Lock - "command" "unlock" "default" = set to ???? state - LockCurrentState
|
|
215
241
|
*/
|
|
216
242
|
async pushChanges(): Promise<void> {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
|
|
222
|
-
.update(Buffer.from(data, 'utf-8'))
|
|
223
|
-
.digest();
|
|
224
|
-
const sign = signTerm.toString('base64');
|
|
225
|
-
this.debugLog(`Lock: ${this.accessory.displayName} sign: ${sign}`);
|
|
226
|
-
let command = '';
|
|
227
|
-
if (this.LockTargetState) {
|
|
228
|
-
command = 'lock';
|
|
243
|
+
/*if (this.BLE) {
|
|
244
|
+
await this.BLERefreshStatus();
|
|
245
|
+
} else*/ if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
246
|
+
await this.openAPIpushChanges();
|
|
229
247
|
} else {
|
|
230
|
-
|
|
248
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
249
|
+
+ ` ${this.device.connectionType}, pushChanges will not happen.`);
|
|
231
250
|
}
|
|
232
|
-
const body = JSON.stringify({
|
|
233
|
-
'command': `${command}`,
|
|
234
|
-
'parameter': 'default',
|
|
235
|
-
'commandType': 'command',
|
|
236
|
-
});
|
|
237
|
-
this.infoLog(`Lock: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
|
|
238
|
-
const options = {
|
|
239
|
-
hostname: HostDomain,
|
|
240
|
-
port: 443,
|
|
241
|
-
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
242
|
-
method: 'POST',
|
|
243
|
-
headers: {
|
|
244
|
-
'Authorization': this.platform.config.credentials?.token,
|
|
245
|
-
'sign': sign,
|
|
246
|
-
'nonce': nonce,
|
|
247
|
-
't': t,
|
|
248
|
-
'Content-Type': 'application/json',
|
|
249
|
-
'Content-Length': body.length,
|
|
250
|
-
},
|
|
251
|
-
};
|
|
252
|
-
const req = https.request(options, res => {
|
|
253
|
-
this.debugLog(`Lock: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
254
|
-
this.statusCode({ res });
|
|
255
|
-
res.on('data', d => {
|
|
256
|
-
this.debugLog(`Lock: ${this.accessory.displayName} d: ${d}`);
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
req.on('error', (e: any) => {
|
|
260
|
-
this.errorLog(`Lock: ${this.accessory.displayName} error message: ${e.message}`);
|
|
261
|
-
});
|
|
262
|
-
req.write(body);
|
|
263
|
-
req.end();
|
|
264
|
-
this.debugLog(`Lock: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
|
|
265
|
-
this.accessory.context.On = this.LockTargetState;
|
|
266
251
|
interval(5000)
|
|
267
252
|
.pipe(take(1))
|
|
268
253
|
.subscribe(async () => {
|
|
@@ -270,77 +255,241 @@ export class Lock {
|
|
|
270
255
|
});
|
|
271
256
|
}
|
|
272
257
|
|
|
258
|
+
async BLEpushChanges(): Promise<void> {
|
|
259
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
|
|
260
|
+
if (this.LockTargetState !== this.accessory.context.LockTargetState) {
|
|
261
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges LockTargetState: ${this.LockTargetState}`
|
|
262
|
+
+ ` LockTargetStateCached: ${this.accessory.context.LockTargetState}`);
|
|
263
|
+
const switchbot = await this.platform.connectBLE();
|
|
264
|
+
// Convert to BLE Address
|
|
265
|
+
this.device.bleMac = this.device
|
|
266
|
+
.deviceId!.match(/.{1,2}/g)!
|
|
267
|
+
.join(':')
|
|
268
|
+
.toLowerCase();
|
|
269
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
|
|
270
|
+
switchbot
|
|
271
|
+
.discover({
|
|
272
|
+
model: '',
|
|
273
|
+
id: this.device.bleMac,
|
|
274
|
+
})
|
|
275
|
+
.then(() => {
|
|
276
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
|
|
277
|
+
this.LockTargetState = this.platform.Characteristic.LockTargetState.SECURED;
|
|
278
|
+
})
|
|
279
|
+
.catch(async (e: any) => {
|
|
280
|
+
this.apiError(e);
|
|
281
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
|
|
282
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
283
|
+
if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
|
|
284
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
285
|
+
await this.openAPIpushChanges();
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
} else {
|
|
289
|
+
this.debugLog(
|
|
290
|
+
`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `LockTargetState: ${this.LockTargetState}, `
|
|
291
|
+
+`LockTargetStateCached: ${this.accessory.context.LockTargetState}`,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async openAPIpushChanges(): Promise<void> {
|
|
297
|
+
try {
|
|
298
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
|
|
299
|
+
if (this.LockTargetState !== this.accessory.context.LockTargetState) {
|
|
300
|
+
// Make Push On request to the API
|
|
301
|
+
const t = Date.now();
|
|
302
|
+
const nonce = 'requestID';
|
|
303
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
304
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
|
|
305
|
+
.update(Buffer.from(data, 'utf-8'))
|
|
306
|
+
.digest();
|
|
307
|
+
const sign = signTerm.toString('base64');
|
|
308
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
309
|
+
let command = '';
|
|
310
|
+
if (this.LockTargetState) {
|
|
311
|
+
command = 'lock';
|
|
312
|
+
} else {
|
|
313
|
+
command = 'unlock';
|
|
314
|
+
}
|
|
315
|
+
const body = superStringify({
|
|
316
|
+
'command': `${command}`,
|
|
317
|
+
'parameter': 'default',
|
|
318
|
+
'commandType': 'command',
|
|
319
|
+
});
|
|
320
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
|
|
321
|
+
const options = {
|
|
322
|
+
hostname: HostDomain,
|
|
323
|
+
port: 443,
|
|
324
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
325
|
+
method: 'POST',
|
|
326
|
+
headers: {
|
|
327
|
+
'Authorization': this.platform.config.credentials?.token,
|
|
328
|
+
'sign': sign,
|
|
329
|
+
'nonce': nonce,
|
|
330
|
+
't': t,
|
|
331
|
+
'Content-Type': 'application/json',
|
|
332
|
+
'Content-Length': body.length,
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
const req = https.request(options, res => {
|
|
336
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
|
|
337
|
+
this.statusCode({ res });
|
|
338
|
+
res.on('data', d => {
|
|
339
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
req.on('error', (e: any) => {
|
|
343
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
344
|
+
});
|
|
345
|
+
req.write(body);
|
|
346
|
+
req.end();
|
|
347
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${superStringify(req)}`);
|
|
348
|
+
} else {
|
|
349
|
+
this.debugLog(
|
|
350
|
+
`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `LockTargetState: ${this.LockTargetState}, `
|
|
351
|
+
+`LockTargetStateCached: ${this.accessory.context.LockTargetState}`,
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
} catch (e: any) {
|
|
355
|
+
this.apiError(e);
|
|
356
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
|
|
357
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`,
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Handle requests to set the value of the "On" characteristic
|
|
364
|
+
*/
|
|
365
|
+
async LockTargetStateSet(value: CharacteristicValue): Promise<void> {
|
|
366
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set LockTargetState: ${value}`);
|
|
367
|
+
|
|
368
|
+
this.LockTargetState = value;
|
|
369
|
+
this.doLockUpdate.next();
|
|
370
|
+
}
|
|
371
|
+
|
|
273
372
|
async updateHomeKitCharacteristics(): Promise<void> {
|
|
274
373
|
if (!this.device.lock?.hide_contactsensor) {
|
|
275
374
|
if (this.ContactSensorState === undefined) {
|
|
276
|
-
this.debugLog(
|
|
375
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
|
|
277
376
|
} else {
|
|
377
|
+
this.accessory.context.ContactSensorState = this.ContactSensorState;
|
|
278
378
|
this.contactSensorService?.updateCharacteristic(this.platform.Characteristic.ContactSensorState, this.ContactSensorState);
|
|
279
|
-
this.debugLog(
|
|
379
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic ContactSensorState: ${this.ContactSensorState}`);
|
|
280
380
|
}
|
|
281
381
|
}
|
|
282
382
|
if (this.LockTargetState === undefined) {
|
|
283
|
-
this.debugLog(
|
|
383
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LockTargetState: ${this.LockTargetState}`);
|
|
284
384
|
} else {
|
|
385
|
+
this.accessory.context.LockTargetState = this.LockTargetState;
|
|
285
386
|
this.lockService.updateCharacteristic(this.platform.Characteristic.LockTargetState, this.LockTargetState);
|
|
286
|
-
this.debugLog(
|
|
387
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic LockTargetState: ${this.LockTargetState}`);
|
|
287
388
|
}
|
|
288
389
|
if (this.LockCurrentState === undefined) {
|
|
289
|
-
this.debugLog(
|
|
390
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LockCurrentState: ${this.LockCurrentState}`);
|
|
290
391
|
} else {
|
|
392
|
+
this.accessory.context.LockCurrentState = this.LockCurrentState;
|
|
291
393
|
this.lockService.updateCharacteristic(this.platform.Characteristic.LockCurrentState, this.LockCurrentState);
|
|
292
|
-
this.debugLog(
|
|
394
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic LockCurrentState: ${this.LockCurrentState}`);
|
|
293
395
|
}
|
|
294
396
|
}
|
|
295
397
|
|
|
296
|
-
async
|
|
297
|
-
if (
|
|
298
|
-
this.
|
|
398
|
+
async scan(device: device & devicesConfig): Promise<void> {
|
|
399
|
+
if (device.scanDuration) {
|
|
400
|
+
this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
|
|
401
|
+
if (this.BLE) {
|
|
402
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
this.scanDuration = this.accessory.context.scanDuration = 1;
|
|
406
|
+
if (this.BLE) {
|
|
407
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
|
|
408
|
+
}
|
|
299
409
|
}
|
|
300
|
-
this.lockService.updateCharacteristic(this.platform.Characteristic.LockTargetState, e);
|
|
301
|
-
this.lockService.updateCharacteristic(this.platform.Characteristic.LockCurrentState, e);
|
|
302
|
-
//throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
|
303
410
|
}
|
|
304
411
|
|
|
305
412
|
async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
|
|
306
413
|
switch (res.statusCode) {
|
|
307
414
|
case 151:
|
|
308
|
-
this.errorLog(
|
|
415
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
|
|
309
416
|
break;
|
|
310
417
|
case 152:
|
|
311
|
-
this.errorLog(
|
|
418
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
|
|
312
419
|
break;
|
|
313
420
|
case 160:
|
|
314
|
-
this.errorLog(
|
|
421
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
|
|
315
422
|
break;
|
|
316
423
|
case 161:
|
|
317
|
-
this.errorLog(
|
|
424
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
|
|
425
|
+
this.offlineOff();
|
|
318
426
|
break;
|
|
319
427
|
case 171:
|
|
320
|
-
this.errorLog(
|
|
428
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
|
|
429
|
+
this.offlineOff();
|
|
321
430
|
break;
|
|
322
431
|
case 190:
|
|
323
432
|
this.errorLog(
|
|
324
|
-
|
|
325
|
-
` Or command: ${
|
|
433
|
+
`${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
434
|
+
` Or command: ${superStringify(res)} format is invalid`,
|
|
326
435
|
);
|
|
327
436
|
break;
|
|
328
437
|
case 100:
|
|
329
|
-
this.debugLog(
|
|
438
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
|
|
330
439
|
break;
|
|
331
440
|
default:
|
|
332
|
-
this.debugLog(
|
|
441
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
|
|
333
442
|
}
|
|
334
443
|
}
|
|
335
444
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
445
|
+
async offlineOff(): Promise<void> {
|
|
446
|
+
if (this.device.offline) {
|
|
447
|
+
this.LockCurrentState = this.platform.Characteristic.LockCurrentState.SECURED;
|
|
448
|
+
this.lockService.getCharacteristic(this.platform.Characteristic.LockCurrentState).updateValue(this.LockCurrentState);
|
|
449
|
+
await this.updateHomeKitCharacteristics();
|
|
450
|
+
}
|
|
451
|
+
}
|
|
341
452
|
|
|
342
|
-
|
|
343
|
-
this.
|
|
453
|
+
async apiError(e: any): Promise<void> {
|
|
454
|
+
if (!this.device.lock?.hide_contactsensor) {
|
|
455
|
+
this.contactSensorService?.updateCharacteristic(this.platform.Characteristic.ContactSensorState, e);
|
|
456
|
+
}
|
|
457
|
+
this.lockService.updateCharacteristic(this.platform.Characteristic.LockTargetState, e);
|
|
458
|
+
this.lockService.updateCharacteristic(this.platform.Characteristic.LockCurrentState, e);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
|
|
462
|
+
let FirmwareRevision: string;
|
|
463
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
|
|
464
|
+
+ ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
|
|
465
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
|
|
466
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
|
|
467
|
+
if (accessory.context.FirmwareRevision) {
|
|
468
|
+
FirmwareRevision = accessory.context.FirmwareRevision;
|
|
469
|
+
} else if (device.firmware) {
|
|
470
|
+
FirmwareRevision = device.firmware;
|
|
471
|
+
} else {
|
|
472
|
+
FirmwareRevision = this.platform.version;
|
|
473
|
+
}
|
|
474
|
+
return FirmwareRevision;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private conext() {
|
|
478
|
+
if (this.LockTargetState === undefined) {
|
|
479
|
+
this.LockTargetState = false;
|
|
480
|
+
} else {
|
|
481
|
+
this.LockTargetState = this.accessory.context.On;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
async refreshRate(device: device & devicesConfig): Promise<void> {
|
|
486
|
+
if (device.refreshRate) {
|
|
487
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
|
|
488
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
|
|
489
|
+
} else if (this.platform.config.options!.refreshRate) {
|
|
490
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
491
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
492
|
+
}
|
|
344
493
|
}
|
|
345
494
|
|
|
346
495
|
async config(device: device & devicesConfig): Promise<void> {
|
|
@@ -348,8 +497,8 @@ export class Lock {
|
|
|
348
497
|
if (device.lock) {
|
|
349
498
|
config = device.lock;
|
|
350
499
|
}
|
|
351
|
-
if (device.
|
|
352
|
-
config['
|
|
500
|
+
if (device.connectionType !== undefined) {
|
|
501
|
+
config['connectionType'] = device.connectionType;
|
|
353
502
|
}
|
|
354
503
|
if (device.logging !== undefined) {
|
|
355
504
|
config['logging'] = device.logging;
|
|
@@ -361,65 +510,26 @@ export class Lock {
|
|
|
361
510
|
config['scanDuration'] = device.scanDuration;
|
|
362
511
|
}
|
|
363
512
|
if (Object.entries(config).length !== 0) {
|
|
364
|
-
this.infoLog(
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
async refreshRate(device: device & devicesConfig): Promise<void> {
|
|
369
|
-
if (device.refreshRate) {
|
|
370
|
-
this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
|
|
371
|
-
this.debugLog(`Lock: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
|
|
372
|
-
} else if (this.platform.config.options!.refreshRate) {
|
|
373
|
-
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
374
|
-
this.debugLog(`Lock: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
async scan(device: device & devicesConfig): Promise<void> {
|
|
379
|
-
if (device.scanDuration) {
|
|
380
|
-
this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
|
|
381
|
-
if (device.ble) {
|
|
382
|
-
this.debugLog(`Lock: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
|
|
383
|
-
}
|
|
384
|
-
} else {
|
|
385
|
-
this.scanDuration = this.accessory.context.scanDuration = 1;
|
|
386
|
-
if (this.device.ble) {
|
|
387
|
-
this.debugLog(`Lock: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
|
|
388
|
-
}
|
|
513
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
|
|
389
514
|
}
|
|
390
515
|
}
|
|
391
516
|
|
|
392
517
|
async logs(device: device & devicesConfig): Promise<void> {
|
|
393
518
|
if (this.platform.debugMode) {
|
|
394
519
|
this.deviceLogging = this.accessory.context.logging = 'debugMode';
|
|
395
|
-
this.debugLog(
|
|
520
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
|
|
396
521
|
} else if (device.logging) {
|
|
397
522
|
this.deviceLogging = this.accessory.context.logging = device.logging;
|
|
398
|
-
this.debugLog(
|
|
523
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
|
|
399
524
|
} else if (this.platform.config.options?.logging) {
|
|
400
525
|
this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
|
|
401
|
-
this.debugLog(
|
|
526
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
|
|
402
527
|
} else {
|
|
403
528
|
this.deviceLogging = this.accessory.context.logging = 'standard';
|
|
404
|
-
this.debugLog(
|
|
529
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
|
|
405
530
|
}
|
|
406
531
|
}
|
|
407
532
|
|
|
408
|
-
FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
|
|
409
|
-
let FirmwareRevision: string;
|
|
410
|
-
this.debugLog(`Lock: ${this.accessory.displayName} accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
|
|
411
|
-
this.debugLog(`Lock: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
|
|
412
|
-
this.debugLog(`Lock: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
|
|
413
|
-
if (accessory.context.FirmwareRevision) {
|
|
414
|
-
FirmwareRevision = accessory.context.FirmwareRevision;
|
|
415
|
-
} else if (device.firmware) {
|
|
416
|
-
FirmwareRevision = device.firmware;
|
|
417
|
-
} else {
|
|
418
|
-
FirmwareRevision = this.platform.version;
|
|
419
|
-
}
|
|
420
|
-
return FirmwareRevision;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
533
|
/**
|
|
424
534
|
* Logging for Device
|
|
425
535
|
*/
|