@switchbot/homebridge-switchbot 5.0.0-beta.13 → 5.0.0-beta.15

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.
@@ -16,6 +16,17 @@ export declare class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
16
16
  private switchBotBLE?;
17
17
  private discoveredDevices;
18
18
  private bleEventHandler;
19
+ private platformLogging?;
20
+ infoLog: (...args: any[]) => void;
21
+ successLog: (...args: any[]) => void;
22
+ debugSuccessLog: (...args: any[]) => void;
23
+ warnLog: (...args: any[]) => void;
24
+ debugWarnLog: (...args: any[]) => void;
25
+ errorLog: (...args: any[]) => void;
26
+ debugErrorLog: (...args: any[]) => void;
27
+ debugLog: (...args: any[]) => void;
28
+ loggingIsDebug: () => Promise<boolean>;
29
+ enablingPlatformLogging: () => Promise<boolean>;
19
30
  constructor(log: Logging, config: SwitchBotPlatformConfig, api: API);
20
31
  /**
21
32
  * Normalize a deviceId for matching (uppercase alphanumerics only)
@@ -1 +1 @@
1
- {"version":3,"file":"platform-matter.d.ts","sourceRoot":"","sources":["../src/platform-matter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,GAAG,EACH,qBAAqB,EACrB,OAAO,EAEP,yBAAyB,EAC1B,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAExD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AA8B5D;;;;;GAKG;AACH,qBAAa,uBAAwB,YAAW,qBAAqB;aAgBjD,GAAG,EAAE,OAAO;aACZ,MAAM,EAAE,uBAAuB;aAC/B,GAAG,EAAE,GAAG;IAZ1B,SAAgB,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAY;IAErF,OAAO,CAAC,YAAY,CAAC,CAAkB;IACvC,OAAO,CAAC,YAAY,CAAC,CAAc;IAEnC,OAAO,CAAC,iBAAiB,CAAe;IAExC,OAAO,CAAC,eAAe,CAA8C;gBAGnD,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,uBAAuB,EAC/B,GAAG,EAAE,GAAG;IA4F1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAOvB;;;OAGG;YACW,sBAAsB;IAsCpC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAW5B;;;OAGG;YACW,yBAAyB;IAqXvC;;OAEG;YACW,eAAe;IAwB7B;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,SAAI,EAAE,mBAAmB,SAAO,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,GAAG,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IA0BzJ;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAwDnC;;;OAGG;IACH,kBAAkB;IAMlB;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,yBAAyB;IAK7D;;OAEG;YACW,yBAAyB;IAoDvC;;OAEG;YACW,yBAAyB;IAqCvC;;OAEG;YACW,wBAAwB;IA8CtC;;OAEG;YACW,0BAA0B;IAsBxC;;OAEG;YACW,wBAAwB;IAsBtC;;OAEG;YACW,uBAAuB;IA0DrC;;OAEG;YACW,uBAAuB;IAkCrC;;OAEG;YACW,oBAAoB;IA4BlC;;;;;OAKG;YACW,wBAAwB;IAsBtC;;;;;;OAMG;YACW,qBAAqB;CAqBpC"}
1
+ {"version":3,"file":"platform-matter.d.ts","sourceRoot":"","sources":["../src/platform-matter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,GAAG,EACH,qBAAqB,EACrB,OAAO,EAEP,yBAAyB,EAC1B,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAExD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AA8B5D;;;;;GAKG;AACH,qBAAa,uBAAwB,YAAW,qBAAqB;aA8BjD,GAAG,EAAE,OAAO;aACZ,MAAM,EAAE,uBAAuB;aAC/B,GAAG,EAAE,GAAG;IA1B1B,SAAgB,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAY;IAErF,OAAO,CAAC,YAAY,CAAC,CAAkB;IACvC,OAAO,CAAC,YAAY,CAAC,CAAc;IAEnC,OAAO,CAAC,iBAAiB,CAAe;IAExC,OAAO,CAAC,eAAe,CAA8C;IAErE,OAAO,CAAC,eAAe,CAAC,CAAS;IAGjC,OAAO,EAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAClC,UAAU,EAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IACrC,eAAe,EAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC1C,OAAO,EAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAClC,YAAY,EAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IACvC,QAAQ,EAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IACnC,aAAa,EAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IACxC,QAAQ,EAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IACnC,cAAc,EAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IACvC,uBAAuB,EAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;gBAG9B,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,uBAAuB,EAC/B,GAAG,EAAE,GAAG;IA0G1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAOvB;;;OAGG;YACW,sBAAsB;IAsCpC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAW5B;;;OAGG;YACW,yBAAyB;IA8VvC;;OAEG;YACW,eAAe;IAwB7B;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,SAAI,EAAE,mBAAmB,SAAO,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,GAAG,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IA0BzJ;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAwDnC;;;OAGG;IACH,kBAAkB;IAMlB;;;;;OAKG;IACH,wBAAwB,CAAC,SAAS,EAAE,yBAAyB;IAK7D;;OAEG;YACW,yBAAyB;IAoDvC;;OAEG;YACW,yBAAyB;IAqCvC;;OAEG;YACW,wBAAwB;IA8CtC;;OAEG;YACW,0BAA0B;IAsBxC;;OAEG;YACW,wBAAwB;IAsBtC;;OAEG;YACW,uBAAuB;IA0DrC;;OAEG;YACW,uBAAuB;IAkCrC;;OAEG;YACW,oBAAoB;IA4BlC;;;;;OAKG;YACW,wBAAwB;IAsBtC;;;;;;OAMG;YACW,qBAAqB;CAqBpC"}
@@ -1,7 +1,7 @@
1
1
  import { SwitchBotBLE, SwitchBotOpenAPI } from 'node-switchbot';
2
2
  import { ColorLightAccessory, ColorTemperatureLightAccessory, ContactSensorAccessory, DimmableLightAccessory, DoorLockAccessory, ExtendedColorLightAccessory, FanAccessory, HumiditySensorAccessory, LeakSensorAccessory, LightSensorAccessory, OccupancySensorAccessory, OnOffLightAccessory, OnOffOutletAccessory, OnOffSwitchAccessory, PowerStripAccessory, RoboticVacuumAccessory, SmokeCOAlarmAccessory, TemperatureSensorAccessory, ThermostatAccessory, VenetianBlindAccessory, WindowBlindAccessory, } from './devices-matter/index.js';
3
3
  import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
4
- import { cleanDeviceConfig, formatDeviceIdAsMac, hs2rgb, rgb2hs, sleep } from './utils.js';
4
+ import { cleanDeviceConfig, createPlatformLogger, formatDeviceIdAsMac, hs2rgb, makeBLESender, makeOpenAPISender, rgb2hs, sleep } from './utils.js';
5
5
  /**
6
6
  * MatterPlatform
7
7
  * Demonstrates all available Matter device types in Homebridge
@@ -24,11 +24,37 @@ export class SwitchBotMatterPlatform {
24
24
  discoveredDevices = [];
25
25
  // BLE event handlers keyed by device MAC (formatted)
26
26
  bleEventHandler = {};
27
+ // Platform logging toggle (can be controlled via UI or config)
28
+ platformLogging;
29
+ // Platform-provided logging helpers (attached in constructor)
30
+ infoLog;
31
+ successLog;
32
+ debugSuccessLog;
33
+ warnLog;
34
+ debugWarnLog;
35
+ errorLog;
36
+ debugErrorLog;
37
+ debugLog;
38
+ loggingIsDebug;
39
+ enablingPlatformLogging;
27
40
  constructor(log, config, api) {
28
41
  this.log = log;
29
42
  this.config = config;
30
43
  this.api = api;
31
- this.log.debug('Finished initializing platform:', this.config.name);
44
+ // Attach platform-wide logging helpers from utils so Matter and device
45
+ // classes can use consistent logging methods (infoLog/debugLog/etc.)
46
+ const _pl = createPlatformLogger(async () => this.platformLogging, this.log);
47
+ this.infoLog = _pl.infoLog;
48
+ this.successLog = _pl.successLog;
49
+ this.debugSuccessLog = _pl.debugSuccessLog;
50
+ this.warnLog = _pl.warnLog;
51
+ this.debugWarnLog = _pl.debugWarnLog;
52
+ this.errorLog = _pl.errorLog;
53
+ this.debugErrorLog = _pl.debugErrorLog;
54
+ this.debugLog = _pl.debugLog;
55
+ this.loggingIsDebug = _pl.loggingIsDebug;
56
+ this.enablingPlatformLogging = _pl.enablingPlatformLogging;
57
+ this.debugLog('Finished initializing platform:', this.config.name);
32
58
  // Normalize deviceConfig to remove UI-inserted defaults
33
59
  try {
34
60
  if (this.config.options) {
@@ -43,11 +69,11 @@ export class SwitchBotMatterPlatform {
43
69
  }
44
70
  }
45
71
  catch (e) {
46
- this.log.debug('Failed to clean deviceConfig: %s', e);
72
+ this.debugLog('Failed to clean deviceConfig: %s', e);
47
73
  }
48
74
  // Does the user have a version of Homebridge that is compatible with matter?
49
75
  if (!this.api.isMatterAvailable?.()) {
50
- this.log.warn('Matter is not available in this version of Homebridge. Please update Homebridge to use this plugin.');
76
+ this.warnLog('Matter is not available in this version of Homebridge. Please update Homebridge to use this plugin.');
51
77
  }
52
78
  // Check if the user has matter enabled, this means:
53
79
  // - If the plugin is running on the main bridge, then the user must have enabled matter in the Homebridge settings page in the UI
@@ -55,36 +81,36 @@ export class SwitchBotMatterPlatform {
55
81
  // In reality, only the below check is needed, but they are both included here for completeness
56
82
  // Remember to use a '?.' optional chaining operator in case the user is running an older version of Homebridge that does not have these APIs
57
83
  if (!this.api.isMatterEnabled?.()) {
58
- this.log.warn('Matter is not enabled in Homebridge. Please enable Matter in the Homebridge settings to use this plugin.');
84
+ this.warnLog('Matter is not enabled in Homebridge. Please enable Matter in the Homebridge settings to use this plugin.');
59
85
  return;
60
86
  }
61
87
  // Register Matter accessories when Homebridge has finished launching
62
88
  this.api.on('didFinishLaunching', () => {
63
- this.log.debug('Executed didFinishLaunching callback');
89
+ this.debugLog('Executed didFinishLaunching callback');
64
90
  // Initialize SwitchBot API clients
65
91
  try {
66
92
  if (this.config.credentials?.token && this.config.credentials?.secret) {
67
93
  this.switchBotAPI = new SwitchBotOpenAPI(this.config.credentials.token, this.config.credentials.secret, this.config.options?.hostname);
68
94
  // forward basic logs
69
95
  if (!this.config.options?.disableLogsforOpenAPI && this.switchBotAPI?.on) {
70
- this.switchBotAPI.on('log', (l) => this.log.debug('[SwitchBot OpenAPI]', l.message));
96
+ this.switchBotAPI.on('log', (l) => this.debugLog('[SwitchBot OpenAPI]', l.message));
71
97
  }
72
98
  }
73
99
  else {
74
- this.log.debug('SwitchBot OpenAPI credentials not provided; cloud devices will be skipped');
100
+ this.debugLog('SwitchBot OpenAPI credentials not provided; cloud devices will be skipped');
75
101
  }
76
102
  }
77
103
  catch (e) {
78
- this.log.error('Failed to initialize SwitchBot OpenAPI:', e?.message ?? e);
104
+ this.errorLog('Failed to initialize SwitchBot OpenAPI:', e?.message ?? e);
79
105
  }
80
106
  try {
81
107
  this.switchBotBLE = new SwitchBotBLE();
82
108
  if (!this.config.options?.disableLogsforBLE && this.switchBotBLE?.on) {
83
- this.switchBotBLE.on('log', (l) => this.log.debug('[SwitchBot BLE]', l.message));
109
+ this.switchBotBLE.on('log', (l) => this.debugLog('[SwitchBot BLE]', l.message));
84
110
  }
85
111
  }
86
112
  catch (e) {
87
- this.log.error('Failed to initialize SwitchBot BLE client:', e?.message ?? e);
113
+ this.errorLog('Failed to initialize SwitchBot BLE client:', e?.message ?? e);
88
114
  }
89
115
  // If BLE scanning is enabled, start scanning and route advertisements to registered handlers
90
116
  if (this.config.options?.BLE && this.switchBotBLE) {
@@ -94,7 +120,7 @@ export class SwitchBotMatterPlatform {
94
120
  await ble.startScan();
95
121
  }
96
122
  catch (e) {
97
- this.log.error(`Failed to start BLE scanning: ${e?.message ?? e}`);
123
+ this.errorLog(`Failed to start BLE scanning: ${e?.message ?? e}`);
98
124
  }
99
125
  // route advertisements to our handlers
100
126
  ble.onadvertisement = async (ad) => {
@@ -106,7 +132,7 @@ export class SwitchBotMatterPlatform {
106
132
  }
107
133
  }
108
134
  catch (e) {
109
- this.log.error(`Failed to handle BLE advertisement: ${e?.message ?? e}`);
135
+ this.errorLog(`Failed to handle BLE advertisement: ${e?.message ?? e}`);
110
136
  }
111
137
  };
112
138
  })();
@@ -145,7 +171,7 @@ export class SwitchBotMatterPlatform {
145
171
  const devicesWithTypeConfig = await Promise.all(discovered.map(async (deviceObj) => {
146
172
  if (!deviceObj.deviceType) {
147
173
  deviceObj.deviceType = deviceObj.configDeviceType !== undefined ? deviceObj.configDeviceType : 'Unknown';
148
- this.log.debug(`API missing deviceType for ${deviceObj.deviceId}, using configDeviceType: ${deviceObj.configDeviceType}`);
174
+ this.debugLog(`API missing deviceType for ${deviceObj.deviceId}, using configDeviceType: ${deviceObj.configDeviceType}`);
149
175
  }
150
176
  const deviceTypeConfig = this.config.options?.deviceConfig?.[deviceObj.deviceType] || {};
151
177
  return Object.assign({}, deviceObj, deviceTypeConfig);
@@ -210,45 +236,9 @@ export class SwitchBotMatterPlatform {
210
236
  deviceId: dev.deviceId,
211
237
  },
212
238
  };
213
- // Small helper to wrap common OpenAPI on/off commands
214
- // Helper to send an OpenAPI command
215
- const sendOpenAPI = async (command, parameter = 'default') => {
216
- const bodyChange = { command, parameter, commandType: 'command' };
217
- return this.retryCommand(dev, bodyChange, this.config.options?.maxRetries ?? 1, this.config.options?.delayBetweenRetries ?? 1000);
218
- };
219
- // Helper to send a BLE action if Platform BLE is enabled and switchBotBLE exists
220
- const sendBLE = async (methodName, ...args) => {
221
- // Provide a small retry loop for flaky BLE operations
222
- if (!this.switchBotBLE) {
223
- throw new Error('Platform BLE not available');
224
- }
225
- const id = formatDeviceIdAsMac(dev.deviceId);
226
- const maxRetries = this.config.options?.bleRetries ?? 2;
227
- const retryDelay = this.config.options?.bleRetryDelay ?? 500;
228
- let attempt = 0;
229
- while (attempt < maxRetries) {
230
- try {
231
- const list = await this.switchBotBLE.discover({ model: dev.bleModel, id });
232
- if (!Array.isArray(list) || list.length === 0) {
233
- throw new Error('BLE device not found');
234
- }
235
- const deviceInst = list[0];
236
- if (typeof deviceInst[methodName] !== 'function') {
237
- throw new TypeError(`BLE method ${methodName} not available on device`);
238
- }
239
- return await deviceInst[methodName](...args);
240
- }
241
- catch (e) {
242
- attempt++;
243
- if (attempt >= maxRetries) {
244
- throw e;
245
- }
246
- this.log.debug(`BLE ${methodName} attempt ${attempt} failed for ${dev.deviceId}: ${e?.message ?? e}, retrying in ${retryDelay}ms`);
247
- await sleep(retryDelay);
248
- }
249
- }
250
- throw new Error('BLE operation failed');
251
- };
239
+ // Build platform-side helpers using shared factories so they can be reused/tested
240
+ const sendOpenAPI = makeOpenAPISender(this.retryCommand.bind(this), dev, { maxRetries: this.config.options?.maxRetries ?? 1, delayBetweenRetries: this.config.options?.delayBetweenRetries ?? 1000 });
241
+ const sendBLE = makeBLESender(this.switchBotBLE, dev, { bleRetries: this.config.options?.bleRetries ?? 2, bleRetryDelay: this.config.options?.bleRetryDelay ?? 500 });
252
242
  const makeOnOffHandlers = (uuid, connectionType) => ({
253
243
  onOff: {
254
244
  on: async () => {
@@ -262,7 +252,7 @@ export class SwitchBotMatterPlatform {
262
252
  await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.OnOff, { onOff: true });
263
253
  }
264
254
  catch (e) {
265
- this.log.error(`Failed to turn on device ${dev.deviceId}: ${e?.message ?? e}`);
255
+ this.errorLog(`Failed to turn on device ${dev.deviceId}: ${e?.message ?? e}`);
266
256
  }
267
257
  },
268
258
  off: async () => {
@@ -276,7 +266,7 @@ export class SwitchBotMatterPlatform {
276
266
  await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.OnOff, { onOff: false });
277
267
  }
278
268
  catch (e) {
279
- this.log.error(`Failed to turn off device ${dev.deviceId}: ${e?.message ?? e}`);
269
+ this.errorLog(`Failed to turn off device ${dev.deviceId}: ${e?.message ?? e}`);
280
270
  }
281
271
  },
282
272
  },
@@ -354,7 +344,7 @@ export class SwitchBotMatterPlatform {
354
344
  };
355
345
  const Ctor = mapping[dev.deviceType ?? ''];
356
346
  if (!Ctor) {
357
- this.log.debug(`No Matter mapping for deviceType='${dev.deviceType}', deviceId=${dev.deviceId}`);
347
+ this.debugLog(`No Matter mapping for deviceType='${dev.deviceType}', deviceId=${dev.deviceId}`);
358
348
  return undefined;
359
349
  }
360
350
  // Build opts and handlers tailored for basic capabilities
@@ -381,7 +371,7 @@ export class SwitchBotMatterPlatform {
381
371
  await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.LevelControl, { currentLevel: level });
382
372
  }
383
373
  catch (e) {
384
- this.log.error(`Failed to set brightness for ${dev.deviceId}: ${e?.message ?? e}`);
374
+ this.errorLog(`Failed to set brightness for ${dev.deviceId}: ${e?.message ?? e}`);
385
375
  }
386
376
  },
387
377
  };
@@ -401,7 +391,7 @@ export class SwitchBotMatterPlatform {
401
391
  await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.ColorControl, { currentHue: hue, currentSaturation: saturation });
402
392
  }
403
393
  catch (e) {
404
- this.log.error(`Failed to set hue/sat for ${dev.deviceId}: ${e?.message ?? e}`);
394
+ this.errorLog(`Failed to set hue/sat for ${dev.deviceId}: ${e?.message ?? e}`);
405
395
  }
406
396
  },
407
397
  moveToColorLogic: async (request) => {
@@ -422,7 +412,7 @@ export class SwitchBotMatterPlatform {
422
412
  await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.ColorControl, { currentX: colorX, currentY: colorY });
423
413
  }
424
414
  catch (e) {
425
- this.log.error(`Failed to set XY color for ${dev.deviceId}: ${e?.message ?? e}`);
415
+ this.errorLog(`Failed to set XY color for ${dev.deviceId}: ${e?.message ?? e}`);
426
416
  }
427
417
  },
428
418
  };
@@ -440,7 +430,7 @@ export class SwitchBotMatterPlatform {
440
430
  await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.ColorControl, { currentX: request.colorX ?? 0, currentY: request.colorY ?? 0 });
441
431
  }
442
432
  catch (e) {
443
- this.log.error(`Failed to set color temperature for ${dev.deviceId}: ${e?.message ?? e}`);
433
+ this.errorLog(`Failed to set color temperature for ${dev.deviceId}: ${e?.message ?? e}`);
444
434
  }
445
435
  },
446
436
  };
@@ -449,11 +439,24 @@ export class SwitchBotMatterPlatform {
449
439
  // classes can call OpenAPI/BLE actions (sendOpenAPI/sendBLE) and know
450
440
  // the effective connection type.
451
441
  try {
442
+ /* Inject platform helpers (OpenAPI/BLE senders + logging helpers + connection type)
443
+ into the accessory context so Matter accessory classes can use them without
444
+ reaching into the platform implementation directly. */
452
445
  ;
