@switchbot/homebridge-switchbot 3.6.0 → 3.6.1-beta.1

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.
Files changed (72) hide show
  1. package/.github/npm-version-script.cjs +81 -0
  2. package/config.schema.json +11 -0
  3. package/dist/device/blindtilt.js +1 -1
  4. package/dist/device/blindtilt.js.map +1 -1
  5. package/dist/device/bot.d.ts.map +1 -1
  6. package/dist/device/bot.js +2 -0
  7. package/dist/device/bot.js.map +1 -1
  8. package/dist/device/ceilinglight.js +1 -1
  9. package/dist/device/ceilinglight.js.map +1 -1
  10. package/dist/device/colorbulb.js +1 -1
  11. package/dist/device/colorbulb.js.map +1 -1
  12. package/dist/device/contact.js +1 -1
  13. package/dist/device/contact.js.map +1 -1
  14. package/dist/device/curtain.d.ts.map +1 -1
  15. package/dist/device/curtain.js +36 -19
  16. package/dist/device/curtain.js.map +1 -1
  17. package/dist/device/device.d.ts.map +1 -1
  18. package/dist/device/device.js +2 -3
  19. package/dist/device/device.js.map +1 -1
  20. package/dist/device/fan.js +1 -1
  21. package/dist/device/fan.js.map +1 -1
  22. package/dist/device/hub.js +1 -1
  23. package/dist/device/hub.js.map +1 -1
  24. package/dist/device/humidifier.js +1 -1
  25. package/dist/device/humidifier.js.map +1 -1
  26. package/dist/device/iosensor.js +1 -1
  27. package/dist/device/iosensor.js.map +1 -1
  28. package/dist/device/lightstrip.js +1 -1
  29. package/dist/device/lightstrip.js.map +1 -1
  30. package/dist/device/lock.js +1 -1
  31. package/dist/device/lock.js.map +1 -1
  32. package/dist/device/meter.js +1 -1
  33. package/dist/device/meter.js.map +1 -1
  34. package/dist/device/meterplus.js +1 -1
  35. package/dist/device/meterplus.js.map +1 -1
  36. package/dist/device/motion.js +1 -1
  37. package/dist/device/motion.js.map +1 -1
  38. package/dist/device/plug.js +1 -1
  39. package/dist/device/plug.js.map +1 -1
  40. package/dist/device/robotvacuumcleaner.js +1 -1
  41. package/dist/device/robotvacuumcleaner.js.map +1 -1
  42. package/dist/device/waterdetector.js +1 -1
  43. package/dist/device/waterdetector.js.map +1 -1
  44. package/dist/platform.d.ts +4 -0
  45. package/dist/platform.d.ts.map +1 -1
  46. package/dist/platform.js +32 -0
  47. package/dist/platform.js.map +1 -1
  48. package/dist/settings.d.ts +1 -0
  49. package/dist/settings.d.ts.map +1 -1
  50. package/dist/settings.js.map +1 -1
  51. package/package.json +5 -5
  52. package/src/device/blindtilt.ts +1 -1
  53. package/src/device/bot.ts +2 -0
  54. package/src/device/ceilinglight.ts +1 -1
  55. package/src/device/colorbulb.ts +1 -1
  56. package/src/device/contact.ts +1 -1
  57. package/src/device/curtain.ts +34 -19
  58. package/src/device/device.ts +3 -4
  59. package/src/device/fan.ts +1 -1
  60. package/src/device/hub.ts +1 -1
  61. package/src/device/humidifier.ts +1 -1
  62. package/src/device/iosensor.ts +1 -1
  63. package/src/device/lightstrip.ts +1 -1
  64. package/src/device/lock.ts +1 -1
  65. package/src/device/meter.ts +1 -1
  66. package/src/device/meterplus.ts +1 -1
  67. package/src/device/motion.ts +1 -1
  68. package/src/device/plug.ts +1 -1
  69. package/src/device/robotvacuumcleaner.ts +1 -1
  70. package/src/device/waterdetector.ts +1 -1
  71. package/src/platform.ts +30 -0
  72. package/src/settings.ts +1 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "SwitchBot",
3
3
  "name": "@switchbot/homebridge-switchbot",
