@switchbot/homebridge-switchbot 2.6.0-beta.0 → 2.6.0-beta.2
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/README.md +0 -2
- package/config.schema.json +27 -1
- package/dist/device/hub.d.ts +65 -0
- package/dist/device/hub.d.ts.map +1 -0
- package/dist/device/hub.js +352 -0
- package/dist/device/hub.js.map +1 -0
- package/dist/platform.d.ts +1 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +57 -0
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +5 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js.map +1 -1
- package/package.json +1 -1
- package/src/device/hub.ts +395 -0
- package/src/platform.ts +61 -1
- package/src/settings.ts +6 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import https from 'https';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { Context } from 'vm';
|
|
4
|
+
import { IncomingMessage } from 'http';
|
|
5
|
+
import { interval } from 'rxjs';
|
|
6
|
+
import superStringify from 'super-stringify';
|
|
7
|
+
import { SwitchBotPlatform } from '../platform';
|
|
8
|
+
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
9
|
+
import { device, devicesConfig, HostDomain, DevicePath } from '../settings';
|
|
10
|
+
import { sleep } from '../utils';
|
|
11
|
+
|
|
12
|
+
export class Hub {
|
|
13
|
+
// Services
|
|
14
|
+
hubTemperatureSensor: Service;
|
|
15
|
+
hubHumiditySensor: Service;
|
|
16
|
+
|
|
17
|
+
// Characteristic Values
|
|
18
|
+
CurrentRelativeHumidity!: number;
|
|
19
|
+
CurrentTemperature!: number;
|
|
20
|
+
|
|
21
|
+
// OpenAPI Others
|
|
22
|
+
deviceStatus!: any; //deviceStatusResponse;
|
|
23
|
+
|
|
24
|
+
// Config
|
|
25
|
+
set_minStep!: number;
|
|
26
|
+
updateRate!: number;
|
|
27
|
+
set_minLux!: number;
|
|
28
|
+
set_maxLux!: number;
|
|
29
|
+
scanDuration!: number;
|
|
30
|
+
deviceLogging!: string;
|
|
31
|
+
deviceRefreshRate!: number;
|
|
32
|
+
|
|
33
|
+
// Connection
|
|
34
|
+
private readonly BLE = this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI';
|
|
35
|
+
private readonly OpenAPI = this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI';
|
|
36
|
+
|
|
37
|
+
constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
|
|
38
|
+
// default placeholders
|
|
39
|
+
this.logs(device);
|
|
40
|
+
this.refreshRate(device);
|
|
41
|
+
|
|
42
|
+
this.CurrentRelativeHumidity = accessory.context.CurrentRelativeHumidity;
|
|
43
|
+
this.CurrentTemperature = accessory.context.CurrentTemperature;
|
|
44
|
+
|
|
45
|
+
// Retrieve initial values and updateHomekit
|
|
46
|
+
this.refreshStatus();
|
|
47
|
+
|
|
48
|
+
// set accessory information
|
|
49
|
+
accessory
|
|
50
|
+
.getService(this.platform.Service.AccessoryInformation)!
|
|
51
|
+
.setCharacteristic(this.platform.Characteristic.Manufacturer, 'SwitchBot')
|
|
52
|
+
.setCharacteristic(this.platform.Characteristic.Model, accessory.context.model)
|
|
53
|
+
.setCharacteristic(this.platform.Characteristic.SerialNumber, device.deviceId)
|
|
54
|
+
.setCharacteristic(this.platform.Characteristic.FirmwareRevision, this.FirmwareRevision(accessory, device))
|
|
55
|
+
.getCharacteristic(this.platform.Characteristic.FirmwareRevision)
|
|
56
|
+
.updateValue(this.FirmwareRevision(accessory, device));
|
|
57
|
+
|
|
58
|
+
// get the WindowCovering service if it exists, otherwise create a new WindowCovering service
|
|
59
|
+
// you can create multiple services for each accessory
|
|
60
|
+
(this.hubTemperatureSensor =
|
|
61
|
+
accessory.getService(this.platform.Service.TemperatureSensor) || accessory.addService(this.platform.Service.TemperatureSensor)),
|
|
62
|
+
`${device.deviceName} ${device.deviceType}`;
|
|
63
|
+
|
|
64
|
+
(this.hubHumiditySensor =
|
|
65
|
+
accessory.getService(this.platform.Service.HumiditySensor) || accessory.addService(this.platform.Service.HumiditySensor)),
|
|
66
|
+
`${device.deviceName} ${device.deviceType}`;
|
|
67
|
+
|
|
68
|
+
// To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
|
|
69
|
+
// when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
|
|
70
|
+
// accessory.getService('NAME') ?? accessory.addService(this.platform.Service.WindowCovering, 'NAME', 'USER_DEFINED_SUBTYPE');
|
|
71
|
+
|
|
72
|
+
// set the service name, this is what is displayed as the default name on the Home app
|
|
73
|
+
// in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
|
|
74
|
+
this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
75
|
+
if (!this.hubTemperatureSensor.testCharacteristic(this.platform.Characteristic.ConfiguredName)) {
|
|
76
|
+
this.hubTemperatureSensor.addCharacteristic(this.platform.Characteristic.ConfiguredName, accessory.displayName);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.hubHumiditySensor.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
80
|
+
if (!this.hubHumiditySensor.testCharacteristic(this.platform.Characteristic.ConfiguredName)) {
|
|
81
|
+
this.hubHumiditySensor.addCharacteristic(this.platform.Characteristic.ConfiguredName, accessory.displayName);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// each service must implement at-minimum the "required characteristics" for the given service type
|
|
85
|
+
// see https://developers.homebridge.io/#/service/WindowCovering
|
|
86
|
+
|
|
87
|
+
// console.log(this.hubHumiditySensor);
|
|
88
|
+
|
|
89
|
+
// Humidity Sensor Service
|
|
90
|
+
if (device.hub?.hide_humidity) {
|
|
91
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Humidity Sensor Service`);
|
|
92
|
+
this.hubHumiditySensor = this.hubHumiditySensor.setCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, false);
|
|
93
|
+
accessory.removeService(this.hubHumiditySensor!);
|
|
94
|
+
} else if (!this.hubHumiditySensor) {
|
|
95
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Humidity Sensor Service`);
|
|
96
|
+
(this.hubHumiditySensor =
|
|
97
|
+
accessory.getService(this.platform.Service.HumiditySensor) || accessory.addService(this.platform.Service.HumiditySensor)),
|
|
98
|
+
`${device.deviceName} ${device.deviceType}`;
|
|
99
|
+
|
|
100
|
+
this.hubHumiditySensor.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Humidity Sensor`);
|
|
101
|
+
this.hubHumiditySensor.setCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Humidity Sensor`);
|
|
102
|
+
} else {
|
|
103
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Humidity Sensor Service Not Added`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Temperature Sensor Service
|
|
107
|
+
if (device.hub?.hide_temperature) {
|
|
108
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Temperature Sensor Service`);
|
|
109
|
+
this.hubTemperatureSensor = this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.CurrentTemperature, false);
|
|
110
|
+
accessory.removeService(this.hubTemperatureSensor!);
|
|
111
|
+
} else if (!this.hubTemperatureSensor) {
|
|
112
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Temperature Sensor Service`);
|
|
113
|
+
(this.hubTemperatureSensor =
|
|
114
|
+
accessory.getService(this.platform.Service.TemperatureSensor) || accessory.addService(this.platform.Service.TemperatureSensor)),
|
|
115
|
+
`${device.deviceName} ${device.deviceType}`;
|
|
116
|
+
|
|
117
|
+
this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Temperature Sensor`);
|
|
118
|
+
this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.ConfiguredName, `${accessory.displayName} Temperature Sensor`);
|
|
119
|
+
} else {
|
|
120
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Temperature Sensor Service Not Added`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Update Homekit
|
|
124
|
+
this.updateHomeKitCharacteristics();
|
|
125
|
+
|
|
126
|
+
// Start an update interval
|
|
127
|
+
interval(this.deviceRefreshRate * 1000).subscribe(async () => {
|
|
128
|
+
await this.refreshStatus();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Parse the device status from the SwitchBot api
|
|
134
|
+
*/
|
|
135
|
+
async parseStatus(): Promise<void> {
|
|
136
|
+
if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
137
|
+
await this.openAPIparseStatus();
|
|
138
|
+
} else {
|
|
139
|
+
await this.offlineOff();
|
|
140
|
+
this.debugWarnLog(
|
|
141
|
+
`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:` + ` ${this.device.connectionType}, parseStatus will not happen.`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async openAPIparseStatus(): Promise<void> {
|
|
147
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
|
|
148
|
+
this.infoLog(`update temperature and humidity for ${this.accessory.displayName}`);
|
|
149
|
+
// this.infoLog(`temp: ${this.CurrentTemperature}, humidity: ${this.CurrentRelativeHumidity}`);
|
|
150
|
+
this.hubTemperatureSensor.setCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature);
|
|
151
|
+
this.hubHumiditySensor.setCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async refreshStatus(): Promise<void> {
|
|
155
|
+
if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
156
|
+
await this.openAPIRefreshStatus();
|
|
157
|
+
} else {
|
|
158
|
+
await this.offlineOff();
|
|
159
|
+
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type: OpenAPI, refreshStatus will not happen.`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async openAPIRefreshStatus(): Promise<void> {
|
|
164
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
|
|
165
|
+
try {
|
|
166
|
+
const t = Date.now();
|
|
167
|
+
const nonce = 'requestID';
|
|
168
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
169
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
170
|
+
const sign = signTerm.toString('base64');
|
|
171
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
172
|
+
const options = {
|
|
173
|
+
hostname: HostDomain,
|
|
174
|
+
port: 443,
|
|
175
|
+
path: `${DevicePath}/${this.device.deviceId}/status`,
|
|
176
|
+
method: 'GET',
|
|
177
|
+
headers: {
|
|
178
|
+
Authorization: this.platform.config.credentials?.token,
|
|
179
|
+
sign: sign,
|
|
180
|
+
nonce: nonce,
|
|
181
|
+
t: t,
|
|
182
|
+
'Content-Type': 'application/json',
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
const req = https.request(options, (res) => {
|
|
186
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
187
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}: ${res}`);
|
|
188
|
+
let rawData = '';
|
|
189
|
+
res.on('data', (d) => {
|
|
190
|
+
rawData += d;
|
|
191
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
192
|
+
});
|
|
193
|
+
res.on('end', () => {
|
|
194
|
+
try {
|
|
195
|
+
this.deviceStatus = JSON.parse(rawData);
|
|
196
|
+
this.CurrentTemperature = this.deviceStatus.body.temperature;
|
|
197
|
+
this.CurrentRelativeHumidity = this.deviceStatus.body.humidity;
|
|
198
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
|
|
199
|
+
this.openAPIparseStatus();
|
|
200
|
+
this.updateHomeKitCharacteristics();
|
|
201
|
+
} catch (e: any) {
|
|
202
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
req.on('error', (e: any) => {
|
|
207
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
208
|
+
});
|
|
209
|
+
req.end();
|
|
210
|
+
} catch (e: any) {
|
|
211
|
+
this.apiError(e);
|
|
212
|
+
this.errorLog(
|
|
213
|
+
`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` +
|
|
214
|
+
` Connection, Error Message: ${superStringify(e.message)}`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
|
|
220
|
+
return fn().catch(async (e: any) => {
|
|
221
|
+
if (max === 0) {
|
|
222
|
+
throw e;
|
|
223
|
+
}
|
|
224
|
+
this.infoLog(e);
|
|
225
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Retrying`);
|
|
226
|
+
await sleep(1000);
|
|
227
|
+
return this.retry({ max: max - 1, fn });
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
maxRetry(): number {
|
|
232
|
+
if (this.device.maxRetry) {
|
|
233
|
+
return this.device.maxRetry;
|
|
234
|
+
} else {
|
|
235
|
+
return 5;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Handle requests to set the value of the "Target Position" characteristic
|
|
241
|
+
*/
|
|
242
|
+
|
|
243
|
+
async updateHomeKitCharacteristics(): Promise<void> {
|
|
244
|
+
this.hubHumiditySensor?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.CurrentRelativeHumidity);
|
|
245
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
|
|
246
|
+
this.hubTemperatureSensor?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
|
|
250
|
+
switch (res.statusCode) {
|
|
251
|
+
case 151:
|
|
252
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
|
|
253
|
+
break;
|
|
254
|
+
case 152:
|
|
255
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
|
|
256
|
+
break;
|
|
257
|
+
case 160:
|
|
258
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
|
|
259
|
+
break;
|
|
260
|
+
case 161:
|
|
261
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
|
|
262
|
+
this.offlineOff();
|
|
263
|
+
break;
|
|
264
|
+
case 171:
|
|
265
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
|
|
266
|
+
this.offlineOff();
|
|
267
|
+
break;
|
|
268
|
+
case 190:
|
|
269
|
+
this.errorLog(
|
|
270
|
+
`${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
271
|
+
` Or command: ${superStringify(res)} format is invalid`,
|
|
272
|
+
);
|
|
273
|
+
break;
|
|
274
|
+
case 100:
|
|
275
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async offlineOff(): Promise<void> {
|
|
283
|
+
if (this.device.offline) {
|
|
284
|
+
await this.updateHomeKitCharacteristics();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async apiError(e: any): Promise<void> {
|
|
289
|
+
this.hubTemperatureSensor?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, e);
|
|
290
|
+
this.hubHumiditySensor?.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, e);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
|
|
294
|
+
let FirmwareRevision: string;
|
|
295
|
+
this.debugLog(
|
|
296
|
+
`${this.device.deviceType}: ${this.accessory.displayName}` + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`,
|
|
297
|
+
);
|
|
298
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
|
|
299
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
|
|
300
|
+
if (accessory.context.FirmwareRevision) {
|
|
301
|
+
FirmwareRevision = accessory.context.FirmwareRevision;
|
|
302
|
+
} else if (device.firmware) {
|
|
303
|
+
FirmwareRevision = device.firmware;
|
|
304
|
+
} else {
|
|
305
|
+
FirmwareRevision = this.platform.version;
|
|
306
|
+
}
|
|
307
|
+
return FirmwareRevision;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async refreshRate(device: device & devicesConfig): Promise<void> {
|
|
311
|
+
// refreshRate
|
|
312
|
+
if (device.refreshRate) {
|
|
313
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
|
|
314
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
|
|
315
|
+
} else if (this.platform.config.options!.refreshRate) {
|
|
316
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
317
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
318
|
+
}
|
|
319
|
+
// updateRate
|
|
320
|
+
if (device?.curtain?.updateRate) {
|
|
321
|
+
this.updateRate = device?.curtain?.updateRate;
|
|
322
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Curtain updateRate: ${this.updateRate}`);
|
|
323
|
+
} else {
|
|
324
|
+
this.updateRate = 7;
|
|
325
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default Curtain updateRate: ${this.updateRate}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async logs(device: device & devicesConfig): Promise<void> {
|
|
330
|
+
if (this.platform.debugMode) {
|
|
331
|
+
this.deviceLogging = this.accessory.context.logging = 'debugMode';
|
|
332
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
|
|
333
|
+
} else if (device.logging) {
|
|
334
|
+
this.deviceLogging = this.accessory.context.logging = device.logging;
|
|
335
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
|
|
336
|
+
} else if (this.platform.config.options?.logging) {
|
|
337
|
+
this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
|
|
338
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
|
|
339
|
+
} else {
|
|
340
|
+
this.deviceLogging = this.accessory.context.logging = 'standard';
|
|
341
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Logging for Device
|
|
347
|
+
*/
|
|
348
|
+
infoLog(...log: any[]): void {
|
|
349
|
+
if (this.enablingDeviceLogging()) {
|
|
350
|
+
this.platform.log.info(String(...log));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
warnLog(...log: any[]): void {
|
|
355
|
+
if (this.enablingDeviceLogging()) {
|
|
356
|
+
this.platform.log.warn(String(...log));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
debugWarnLog(...log: any[]): void {
|
|
361
|
+
if (this.enablingDeviceLogging()) {
|
|
362
|
+
if (this.deviceLogging?.includes('debug')) {
|
|
363
|
+
this.platform.log.warn('[DEBUG]', String(...log));
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
errorLog(...log: any[]): void {
|
|
369
|
+
if (this.enablingDeviceLogging()) {
|
|
370
|
+
this.platform.log.error(String(...log));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
debugErrorLog(...log: any[]): void {
|
|
375
|
+
if (this.enablingDeviceLogging()) {
|
|
376
|
+
if (this.deviceLogging?.includes('debug')) {
|
|
377
|
+
this.platform.log.error('[DEBUG]', String(...log));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
debugLog(...log: any[]): void {
|
|
383
|
+
if (this.enablingDeviceLogging()) {
|
|
384
|
+
if (this.deviceLogging === 'debug') {
|
|
385
|
+
this.platform.log.info('[DEBUG]', String(...log));
|
|
386
|
+
} else {
|
|
387
|
+
this.platform.log.debug(String(...log));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
enablingDeviceLogging(): boolean {
|
|
393
|
+
return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
|
|
394
|
+
}
|
|
395
|
+
}
|
package/src/platform.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Plug } from './device/plug';
|
|
|
3
3
|
import { Lock } from './device/lock';
|
|
4
4
|
import { Meter } from './device/meter';
|
|
5
5
|
import { Motion } from './device/motion';
|
|
6
|
+
import { Hub } from './device/hub';
|
|
6
7
|
import { Contact } from './device/contact';
|
|
7
8
|
import { Curtain } from './device/curtain';
|
|
8
9
|
import { IOSensor } from './device/iosensor';
|
|
@@ -414,6 +415,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
414
415
|
break;
|
|
415
416
|
case 'Hub 2':
|
|
416
417
|
this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
|
|
418
|
+
this.createHub2(device);
|
|
417
419
|
break;
|
|
418
420
|
case 'Bot':
|
|
419
421
|
this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
|
|
@@ -730,7 +732,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
730
732
|
}
|
|
731
733
|
}
|
|
732
734
|
|
|
733
|
-
|
|
735
|
+
private async createMeterPlus(device: device & devicesConfig) {
|
|
734
736
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
|
|
735
737
|
|
|
736
738
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -740,6 +742,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
740
742
|
if (existingAccessory) {
|
|
741
743
|
// the accessory already exists
|
|
742
744
|
if (await this.registerDevice(device)) {
|
|
745
|
+
// console.log("existingAccessory", existingAccessory);
|
|
743
746
|
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
|
|
744
747
|
existingAccessory.context.model = device.deviceType;
|
|
745
748
|
existingAccessory.context.deviceID = device.deviceId;
|
|
@@ -786,6 +789,63 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
786
789
|
}
|
|
787
790
|
}
|
|
788
791
|
|
|
792
|
+
private async createHub2(device: device & devicesConfig) {
|
|
793
|
+
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
|
|
794
|
+
|
|
795
|
+
// see if an accessory with the same uuid has already been registered and restored from
|
|
796
|
+
// the cached devices we stored in the `configureAccessory` method above
|
|
797
|
+
const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
|
|
798
|
+
|
|
799
|
+
if (existingAccessory) {
|
|
800
|
+
// the accessory already exists
|
|
801
|
+
if (await this.registerDevice(device)) {
|
|
802
|
+
// console.log("existingAccessory", existingAccessory);
|
|
803
|
+
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
|
|
804
|
+
existingAccessory.context.model = device.deviceType;
|
|
805
|
+
existingAccessory.context.deviceID = device.deviceId;
|
|
806
|
+
existingAccessory.displayName = device.configDeviceName || device.deviceName;
|
|
807
|
+
existingAccessory.context.firmwareRevision = device.firmware;
|
|
808
|
+
existingAccessory.context.deviceType = `SwitchBot: ${device.deviceType}`;
|
|
809
|
+
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName} DeviceID: ${device.deviceId}`);
|
|
810
|
+
existingAccessory.context.connectionType = await this.connectionType(device);
|
|
811
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
812
|
+
// create the accessory handler for the restored accessory
|
|
813
|
+
// this is imported from `platformAccessory.ts`
|
|
814
|
+
new Hub(this, existingAccessory, device);
|
|
815
|
+
this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${existingAccessory.UUID})`);
|
|
816
|
+
} else {
|
|
817
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
818
|
+
}
|
|
819
|
+
} else if (await this.registerDevice(device)) {
|
|
820
|
+
// the accessory does not yet exist, so we need to create it
|
|
821
|
+
if (!device.external) {
|
|
822
|
+
this.infoLog(`Adding new accessory: ${device.deviceName} ${device.deviceType} DeviceID: ${device.deviceId}`);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// create a new accessory
|
|
826
|
+
const accessory = new this.api.platformAccessory(device.deviceName, uuid);
|
|
827
|
+
|
|
828
|
+
// store a copy of the device object in the `accessory.context`
|
|
829
|
+
// the `context` property can be used to store any data about the accessory you may need
|
|
830
|
+
accessory.context.device = device;
|
|
831
|
+
accessory.context.model = device.deviceType;
|
|
832
|
+
accessory.context.deviceID = device.deviceId;
|
|
833
|
+
accessory.context.firmwareRevision = device.firmware;
|
|
834
|
+
accessory.context.deviceType = `SwitchBot: ${device.deviceType}`;
|
|
835
|
+
accessory.context.connectionType = await this.connectionType(device);
|
|
836
|
+
// create the accessory handler for the newly create accessory
|
|
837
|
+
// this is imported from `platformAccessory.ts`
|
|
838
|
+
new Hub(this, accessory, device);
|
|
839
|
+
this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${accessory.UUID})`);
|
|
840
|
+
|
|
841
|
+
// publish device externally or link the accessory to your platform
|
|
842
|
+
this.externalOrPlatform(device, accessory);
|
|
843
|
+
this.accessories.push(accessory);
|
|
844
|
+
} else {
|
|
845
|
+
this.debugLog(`Device not registered: ${device.deviceName} ${device.deviceType} DeviceID: ${device.deviceId}`);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
789
849
|
private async createIOSensor(device: device & devicesConfig) {
|
|
790
850
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
|
|
791
851
|
|
package/src/settings.ts
CHANGED
|
@@ -73,6 +73,7 @@ export interface devicesConfig extends device {
|
|
|
73
73
|
ceilinglight?: ceilinglight;
|
|
74
74
|
plug?: Record<any, any>;
|
|
75
75
|
lock?: lock;
|
|
76
|
+
hub?: hub;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
export type meter = {
|
|
@@ -152,6 +153,11 @@ export type lock = {
|
|
|
152
153
|
hide_contactsensor?: boolean;
|
|
153
154
|
};
|
|
154
155
|
|
|
156
|
+
export type hub = {
|
|
157
|
+
hide_temperature?: boolean;
|
|
158
|
+
hide_humidity?: boolean;
|
|
159
|
+
};
|
|
160
|
+
|
|
155
161
|
export interface irDevicesConfig extends irdevice {
|
|
156
162
|
configRemoteType?: string;
|
|
157
163
|
connectionType?: string;
|