453
- baseOpts.context = Object.assign({}, baseOpts.context, { sendOpenAPI, sendBLE, connectionType });
446
+ baseOpts.context = Object.assign({}, baseOpts.context, {
447
+ sendOpenAPI,
448
+ sendBLE,
449
+ connectionType,
450
+ // Expose platform logging helpers so accessories can use consistent logging
451
+ infoLog: this.infoLog,
452
+ debugLog: this.debugLog,
453
+ warnLog: this.warnLog,
454
+ errorLog: this.errorLog,
455
+ successLog: this.successLog,
456
+ });
454
457
  }
455
458
  catch (e) {
456
- this.log.debug('Failed to attach platform helpers to baseOpts.context: %s', e?.message ?? e);
459
+ this.debugLog('Failed to attach platform helpers to baseOpts.context: %s', e?.message ?? e);
457
460
  }
458
461
  const opts = Object.assign({}, baseOpts, { handlers });
459
462
  // Instantiate the device class and return its serialized accessory
@@ -490,7 +493,7 @@ export class SwitchBotMatterPlatform {
490
493
  }
491
494
  }
492
495
  catch (e) {
493
- this.log.debug(`BLE advertisement parsing failed for ${dev.deviceId}: ${e?.message ?? e}`);
496
+ this.debugLog(`BLE advertisement parsing failed for ${dev.deviceId}: ${e?.message ?? e}`);
494
497
  }