4
- "version": "3.6.0",
4
+ "version": "3.6.1-beta.1",
5
5
  "description": "The SwitchBot plugin allows you to access your SwitchBot device(s) from HomeKit.",
6
6
  "author": {
7
7
  "name": "SwitchBot",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "engineStrict": true,
28
28
  "engines": {
29
- "homebridge": "^1.8.3",
29
+ "homebridge": "^1.8.4-beta.21",
30
30
  "node": "^18 || ^20 || ^22"
31
31
  },
32
32
  "main": "dist/index.js",
@@ -94,13 +94,13 @@
94
94
  "@types/node": "^20.14.10",
95
95
  "eslint": "^9.6.0",
96
96
  "globals": "^15.8.0",
97
- "homebridge": "^1.8.3",
97
+ "homebridge": "^1.8.4-beta.21",
98
98
  "homebridge-config-ui-x": "4.56.4",
99
99
  "nodemon": "^3.1.4",
100
100
  "npm-check-updates": "^16.14.20",
101
- "rimraf": "^5.0.8",
101
+ "rimraf": "^6.0.0",
102
102
  "ts-node": "^10.9.2",
103
103
  "typescript": "^5.5.3",
104
- "typescript-eslint": "^8.0.0-alpha.39"
104
+ "typescript-eslint": "^8.0.0-alpha.41"
105
105
  }
106
106
  }
