@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.
@@ -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
- private async createMeterPlus(device: device & devicesConfig) {
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;