495
498
  // Fallback to OpenAPI getDeviceStatus when serviceData is not present or parsing failed
496
499
  if (!this.switchBotAPI) {
@@ -535,12 +538,12 @@ export class SwitchBotMatterPlatform {
535
538
  }
536
539
  }
537
540
  catch (e) {
538
- this.log.debug(`BLE push handler failed for ${dev.deviceId}: ${e?.message ?? e}`);
541
+ this.debugLog(`BLE push handler failed for ${dev.deviceId}: ${e?.message ?? e}`);
539
542
  }
540
543
  };
541
544
  }
542
545
  catch (e) {
543
- this.log.debug(`Failed to register BLE handler for ${dev.deviceId}: ${e?.message ?? e}`);
546
+ this.debugLog(`Failed to register BLE handler for ${dev.deviceId}: ${e?.message ?? e}`);
544
547
  }
545
548
  return instance.toAccessory();
546
549
  }
@@ -549,26 +552,26 @@ export class SwitchBotMatterPlatform {
549
552
  */
550
553
  async discoverDevices() {
551
554
  if (!this.switchBotAPI) {
552
- this.log.debug('SwitchBot OpenAPI not configured; skipping discovery');
555
+ this.debugLog('SwitchBot OpenAPI not configured; skipping discovery');
553
556
  return;
554
557
  }
555
558
  try {
556
559
  const { response, statusCode } = await this.switchBotAPI.getDevices();
557
- this.log.debug(`SwitchBot getDevices response status: ${statusCode}`);
560
+ this.debugLog(`SwitchBot getDevices response status: ${statusCode}`);
558
561
  if (statusCode === 100 || statusCode === 200) {
559
562
  const deviceList = Array.isArray(response?.body?.deviceList) ? response.body.deviceList : [];
560
563
  this.discoveredDevices = deviceList;
561
- this.log.info(`Discovered ${deviceList.length} SwitchBot device(s) from OpenAPI`);
564
+ this.infoLog(`Discovered ${deviceList.length} SwitchBot device(s) from OpenAPI`);
562
565
  for (const d of deviceList) {
563
- this.log.debug(` - ${d.deviceName} (${d.deviceType}) id=${d.deviceId}`);
566
+ this.debugLog(` - ${d.deviceName} (${d.deviceType}) id=${d.deviceId}`);
564
567
  }
565
568
  }
566
569
  else {
567
- this.log.warn(`SwitchBot getDevices returned status ${statusCode}`);
570
+ this.warnLog(`SwitchBot getDevices returned status ${statusCode}`);
568
571
  }
569
572
  }
570
573
  catch (e) {
571
- this.log.error('Failed to discover SwitchBot devices:', e?.message ?? e);
574
+ this.errorLog('Failed to discover SwitchBot devices:', e?.message ?? e);
572
575
  }
573
576
  }
574
577
  /**
@@ -585,7 +588,7 @@ export class SwitchBotMatterPlatform {
585
588
  return { response, statusCode };
586
589
  }
587
590
  catch (e) {
588
- this.log.debug(`retryCommand error: ${e?.message ?? e}`);
591
+ this.debugLog(`retryCommand error: ${e?.message ?? e}`);
589
592
  }
590
593
  retryCount++;
591
594
  await sleep(delayBetweenRetries);
@@ -645,7 +648,7 @@ export class SwitchBotMatterPlatform {
645
648
  return result;
646
649
  }
647
650
  catch (e) {
648
- this.log.debug(`parseAdvertisementForDevice failed for ${dev.deviceId}: ${e?.message ?? e}`);
651
+ this.debugLog(`parseAdvertisementForDevice failed for ${dev.deviceId}: ${e?.message ?? e}`);
649
652
  return null;
650
653
  }
651
654
  }
@@ -665,21 +668,21 @@ export class SwitchBotMatterPlatform {
665
668
  * any custom data you stored when the accessory was originally registered.
666
669
  */
667
670
  configureMatterAccessory(accessory) {
668
- this.log.debug('Loading cached Matter accessory:', accessory.displayName);
671
+ this.debugLog('Loading cached Matter accessory:', accessory.displayName);
669
672
  this.matterAccessories.set(accessory.uuid, accessory);
670
673
  }
671
674
  /**
672
675
  * Register all Matter accessories
673
676
  */
674
677
  async registerMatterAccessories() {
675
- this.log.debug('═'.repeat(80));
676
- this.log.info('Homebridge Matter Plugin');
677
- this.log.debug('═'.repeat(80));
678
+ this.debugLog('═'.repeat(80));
679
+ this.infoLog('Homebridge Matter Plugin');
680
+ this.debugLog('═'.repeat(80));
678
681
  // Remove accessories that are disabled in config
679
682
  await this.removeDisabledAccessories();
680
683
  // If we discovered real SwitchBot devices via OpenAPI, map and register them
681
684
  if (this.discoveredDevices && this.discoveredDevices.length > 0) {
682
- this.log.info(`Registering ${this.discoveredDevices.length} discovered SwitchBot device(s) as Matter accessories`);
685
+ this.infoLog(`Registering ${this.discoveredDevices.length} discovered SwitchBot device(s) as Matter accessories`);
683
686
  const accessories = [];
684
687
  // Merge device config (deviceConfig per deviceType and per-device overrides) to match HAP behavior
685
688
  const devicesToProcess = await this.mergeDiscoveredDevices(this.discoveredDevices);
@@ -691,18 +694,18 @@ export class SwitchBotMatterPlatform {
691
694
  }
692
695
  }
693
696
  catch (e) {
694
- this.log.error(`Failed to create Matter accessory for ${dev.deviceId}: ${e?.message ?? e}`);
697
+ this.errorLog(`Failed to create Matter accessory for ${dev.deviceId}: ${e?.message ?? e}`);
695
698
  }
696
699
  }
697
700
  if (accessories.length > 0) {
698
- this.log.info(`✓ Registered ${accessories.length} discovered device(s)`);
701
+ this.infoLog(`✓ Registered ${accessories.length} discovered device(s)`);
699
702
  for (const acc of accessories) {
700
- this.log.info(` - ${acc.displayName}`);
703
+ this.infoLog(` - ${acc.displayName}`);
701
704
  }
702
705
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
703
706
  return;
704
707
  }
705
- this.log.info('No discovered devices were mapped to Matter accessories; falling back to example sections');
708
+ this.infoLog('No discovered devices were mapped to Matter accessories; falling back to example sections');
706
709
  }