@@ -381,7 +381,7 @@ export class BlindTilt extends deviceBase {
381
381
  async refreshStatus(): Promise<void> {
382
382
  if (!this.device.enableCloudService && this.OpenAPI) {
383
383
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
384
- } else if (this.BLE) {
384
+ } else if (this.BLE || this.config.options?.BLE) {
385
385
  await this.BLERefreshStatus();
386
386
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
387
387
  await this.openAPIRefreshStatus();
package/src/device/bot.ts CHANGED
@@ -551,6 +551,7 @@ export class Bot extends deviceBase {
551
551
 
552
552
  // BLEmode (true if Switch Mode) | (false if Press Mode)
553
553
  if (this.serviceData.mode) {
554
+ await this.setOn(this.serviceData.state);
554
555
  this.accessory.context.On = await this.getOn();
555
556
  if (this.getOn() === undefined) {
556
557
  this.setOn(Boolean(this.serviceData.state));
@@ -586,6 +587,7 @@ export class Bot extends deviceBase {
586
587
  this.setOn(false);
587
588
  this.accessory.context.On = await this.getOn();
588
589
  } else {
590
+ this.setOn(this.deviceStatus.power === 'on' ? true : false);
589
591
  this.accessory.context.On = await this.getOn();
590
592
  if (this.getOn() === undefined) {
591
593
  this.setOn(false);
@@ -276,7 +276,7 @@ export class CeilingLight extends deviceBase {
276
276
  async refreshStatus(): Promise<void> {
277
277
  if (!this.device.enableCloudService && this.OpenAPI) {
278
278
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
279
- } else if (this.BLE) {
279
+ } else if (this.BLE || this.config.options?.BLE) {
280
280
  await this.BLERefreshStatus();
281
281
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
282
282
  await this.openAPIRefreshStatus();
@@ -297,7 +297,7 @@ export class ColorBulb extends deviceBase {
297
297
  async refreshStatus(): Promise<void> {
298
298
  if (!this.device.enableCloudService && this.OpenAPI) {
299
299
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
300
- } else if (this.BLE) {
300
+ } else if (this.BLE || this.config.options?.BLE) {
301
301
  await this.BLERefreshStatus();
302
302
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
303
303
  await this.openAPIRefreshStatus();
@@ -287,7 +287,7 @@ export class Contact extends deviceBase {
287
287
  async refreshStatus(): Promise<void> {
288
288
  if (!this.device.enableCloudService && this.OpenAPI) {
289
289
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
290
- } else if (this.BLE) {
290
+ } else if (this.BLE || this.config.options?.BLE) {
291
291
  await this.BLERefreshStatus();
292
292
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
293
293
  await this.openAPIRefreshStatus();
@@ -425,7 +425,7 @@ export class Curtain extends deviceBase {
425
425
  async refreshStatus(): Promise<void> {
426
426
  if (!this.device.enableCloudService && this.OpenAPI) {
427
427
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
428
- } else if (this.BLE) {
428
+ } else if (this.BLE || this.config.options?.BLE) {
429
429
  await this.BLERefreshStatus();
430
430
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
431
431
  await this.openAPIRefreshStatus();
@@ -437,26 +437,41 @@ export class Curtain extends deviceBase {
437
437
 
438
438
  async BLERefreshStatus(): Promise<void> {
439
439
  await this.debugLog('BLERefreshStatus');
440
- const switchbot = await this.switchbotBLE();
441
-
442
- if (switchbot === undefined) {
443
- await this.BLERefreshConnection(switchbot);
444
- } else {
445
- // Start to monitor advertisement packets
446
- (async () => {
447
- // Start to monitor advertisement packets
448
- const serviceData = await this.monitorAdvertisementPackets(switchbot) as curtainServiceData | curtain3ServiceData;
449
- // Update HomeKit
450
- if ((serviceData.model === SwitchBotBLEModel.Curtain || SwitchBotBLEModel.Curtain3)
451
- && (serviceData.modelName === SwitchBotBLEModelName.Curtain || SwitchBotBLEModelName.Curtain3)) {
452
- this.serviceData = serviceData;
453
- await this.BLEparseStatus();
440
+ if (this.config.options?.BLE) {
441
+ await this.debugLog('is listening to BLE.');
442
+ this.platform.bleEventHandler[this.device.deviceId] = async (context: curtainServiceData | curtain3ServiceData) => {
443
+ try {
444
+ await this.debugLog(`received Webhook: ${JSON.stringify(context)}`);
445
+ this.serviceData = context;
446
+ await this.parseStatusWebhook();
454
447
  await this.updateHomeKitCharacteristics();
455
- } else {
456
- await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`);
457
- await this.BLERefreshConnection(switchbot);
448
+ } catch (e: any) {
449
+ await this.errorLog(`failed to handle BLE. Received: ${JSON.stringify(context)} Error: ${e}`);
458
450
  }
459
- })();
451
+ };
452
+ } else {
453
+ await this.debugLog('is not listening to BLE.');
454
+ const switchbot = await this.switchbotBLE();
455
+
456
+ if (switchbot === undefined) {
457
+ await this.BLERefreshConnection(switchbot);
458
+ } else {
459
+ // Start to monitor advertisement packets
460
+ (async () => {
461
+ // Start to monitor advertisement packets
462
+ const serviceData = await this.monitorAdvertisementPackets(switchbot) as curtainServiceData | curtain3ServiceData;
463
+ // Update HomeKit
464
+ if ((serviceData.model === SwitchBotBLEModel.Curtain || SwitchBotBLEModel.Curtain3)
465
+ && (serviceData.modelName === SwitchBotBLEModelName.Curtain || SwitchBotBLEModelName.Curtain3)) {
466
+ this.serviceData = serviceData;
467
+ await this.BLEparseStatus();
468
+ await this.updateHomeKitCharacteristics();
469
+ } else {
470
+ await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`);
471
+ await this.BLERefreshConnection(switchbot);
472
+ }
473
+ })();
474
+ }
460
475
  }
461
476
  }
462
477
 
@@ -355,16 +355,15 @@ export abstract class deviceBase {
355
355
  .deviceId!.match(/.{1,2}/g)!
356
356
  .join(':')
357
357
  .toLowerCase();
358
- this.debugLog(`BLE Address: ${this.device.bleMac}`);
358
+ await this.debugLog(`BLE Address: ${this.device.bleMac}`);
359
359
  }
360
360
 
361
361
  async monitorAdvertisementPackets(switchbot: any) {
362
- this.debugLog(`Scanning for ${this.device.bleModelName} devices...`);
362
+ await this.debugLog(`Scanning for ${this.device.bleModelName} devices...`);
363
363
  await switchbot.startScan({ model: this.device.bleModel, id: this.device.bleMac });
364
364
  // Set an event handler
365
365
  let serviceData = { model: this.device.bleModel, modelName: this.device.bleModelName } as ad['serviceData'];
366
366
  switchbot.onadvertisement = async (ad: ad) => {
367
- this.warnLog(`ad: ${JSON.stringify(ad, null, ' ')}`);
368
367
  if (this.device.bleMac === ad.address && ad.serviceData.model === this.device.bleModel) {
369
368
  this.debugLog(`${JSON.stringify(ad, null, ' ')}`);
370
369
  this.debugLog(`address: ${ad.address}, model: ${ad.serviceData.model}`);
@@ -830,4 +829,4 @@ export abstract class deviceBase {
830
829
  async enablingDeviceLogging(): Promise<boolean> {
831
830
  return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
832
831
  }
833
- }
832
+ }
package/src/device/fan.ts CHANGED
@@ -314,7 +314,7 @@ export class Fan extends deviceBase {
314
314
  async refreshStatus(): Promise<void> {
315
315
  if (!this.device.enableCloudService && this.OpenAPI) {
316
316
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
317
- } else if (this.BLE) {
317
+ } else if (this.BLE || this.config.options?.BLE) {
318
318
  await this.BLERefreshStatus();
319
319
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
320
320
  await this.openAPIRefreshStatus();
package/src/device/hub.ts CHANGED
@@ -278,7 +278,7 @@ export class Hub extends deviceBase {
278
278
  async refreshStatus(): Promise<void> {
279
279
  if (!this.device.enableCloudService && this.OpenAPI) {
280
280
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
281
- } else if (this.BLE) {
281
+ } else if (this.BLE || this.config.options?.BLE) {
282
282
  await this.BLERefreshStatus();
283
283
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
284
284
  await this.openAPIRefreshStatus();
@@ -318,7 +318,7 @@ export class Humidifier extends deviceBase {
318
318
  async refreshStatus(): Promise<void> {
319
319
  if (!this.device.enableCloudService && this.OpenAPI) {
320
320
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
321
- } else if (this.BLE) {
321
+ } else if (this.BLE || this.config.options?.BLE) {
322
322
  await this.BLERefreshStatus();
323
323
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
324
324
  await this.openAPIRefreshStatus();
@@ -271,7 +271,7 @@ export class IOSensor extends deviceBase {
271
271
  async refreshStatus(): Promise<void> {
272
272
  if (!this.device.enableCloudService && this.OpenAPI) {
273
273
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
274
- } else if (this.BLE) {
274
+ } else if (this.BLE || this.config.options?.BLE) {
275
275
  await this.BLERefreshStatus();
276
276
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
277
277
  await this.openAPIRefreshStatus();
@@ -301,7 +301,7 @@ export class StripLight extends deviceBase {
301
301
  async refreshStatus(): Promise<void> {
302
302
  if (!this.device.enableCloudService && this.OpenAPI) {
303
303
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
304
- } else if (this.BLE) {
304
+ } else if (this.BLE || this.config.options?.BLE) {
305
305
  await this.BLERefreshStatus();
306
306
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
307
307
  await this.openAPIRefreshStatus();
@@ -297,7 +297,7 @@ export class Lock extends deviceBase {
297
297
  async refreshStatus(): Promise<void> {
298
298
  if (!this.device.enableCloudService && this.OpenAPI) {
299
299
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
300
- } else if (this.BLE) {
300
+ } else if (this.BLE || this.config.options?.BLE) {
301
301
  await this.BLERefreshStatus();
302
302
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
303
303
  await this.openAPIRefreshStatus();
@@ -265,7 +265,7 @@ export class Meter extends deviceBase {
265
265
  async refreshStatus(): Promise<void> {
266
266
  if (!this.device.enableCloudService && this.OpenAPI) {
267
267
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
268
- } else if (this.BLE) {
268
+ } else if (this.BLE || this.config.options?.BLE) {
269
269
  await this.BLERefreshStatus();
270
270
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
271
271
  await this.openAPIRefreshStatus();
@@ -266,7 +266,7 @@ export class MeterPlus extends deviceBase {
266
266
  async refreshStatus(): Promise<void> {
267
267
  if (!this.device.enableCloudService && this.OpenAPI) {
268
268
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
269
- } else if (this.BLE) {
269
+ } else if (this.BLE || this.config.options?.BLE) {
270
270
  await this.BLERefreshStatus();
271
271
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
272
272
  await this.openAPIRefreshStatus();
@@ -237,7 +237,7 @@ export class Motion extends deviceBase {
237
237
  async refreshStatus(): Promise<void> {
238
238
  if (!this.device.enableCloudService && this.OpenAPI) {
239
239
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
240
- } else if (this.BLE) {
240
+ } else if (this.BLE || this.config.options?.BLE) {
241
241
  await this.BLERefreshStatus();
242
242
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
243
243
  await this.openAPIRefreshStatus();
@@ -148,7 +148,7 @@ export class Plug extends deviceBase {
148
148
  async refreshStatus(): Promise<void> {
149
149
  if (!this.device.enableCloudService && this.OpenAPI) {
150
150
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
151
- } else if (this.BLE) {
151
+ } else if (this.BLE || this.config.options?.BLE) {
152
152
  await this.BLERefreshStatus();
153
153
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
154
154
  await this.openAPIRefreshStatus();
@@ -249,7 +249,7 @@ export class RobotVacuumCleaner extends deviceBase {
249
249
  async refreshStatus(): Promise<void> {
250
250
  if (!this.device.enableCloudService && this.OpenAPI) {
251
251
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
252
- } else if (this.BLE) {
252
+ } else if (this.BLE || this.config.options?.BLE) {
253
253
  await this.BLERefreshStatus();
254
254
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
255
255
  await this.openAPIRefreshStatus();
@@ -234,7 +234,7 @@ export class WaterDetector extends deviceBase {
234
234
  async refreshStatus(): Promise<void> {
235
235
  if (!this.device.enableCloudService && this.OpenAPI) {
236
236
  await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`);
237
- } else if (this.BLE) {
237
+ } else if (this.BLE || this.config.options?.BLE) {
238
238
  await this.BLERefreshStatus();
239
239
  } else if (this.OpenAPI && this.platform.config.credentials?.token) {
240
240
  await this.openAPIRefreshStatus();
package/src/platform.ts CHANGED
@@ -78,6 +78,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
78
78
  public readonly eve: any;
79
79
  public readonly fakegatoAPI: any;
80
80
  public readonly webhookEventHandler: { [x: string]: (context: any) => void } = {};
81
+ public readonly bleEventHandler: { [x: string]: (context: any) => void } = {};
81
82
 
82
83
  constructor(
83
84
  log: Logging,
@@ -148,6 +149,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
148
149
 
149
150
  this.setupMqtt();
150
151
  this.setupwebhook();
152
+ this.setupBlE();
151
153
  }
152
154
 
153
155
  async setupMqtt(): Promise<void> {
@@ -312,6 +314,34 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
312
314
  }
313
315
  }
314
316
 
317
+ async setupBlE() {
318
+ if (this.config.options?.BLE) {
319
+ await this.debugLog('setupBLE');
320
+ const SwitchBot = (await import('node-switchbot')).SwitchBot;
321
+ const switchbot = new SwitchBot();
322
+ if (switchbot === undefined) {
323
+ await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
324
+ } else {
325
+ // Start to monitor advertisement packets
326
+ (async () => {
327
+ // Start to monitor advertisement packets
328
+ await this.debugLog('Scanning for BLE SwitchBot devices...');
329
+ await switchbot.startScan();
330
+ // Set an event handler to monitor advertisement packets
331
+ switchbot.onadvertisement = async (ad: any) => {
332
+ try {
333
+ this.bleEventHandler[ad.id]?.(ad);
334
+ } catch (e: any) {
335
+ this.errorLog(`Failed to handle BLE event. Error:${e}`);
336
+ }
337
+ };
338
+ })();
339
+ }
340
+ } else {
341
+ await this.debugLog('Platform BLE is not enabled');
342
+ }
343
+ }
344
+
315
345
  /**
316
346
  * This function is invoked when homebridge restores cached accessories from disk at startup.
317
347
  * It should be used to setup event handlers for characteristics and update respective values.
package/src/settings.ts CHANGED
@@ -61,6 +61,7 @@ interface options {
61
61
  mqttURL?: string;
62
62
  mqttOptions?: IClientOptions;
63
63
  mqttPubOptions?: IClientOptions;
64
+ BLE?: boolean;
64
65
  webhookURL?: string;
65
66
  maxRetries?: number;
66
67
  delayBetweenRetries?: number;