707
710
  // Register example/demo devices by Matter specification sections
708
711
  await this.registerSection4Lighting();
@@ -713,9 +716,9 @@ export class SwitchBotMatterPlatform {
713
716
  await this.registerSection9HVAC();
714
717
  await this.registerSection12Robotic();
715
718
  await this.registerCustomDevices();
716
- this.log.debug('═'.repeat(80));
717
- this.log.debug('Finished registering Matter accessories');
718
- this.log.debug('═'.repeat(80));
719
+ this.debugLog('═'.repeat(80));
720
+ this.debugLog('Finished registering Matter accessories');
721
+ this.debugLog('═'.repeat(80));
719
722
  }
720
723
  /**
721
724
  * Remove accessories that are disabled in config
@@ -748,7 +751,7 @@ export class SwitchBotMatterPlatform {
748
751
  if (enabled === false) {
749
752
  const existingAccessory = this.matterAccessories.get(uuid);
750
753
  if (existingAccessory) {
751
- this.log.info(`Removing accessory '${name}' (disabled in config)`);
754
+ this.infoLog(`Removing accessory '${name}' (disabled in config)`);
752
755
  await this.api.matter.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
753
756
  this.matterAccessories.delete(uuid);
754
757
  }
@@ -759,9 +762,9 @@ export class SwitchBotMatterPlatform {
759
762
  * Section 4: Lighting Devices (Matter Spec § 4)
760
763
  */
761
764
  async registerSection4Lighting() {
762
- this.log.debug('═'.repeat(80));
763
- this.log.info('Section 4: Lighting Devices (Matter Spec § 4)');
764
- this.log.debug('═'.repeat(80));
765
+ this.debugLog('═'.repeat(80));
766
+ this.infoLog('Section 4: Lighting Devices (Matter Spec § 4)');
767
+ this.debugLog('═'.repeat(80));
765
768
  const accessories = [];
766
769
  // On/Off Light
767
770
  if (this.config.enableOnOffLight !== false) {
@@ -789,9 +792,9 @@ export class SwitchBotMatterPlatform {
789
792
  accessories.push(device.toAccessory());
790
793
  }
791
794
  if (accessories.length > 0) {
792
- this.log.info(`✓ Registered ${accessories.length} lighting device(s)`);
795
+ this.infoLog(`✓ Registered ${accessories.length} lighting device(s)`);
793
796
  for (const acc of accessories) {
794
- this.log.info(` - ${acc.displayName}`);
797
+ this.infoLog(` - ${acc.displayName}`);
795
798
  }
796
799
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
797
800
  }
@@ -800,9 +803,9 @@ export class SwitchBotMatterPlatform {
800
803
  * Section 5: Smart Plugs/Actuators (Matter Spec § 5)
801
804
  */
802
805
  async registerSection5SmartPlugs() {
803
- this.log.debug('═'.repeat(80));
804
- this.log.info('Section 5: Smart Plugs/Actuators (Matter Spec § 5)');
805
- this.log.debug('═'.repeat(80));
806
+ this.debugLog('═'.repeat(80));
807
+ this.infoLog('Section 5: Smart Plugs/Actuators (Matter Spec § 5)');
808
+ this.debugLog('═'.repeat(80));
806
809
  const accessories = [];
807
810
  // On/Off Outlet
808
811
  if (this.config.enableOnOffOutlet !== false) {
@@ -810,9 +813,9 @@ export class SwitchBotMatterPlatform {
810
813
  accessories.push(device.toAccessory());
811
814
  }
812
815
  if (accessories.length > 0) {
813
- this.log.info(`✓ Registered ${accessories.length} smart plug/actuator device(s)`);
816
+ this.infoLog(`✓ Registered ${accessories.length} smart plug/actuator device(s)`);
814
817
  for (const acc of accessories) {
815
- this.log.info(` - ${acc.displayName}`);
818
+ this.infoLog(` - ${acc.displayName}`);
816
819
  }
817
820
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
818
821
  }
@@ -821,9 +824,9 @@ export class SwitchBotMatterPlatform {
821
824
  * Section 6: Switches & Controllers (Matter Spec § 6)
822
825
  */
823
826
  async registerSection6Switches() {
824
- this.log.debug('═'.repeat(80));
825
- this.log.info('Section 6: Switches & Controllers (Matter Spec § 6)');
826
- this.log.debug('═'.repeat(80));
827
+ this.debugLog('═'.repeat(80));
828
+ this.infoLog('Section 6: Switches & Controllers (Matter Spec § 6)');
829
+ this.debugLog('═'.repeat(80));
827
830
  const accessories = [];
828
831
  // On/Off Switch
829
832
  if (this.config.enableOnOffSwitch !== false) {
@@ -831,9 +834,9 @@ export class SwitchBotMatterPlatform {
831
834
  accessories.push(device.toAccessory());
832
835
  }
833
836
  if (accessories.length > 0) {
834
- this.log.info(`✓ Registered ${accessories.length} switch/controller device(s)`);
837
+ this.infoLog(`✓ Registered ${accessories.length} switch/controller device(s)`);
835
838
  for (const acc of accessories) {
836
- this.log.info(` - ${acc.displayName}`);
839
+ this.infoLog(` - ${acc.displayName}`);
837
840
  }
838
841
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
839
842
  }
@@ -842,9 +845,9 @@ export class SwitchBotMatterPlatform {
842
845
  * Section 7: Sensors (Matter Spec § 7)
843
846
  */
844
847
  async registerSection7Sensors() {
845
- this.log.debug('═'.repeat(80));
846
- this.log.info('Section 7: Sensors (Matter Spec § 7)');
847
- this.log.debug('═'.repeat(80));
848
+ this.debugLog('═'.repeat(80));
849
+ this.infoLog('Section 7: Sensors (Matter Spec § 7)');
850
+ this.debugLog('═'.repeat(80));
848
851
  const accessories = [];
849
852
  // Contact Sensor
850
853
  if (this.config.enableContactSensor !== false) {
@@ -882,9 +885,9 @@ export class SwitchBotMatterPlatform {
882
885
  accessories.push(device.toAccessory());
883
886
  }
884
887
  if (accessories.length > 0) {
885
- this.log.info(`✓ Registered ${accessories.length} sensor device(s)`);
888
+ this.infoLog(`✓ Registered ${accessories.length} sensor device(s)`);
886
889
  for (const acc of accessories) {
887
- this.log.info(` - ${acc.displayName}`);
890
+ this.infoLog(` - ${acc.displayName}`);
888
891
  }
889
892
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
890
893
  }
@@ -893,9 +896,9 @@ export class SwitchBotMatterPlatform {
893
896
  * Section 8: Closure Devices (Matter Spec § 8)
894
897
  */
895
898
  async registerSection8Closure() {
896
- this.log.debug('═'.repeat(80));
897
- this.log.info('Section 8: Closure Devices (Matter Spec § 8)');
898
- this.log.debug('═'.repeat(80));
899
+ this.debugLog('═'.repeat(80));
900
+ this.infoLog('Section 8: Closure Devices (Matter Spec § 8)');
901
+ this.debugLog('═'.repeat(80));
899
902
  const accessories = [];
900
903
  // Door Lock
901
904
  if (this.config.enableDoorLock !== false) {
@@ -913,9 +916,9 @@ export class SwitchBotMatterPlatform {
913
916
  accessories.push(device.toAccessory());
914
917
  }
915
918
  if (accessories.length > 0) {
916
- this.log.info(`✓ Registered ${accessories.length} closure device(s)`);
919
+ this.infoLog(`✓ Registered ${accessories.length} closure device(s)`);
917
920
  for (const acc of accessories) {
918
- this.log.info(` - ${acc.displayName}`);
921
+ this.infoLog(` - ${acc.displayName}`);
919
922
  }
920
923
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
921
924
  }
@@ -924,9 +927,9 @@ export class SwitchBotMatterPlatform {
924
927
  * Section 9: HVAC (Matter Spec § 9)
925
928
  */
926
929
  async registerSection9HVAC() {
927
- this.log.debug('═'.repeat(80));
928
- this.log.info('Section 9: HVAC (Matter Spec § 9)');
929
- this.log.debug('═'.repeat(80));
930
+ this.debugLog('═'.repeat(80));
931
+ this.infoLog('Section 9: HVAC (Matter Spec § 9)');
932
+ this.debugLog('═'.repeat(80));
930
933
  const accessories = [];
931
934
  // Thermostat
932
935
  if (this.config.enableThermostat !== false) {
@@ -939,9 +942,9 @@ export class SwitchBotMatterPlatform {
939
942
  accessories.push(device.toAccessory());
940
943
  }
941
944
  if (accessories.length > 0) {
942
- this.log.info(`✓ Registered ${accessories.length} HVAC device(s)`);
945
+ this.infoLog(`✓ Registered ${accessories.length} HVAC device(s)`);
943
946
  for (const acc of accessories) {
944
- this.log.info(` - ${acc.displayName}`);
947
+ this.infoLog(` - ${acc.displayName}`);
945
948
  }
946
949
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
947
950
  }
@@ -953,9 +956,9 @@ export class SwitchBotMatterPlatform {
953
956
  * Use those codes to pair the vacuum as a separate bridge in your Home app.
954
957
  */
955
958
  async registerSection12Robotic() {
956
- this.log.debug('═'.repeat(80));
957
- this.log.info('Section 12: Robotic Devices (Matter Spec § 12)');
958
- this.log.debug('═'.repeat(80));
959
+ this.debugLog('═'.repeat(80));
960
+ this.infoLog('Section 12: Robotic Devices (Matter Spec § 12)');
961
+ this.debugLog('═'.repeat(80));
959
962
  const accessories = [];
960
963
  // Robot Vacuum
961
964
  if (this.config.enableRobotVacuum !== false) {
@@ -963,9 +966,9 @@ export class SwitchBotMatterPlatform {
963
966
  accessories.push(device.toAccessory());
964
967
  }
965
968
  if (accessories.length > 0) {
966
- this.log.info(`✓ Registered ${accessories.length} robot vacuum device(s)`);
969
+ this.infoLog(`✓ Registered ${accessories.length} robot vacuum device(s)`);
967
970
  for (const acc of accessories) {
968
- this.log.info(` - ${acc.displayName} (standalone for Apple Home compatibility)`);
971
+ this.infoLog(` - ${acc.displayName} (standalone for Apple Home compatibility)`);
969
972
  }
970
973
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
971
974
  }
@@ -978,9 +981,9 @@ export class SwitchBotMatterPlatform {
978
981
  * like managing multiple logical components within a single device.
979
982
  */
980
983
  async registerCustomDevices() {
981
- this.log.debug('═'.repeat(80));
982
- this.log.info('Custom Devices');
983
- this.log.debug('═'.repeat(80));
984
+ this.debugLog('═'.repeat(80));
985
+ this.infoLog('Custom Devices');
986
+ this.debugLog('═'.repeat(80));
984
987
  const accessories = [];
985
988
  // Power Strip (4 Outlets)
986
989
  if (this.config.enablePowerStrip !== false) {
@@ -988,9 +991,9 @@ export class SwitchBotMatterPlatform {
988
991
  accessories.push(device.toAccessory());
989
992
  }
990
993
  if (accessories.length > 0) {
991
- this.log.info(`✓ Registered ${accessories.length} custom device(s)`);
994
+ this.infoLog(`✓ Registered ${accessories.length} custom device(s)`);
992
995
  for (const acc of accessories) {
993
- this.log.info(` - ${acc.displayName}`);
996
+ this.infoLog(` - ${acc.displayName}`);
994
997
  }
995
998
  await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
996
999
  }