@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.
- package/dist/devices-hap/device.d.ts.map +1 -1
- package/dist/devices-hap/device.js +104 -22
- package/dist/devices-hap/device.js.map +1 -1
- package/dist/devices-matter/BaseMatterAccessory.d.ts.map +1 -1
- package/dist/devices-matter/BaseMatterAccessory.js +25 -1
- package/dist/devices-matter/BaseMatterAccessory.js.map +1 -1
- package/dist/irdevice/irdevice.d.ts.map +1 -1
- package/dist/irdevice/irdevice.js +122 -22
- package/dist/irdevice/irdevice.js.map +1 -1
- package/dist/platform-hap.d.ts +10 -14
- package/dist/platform-hap.d.ts.map +1 -1
- package/dist/platform-hap.js +28 -66
- package/dist/platform-hap.js.map +1 -1
- package/dist/platform-matter.d.ts +11 -0
- package/dist/platform-matter.d.ts.map +1 -1
- package/dist/platform-matter.js +129 -126
- package/dist/platform-matter.js.map +1 -1
- package/dist/utils.d.ts +53 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +155 -0
- package/dist/utils.js.map +1 -1
- package/dist/verifyconfig.test.js +2 -2
- package/dist/verifyconfig.test.js.map +1 -1
- package/docs/variables/default.html +1 -1
- package/package.json +1 -1
- package/src/devices-hap/device.ts +98 -25
- package/src/devices-matter/BaseMatterAccessory.ts +25 -1
- package/src/irdevice/irdevice.ts +113 -22
- package/src/platform-hap.ts +30 -75
- package/src/platform-matter.ts +131 -126
- package/src/utils.ts +158 -1
- package/src/verifyconfig.test.ts +11 -10
package/src/platform-matter.ts
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
WindowBlindAccessory,
|
|
36
36
|
} from './devices-matter/index.js'
|
|
37
37
|
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js'
|
|
38
|
-
import { cleanDeviceConfig, formatDeviceIdAsMac, hs2rgb, rgb2hs, sleep } from './utils.js'
|
|
38
|
+
import { cleanDeviceConfig, createPlatformLogger, formatDeviceIdAsMac, hs2rgb, makeBLESender, makeOpenAPISender, rgb2hs, sleep } from './utils.js'
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* MatterPlatform
|
|
@@ -57,13 +57,41 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
57
57
|
private discoveredDevices: device[] = []
|
|
58
58
|
// BLE event handlers keyed by device MAC (formatted)
|
|
59
59
|
private bleEventHandler: { [x: string]: (context: any) => void } = {}
|
|
60
|
+
// Platform logging toggle (can be controlled via UI or config)
|
|
61
|
+
private platformLogging?: boolean
|
|
62
|
+
|
|
63
|
+
// Platform-provided logging helpers (attached in constructor)
|
|
64
|
+
infoLog!: (...args: any[]) => void
|
|
65
|
+
successLog!: (...args: any[]) => void
|
|
66
|
+
debugSuccessLog!: (...args: any[]) => void
|
|
67
|
+
warnLog!: (...args: any[]) => void
|
|
68
|
+
debugWarnLog!: (...args: any[]) => void
|
|
69
|
+
errorLog!: (...args: any[]) => void
|
|
70
|
+
debugErrorLog!: (...args: any[]) => void
|
|
71
|
+
debugLog!: (...args: any[]) => void
|
|
72
|
+
loggingIsDebug!: () => Promise<boolean>
|
|
73
|
+
enablingPlatformLogging!: () => Promise<boolean>
|
|
60
74
|
|
|
61
75
|
constructor(
|
|
62
76
|
public readonly log: Logging,
|
|
63
77
|
public readonly config: SwitchBotPlatformConfig,
|
|
64
78
|
public readonly api: API,
|
|
65
79
|
) {
|
|
66
|
-
|
|
80
|
+
// Attach platform-wide logging helpers from utils so Matter and device
|
|
81
|
+
// classes can use consistent logging methods (infoLog/debugLog/etc.)
|
|
82
|
+
const _pl = createPlatformLogger(async () => (this as any).platformLogging, this.log)
|
|
83
|
+
this.infoLog = _pl.infoLog
|
|
84
|
+
this.successLog = _pl.successLog
|
|
85
|
+
this.debugSuccessLog = _pl.debugSuccessLog
|
|
86
|
+
this.warnLog = _pl.warnLog
|
|
87
|
+
this.debugWarnLog = _pl.debugWarnLog
|
|
88
|
+
this.errorLog = _pl.errorLog
|
|
89
|
+
this.debugErrorLog = _pl.debugErrorLog
|
|
90
|
+
this.debugLog = _pl.debugLog
|
|
91
|
+
this.loggingIsDebug = _pl.loggingIsDebug
|
|
92
|
+
this.enablingPlatformLogging = _pl.enablingPlatformLogging
|
|
93
|
+
|
|
94
|
+
this.debugLog('Finished initializing platform:', this.config.name)
|
|
67
95
|
|
|
68
96
|
// Normalize deviceConfig to remove UI-inserted defaults
|
|
69
97
|
try {
|
|
@@ -76,12 +104,12 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
76
104
|
}
|
|
77
105
|
}
|
|
78
106
|
} catch (e) {
|
|
79
|
-
this.
|
|
107
|
+
this.debugLog('Failed to clean deviceConfig: %s', e)
|
|
80
108
|
}
|
|
81
109
|
|
|
82
110
|
// Does the user have a version of Homebridge that is compatible with matter?
|
|
83
111
|
if (!this.api.isMatterAvailable?.()) {
|
|
84
|
-
this.
|
|
112
|
+
this.warnLog('Matter is not available in this version of Homebridge. Please update Homebridge to use this plugin.')
|
|
85
113
|
}
|
|
86
114
|
|
|
87
115
|
// Check if the user has matter enabled, this means:
|
|
@@ -90,35 +118,35 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
90
118
|
// In reality, only the below check is needed, but they are both included here for completeness
|
|
91
119
|
// Remember to use a '?.' optional chaining operator in case the user is running an older version of Homebridge that does not have these APIs
|
|
92
120
|
if (!this.api.isMatterEnabled?.()) {
|
|
93
|
-
this.
|
|
121
|
+
this.warnLog('Matter is not enabled in Homebridge. Please enable Matter in the Homebridge settings to use this plugin.')
|
|
94
122
|
return
|
|
95
123
|
}
|
|
96
124
|
|
|
97
125
|
// Register Matter accessories when Homebridge has finished launching
|
|
98
126
|
this.api.on('didFinishLaunching', () => {
|
|
99
|
-
this.
|
|
127
|
+
this.debugLog('Executed didFinishLaunching callback')
|
|
100
128
|
// Initialize SwitchBot API clients
|
|
101
129
|
try {
|
|
102
130
|
if (this.config.credentials?.token && this.config.credentials?.secret) {
|
|
103
131
|
this.switchBotAPI = new SwitchBotOpenAPI(this.config.credentials.token, this.config.credentials.secret, this.config.options?.hostname)
|
|
104
132
|
// forward basic logs
|
|
105
133
|
if (!this.config.options?.disableLogsforOpenAPI && this.switchBotAPI?.on) {
|
|
106
|
-
this.switchBotAPI.on('log', (l: any) => this.
|
|
134
|
+
this.switchBotAPI.on('log', (l: any) => this.debugLog('[SwitchBot OpenAPI]', l.message))
|
|
107
135
|
}
|
|
108
136
|
} else {
|
|
109
|
-
this.
|
|
137
|
+
this.debugLog('SwitchBot OpenAPI credentials not provided; cloud devices will be skipped')
|
|
110
138
|
}
|
|
111
139
|
} catch (e: any) {
|
|
112
|
-
this.
|
|
140
|
+
this.errorLog('Failed to initialize SwitchBot OpenAPI:', e?.message ?? e)
|
|
113
141
|
}
|
|
114
142
|
|
|
115
143
|
try {
|
|
116
144
|
this.switchBotBLE = new SwitchBotBLE()
|
|
117
145
|
if (!this.config.options?.disableLogsforBLE && this.switchBotBLE?.on) {
|
|
118
|
-
this.switchBotBLE.on('log', (l: any) => this.
|
|
146
|
+
this.switchBotBLE.on('log', (l: any) => this.debugLog('[SwitchBot BLE]', l.message))
|
|
119
147
|
}
|
|
120
148
|
} catch (e: any) {
|
|
121
|
-
this.
|
|
149
|
+
this.errorLog('Failed to initialize SwitchBot BLE client:', e?.message ?? e)
|
|
122
150
|
}
|
|
123
151
|
|
|
124
152
|
// If BLE scanning is enabled, start scanning and route advertisements to registered handlers
|
|
@@ -128,7 +156,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
128
156
|
try {
|
|
129
157
|
await ble.startScan()
|
|
130
158
|
} catch (e: any) {
|
|
131
|
-
this.
|
|
159
|
+
this.errorLog(`Failed to start BLE scanning: ${e?.message ?? e}`)
|
|
132
160
|
}
|
|
133
161
|
|
|
134
162
|
// route advertisements to our handlers
|
|
@@ -140,7 +168,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
140
168
|
await handler(ad.serviceData)
|
|
141
169
|
}
|
|
142
170
|
} catch (e: any) {
|
|
143
|
-
this.
|
|
171
|
+
this.errorLog(`Failed to handle BLE advertisement: ${e?.message ?? e}`)
|
|
144
172
|
}
|
|
145
173
|
}
|
|
146
174
|
})()
|
|
@@ -185,7 +213,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
185
213
|
const devicesWithTypeConfig = await Promise.all(discovered.map(async (deviceObj) => {
|
|
186
214
|
if (!deviceObj.deviceType) {
|
|
187
215
|
deviceObj.deviceType = (deviceObj as any).configDeviceType !== undefined ? (deviceObj as any).configDeviceType : 'Unknown'
|
|
188
|
-
this.
|
|
216
|
+
this.debugLog(`API missing deviceType for ${deviceObj.deviceId}, using configDeviceType: ${(deviceObj as any).configDeviceType}`)
|
|
189
217
|
}
|
|
190
218
|
const deviceTypeConfig = this.config.options?.deviceConfig?.[deviceObj.deviceType] || {}
|
|
191
219
|
return Object.assign({}, deviceObj, deviceTypeConfig)
|
|
@@ -258,45 +286,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
258
286
|
},
|
|
259
287
|
}
|
|
260
288
|
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
const bodyChange: bodyChange = { command, parameter, commandType: 'command' }
|
|
265
|
-
return this.retryCommand(dev, bodyChange, this.config.options?.maxRetries ?? 1, this.config.options?.delayBetweenRetries ?? 1000)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Helper to send a BLE action if Platform BLE is enabled and switchBotBLE exists
|
|
269
|
-
const sendBLE = async (methodName: string, ...args: any[]) => {
|
|
270
|
-
// Provide a small retry loop for flaky BLE operations
|
|
271
|
-
if (!this.switchBotBLE) {
|
|
272
|
-
throw new Error('Platform BLE not available')
|
|
273
|
-
}
|
|
274
|
-
const id = formatDeviceIdAsMac(dev.deviceId)
|
|
275
|
-
const maxRetries = (this.config.options as any)?.bleRetries ?? 2
|
|
276
|
-
const retryDelay = (this.config.options as any)?.bleRetryDelay ?? 500
|
|
277
|
-
let attempt = 0
|
|
278
|
-
while (attempt < maxRetries) {
|
|
279
|
-
try {
|
|
280
|
-
const list = await this.switchBotBLE.discover({ model: (dev as any).bleModel, id })
|
|
281
|
-
if (!Array.isArray(list) || list.length === 0) {
|
|
282
|
-
throw new Error('BLE device not found')
|
|
283
|
-
}
|
|
284
|
-
const deviceInst: any = list[0]
|
|
285
|
-
if (typeof deviceInst[methodName] !== 'function') {
|
|
286
|
-
throw new TypeError(`BLE method ${methodName} not available on device`)
|
|
287
|
-
}
|
|
288
|
-
return await deviceInst[methodName](...args)
|
|
289
|
-
} catch (e: any) {
|
|
290
|
-
attempt++
|
|
291
|
-
if (attempt >= maxRetries) {
|
|
292
|
-
throw e
|
|
293
|
-
}
|
|
294
|
-
this.log.debug(`BLE ${methodName} attempt ${attempt} failed for ${dev.deviceId}: ${e?.message ?? e}, retrying in ${retryDelay}ms`)
|
|
295
|
-
await sleep(retryDelay)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
throw new Error('BLE operation failed')
|
|
299
|
-
}
|
|
289
|
+
// Build platform-side helpers using shared factories so they can be reused/tested
|
|
290
|
+
const sendOpenAPI = makeOpenAPISender(this.retryCommand.bind(this), dev, { maxRetries: this.config.options?.maxRetries ?? 1, delayBetweenRetries: this.config.options?.delayBetweenRetries ?? 1000 })
|
|
291
|
+
const sendBLE = makeBLESender(this.switchBotBLE, dev, { bleRetries: (this.config.options as any)?.bleRetries ?? 2, bleRetryDelay: (this.config.options as any)?.bleRetryDelay ?? 500 })
|
|
300
292
|
|
|
301
293
|
const makeOnOffHandlers = (uuid: string, connectionType: 'BLE' | 'OpenAPI') => ({
|
|
302
294
|
onOff: {
|
|
@@ -309,7 +301,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
309
301
|
}
|
|
310
302
|
await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.OnOff, { onOff: true })
|
|
311
303
|
} catch (e: any) {
|
|
312
|
-
this.
|
|
304
|
+
this.errorLog(`Failed to turn on device ${dev.deviceId}: ${e?.message ?? e}`)
|
|
313
305
|
}
|
|
314
306
|
},
|
|
315
307
|
off: async () => {
|
|
@@ -321,7 +313,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
321
313
|
}
|
|
322
314
|
await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.OnOff, { onOff: false })
|
|
323
315
|
} catch (e: any) {
|
|
324
|
-
this.
|
|
316
|
+
this.errorLog(`Failed to turn off device ${dev.deviceId}: ${e?.message ?? e}`)
|
|
325
317
|
}
|
|
326
318
|
},
|
|
327
319
|
},
|
|
@@ -409,7 +401,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
409
401
|
|
|
410
402
|
const Ctor = mapping[dev.deviceType ?? '']
|
|
411
403
|
if (!Ctor) {
|
|
412
|
-
this.
|
|
404
|
+
this.debugLog(`No Matter mapping for deviceType='${dev.deviceType}', deviceId=${dev.deviceId}`)
|
|
413
405
|
return undefined
|
|
414
406
|
}
|
|
415
407
|
|
|
@@ -438,7 +430,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
438
430
|
}
|
|
439
431
|
await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.LevelControl, { currentLevel: level })
|
|
440
432
|
} catch (e: any) {
|
|
441
|
-
this.
|
|
433
|
+
this.errorLog(`Failed to set brightness for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
442
434
|
}
|
|
443
435
|
},
|
|
444
436
|
}
|
|
@@ -457,7 +449,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
457
449
|
}
|
|
458
450
|
await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.ColorControl, { currentHue: hue, currentSaturation: saturation })
|
|
459
451
|
} catch (e: any) {
|
|
460
|
-
this.
|
|
452
|
+
this.errorLog(`Failed to set hue/sat for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
461
453
|
}
|
|
462
454
|
},
|
|
463
455
|
moveToColorLogic: async (request: any) => {
|
|
@@ -476,7 +468,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
476
468
|
}
|
|
477
469
|
await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.ColorControl, { currentX: colorX, currentY: colorY })
|
|
478
470
|
} catch (e: any) {
|
|
479
|
-
this.
|
|
471
|
+
this.errorLog(`Failed to set XY color for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
480
472
|
}
|
|
481
473
|
},
|
|
482
474
|
}
|
|
@@ -493,7 +485,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
493
485
|
}
|
|
494
486
|
await this.api.matter.updateAccessoryState(uuid, this.api.matter.clusterNames.ColorControl, { currentX: request.colorX ?? 0, currentY: request.colorY ?? 0 })
|
|
495
487
|
} catch (e: any) {
|
|
496
|
-
this.
|
|
488
|
+
this.errorLog(`Failed to set color temperature for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
497
489
|
}
|
|
498
490
|
},
|
|
499
491
|
}
|
|
@@ -503,9 +495,22 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
503
495
|
// classes can call OpenAPI/BLE actions (sendOpenAPI/sendBLE) and know
|
|
504
496
|
// the effective connection type.
|
|
505
497
|
try {
|
|
506
|
-
|
|
498
|
+
/* Inject platform helpers (OpenAPI/BLE senders + logging helpers + connection type)
|
|
499
|
+
into the accessory context so Matter accessory classes can use them without
|
|
500
|
+
reaching into the platform implementation directly. */
|
|
501
|
+
;(baseOpts as any).context = Object.assign({}, (baseOpts as any).context, {
|
|
502
|
+
sendOpenAPI,
|
|
503
|
+
sendBLE,
|
|
504
|
+
connectionType,
|
|
505
|
+
// Expose platform logging helpers so accessories can use consistent logging
|
|
506
|
+
infoLog: this.infoLog,
|
|
507
|
+
debugLog: this.debugLog,
|
|
508
|
+
warnLog: this.warnLog,
|
|
509
|
+
errorLog: this.errorLog,
|
|
510
|
+
successLog: this.successLog,
|
|
511
|
+
})
|
|
507
512
|
} catch (e: any) {
|
|
508
|
-
this.
|
|
513
|
+
this.debugLog('Failed to attach platform helpers to baseOpts.context: %s', e?.message ?? e)
|
|
509
514
|
}
|
|
510
515
|
|
|
511
516
|
const opts = Object.assign({}, baseOpts, { handlers })
|
|
@@ -548,7 +553,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
548
553
|
}
|
|
549
554
|
}
|
|
550
555
|
} catch (e: any) {
|
|
551
|
-
this.
|
|
556
|
+
this.debugLog(`BLE advertisement parsing failed for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
552
557
|
}
|
|
553
558
|
|
|
554
559
|
// Fallback to OpenAPI getDeviceStatus when serviceData is not present or parsing failed
|
|
@@ -595,11 +600,11 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
595
600
|
await this.api.matter.updateAccessoryState(uuidLocal, this.api.matter.clusterNames.ColorControl, { currentHue: Math.round((h / 360) * 254), currentSaturation: Math.round((s / 100) * 254) })
|
|
596
601
|
}
|
|
597
602
|
} catch (e: any) {
|
|
598
|
-
this.
|
|
603
|
+
this.debugLog(`BLE push handler failed for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
599
604
|
}
|
|
600
605
|
}
|
|
601
606
|
} catch (e: any) {
|
|
602
|
-
this.
|
|
607
|
+
this.debugLog(`Failed to register BLE handler for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
603
608
|
}
|
|
604
609
|
|
|
605
610
|
return instance.toAccessory()
|
|
@@ -610,25 +615,25 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
610
615
|
*/
|
|
611
616
|
private async discoverDevices(): Promise<void> {
|
|
612
617
|
if (!this.switchBotAPI) {
|
|
613
|
-
this.
|
|
618
|
+
this.debugLog('SwitchBot OpenAPI not configured; skipping discovery')
|
|
614
619
|
return
|
|
615
620
|
}
|
|
616
621
|
|
|
617
622
|
try {
|
|
618
623
|
const { response, statusCode } = await this.switchBotAPI.getDevices()
|
|
619
|
-
this.
|
|
624
|
+
this.debugLog(`SwitchBot getDevices response status: ${statusCode}`)
|
|
620
625
|
if (statusCode === 100 || statusCode === 200) {
|
|
621
626
|
const deviceList = Array.isArray(response?.body?.deviceList) ? response.body.deviceList : []
|
|
622
627
|
this.discoveredDevices = deviceList
|
|
623
|
-
this.
|
|
628
|
+
this.infoLog(`Discovered ${deviceList.length} SwitchBot device(s) from OpenAPI`)
|
|
624
629
|
for (const d of deviceList) {
|
|
625
|
-
this.
|
|
630
|
+
this.debugLog(` - ${d.deviceName} (${d.deviceType}) id=${d.deviceId}`)
|
|
626
631
|
}
|
|
627
632
|
} else {
|
|
628
|
-
this.
|
|
633
|
+
this.warnLog(`SwitchBot getDevices returned status ${statusCode}`)
|
|
629
634
|
}
|
|
630
635
|
} catch (e: any) {
|
|
631
|
-
this.
|
|
636
|
+
this.errorLog('Failed to discover SwitchBot devices:', e?.message ?? e)
|
|
632
637
|
}
|
|
633
638
|
}
|
|
634
639
|
|
|
@@ -652,7 +657,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
652
657
|
)
|
|
653
658
|
return { response, statusCode }
|
|
654
659
|
} catch (e: any) {
|
|
655
|
-
this.
|
|
660
|
+
this.debugLog(`retryCommand error: ${e?.message ?? e}`)
|
|
656
661
|
}
|
|
657
662
|
retryCount++
|
|
658
663
|
|
|
@@ -716,7 +721,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
716
721
|
|
|
717
722
|
return result
|
|
718
723
|
} catch (e: any) {
|
|
719
|
-
this.
|
|
724
|
+
this.debugLog(`parseAdvertisementForDevice failed for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
720
725
|
return null
|
|
721
726
|
}
|
|
722
727
|
}
|
|
@@ -738,7 +743,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
738
743
|
* any custom data you stored when the accessory was originally registered.
|
|
739
744
|
*/
|
|
740
745
|
configureMatterAccessory(accessory: SerializedMatterAccessory) {
|
|
741
|
-
this.
|
|
746
|
+
this.debugLog('Loading cached Matter accessory:', accessory.displayName)
|
|
742
747
|
this.matterAccessories.set(accessory.uuid, accessory)
|
|
743
748
|
}
|
|
744
749
|
|
|
@@ -746,16 +751,16 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
746
751
|
* Register all Matter accessories
|
|
747
752
|
*/
|
|
748
753
|
private async registerMatterAccessories() {
|
|
749
|
-
this.
|
|
750
|
-
this.
|
|
751
|
-
this.
|
|
754
|
+
this.debugLog('═'.repeat(80))
|
|
755
|
+
this.infoLog('Homebridge Matter Plugin')
|
|
756
|
+
this.debugLog('═'.repeat(80))
|
|
752
757
|
|
|
753
758
|
// Remove accessories that are disabled in config
|
|
754
759
|
await this.removeDisabledAccessories()
|
|
755
760
|
|
|
756
761
|
// If we discovered real SwitchBot devices via OpenAPI, map and register them
|
|
757
762
|
if (this.discoveredDevices && this.discoveredDevices.length > 0) {
|
|
758
|
-
this.
|
|
763
|
+
this.infoLog(`Registering ${this.discoveredDevices.length} discovered SwitchBot device(s) as Matter accessories`)
|
|
759
764
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
760
765
|
|
|
761
766
|
// Merge device config (deviceConfig per deviceType and per-device overrides) to match HAP behavior
|
|
@@ -768,18 +773,18 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
768
773
|
accessories.push(acc)
|
|
769
774
|
}
|
|
770
775
|
} catch (e: any) {
|
|
771
|
-
this.
|
|
776
|
+
this.errorLog(`Failed to create Matter accessory for ${dev.deviceId}: ${e?.message ?? e}`)
|
|
772
777
|
}
|
|
773
778
|
}
|
|
774
779
|
if (accessories.length > 0) {
|
|
775
|
-
this.
|
|
780
|
+
this.infoLog(`✓ Registered ${accessories.length} discovered device(s)`)
|
|
776
781
|
for (const acc of accessories) {
|
|
777
|
-
this.
|
|
782
|
+
this.infoLog(` - ${acc.displayName}`)
|
|
778
783
|
}
|
|
779
784
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
780
785
|
return
|
|
781
786
|
}
|
|
782
|
-
this.
|
|
787
|
+
this.infoLog('No discovered devices were mapped to Matter accessories; falling back to example sections')
|
|
783
788
|
}
|
|
784
789
|
|
|
785
790
|
// Register example/demo devices by Matter specification sections
|
|
@@ -792,9 +797,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
792
797
|
await this.registerSection12Robotic()
|
|
793
798
|
await this.registerCustomDevices()
|
|
794
799
|
|
|
795
|
-
this.
|
|
796
|
-
this.
|
|
797
|
-
this.
|
|
800
|
+
this.debugLog('═'.repeat(80))
|
|
801
|
+
this.debugLog('Finished registering Matter accessories')
|
|
802
|
+
this.debugLog('═'.repeat(80))
|
|
798
803
|
}
|
|
799
804
|
|
|
800
805
|
/**
|
|
@@ -829,7 +834,7 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
829
834
|
if (enabled === false) {
|
|
830
835
|
const existingAccessory = this.matterAccessories.get(uuid)
|
|
831
836
|
if (existingAccessory) {
|
|
832
|
-
this.
|
|
837
|
+
this.infoLog(`Removing accessory '${name}' (disabled in config)`)
|
|
833
838
|
await this.api.matter.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory as unknown as MatterAccessory])
|
|
834
839
|
this.matterAccessories.delete(uuid)
|
|
835
840
|
}
|
|
@@ -841,9 +846,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
841
846
|
* Section 4: Lighting Devices (Matter Spec § 4)
|
|
842
847
|
*/
|
|
843
848
|
private async registerSection4Lighting() {
|
|
844
|
-
this.
|
|
845
|
-
this.
|
|
846
|
-
this.
|
|
849
|
+
this.debugLog('═'.repeat(80))
|
|
850
|
+
this.infoLog('Section 4: Lighting Devices (Matter Spec § 4)')
|
|
851
|
+
this.debugLog('═'.repeat(80))
|
|
847
852
|
|
|
848
853
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
849
854
|
|
|
@@ -878,9 +883,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
878
883
|
}
|
|
879
884
|
|
|
880
885
|
if (accessories.length > 0) {
|
|
881
|
-
this.
|
|
886
|
+
this.infoLog(`✓ Registered ${accessories.length} lighting device(s)`)
|
|
882
887
|
for (const acc of accessories) {
|
|
883
|
-
this.
|
|
888
|
+
this.infoLog(` - ${acc.displayName}`)
|
|
884
889
|
}
|
|
885
890
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
886
891
|
}
|
|
@@ -890,9 +895,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
890
895
|
* Section 5: Smart Plugs/Actuators (Matter Spec § 5)
|
|
891
896
|
*/
|
|
892
897
|
private async registerSection5SmartPlugs() {
|
|
893
|
-
this.
|
|
894
|
-
this.
|
|
895
|
-
this.
|
|
898
|
+
this.debugLog('═'.repeat(80))
|
|
899
|
+
this.infoLog('Section 5: Smart Plugs/Actuators (Matter Spec § 5)')
|
|
900
|
+
this.debugLog('═'.repeat(80))
|
|
896
901
|
|
|
897
902
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
898
903
|
|
|
@@ -903,9 +908,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
903
908
|
}
|
|
904
909
|
|
|
905
910
|
if (accessories.length > 0) {
|
|
906
|
-
this.
|
|
911
|
+
this.infoLog(`✓ Registered ${accessories.length} smart plug/actuator device(s)`)
|
|
907
912
|
for (const acc of accessories) {
|
|
908
|
-
this.
|
|
913
|
+
this.infoLog(` - ${acc.displayName}`)
|
|
909
914
|
}
|
|
910
915
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
911
916
|
}
|
|
@@ -915,9 +920,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
915
920
|
* Section 6: Switches & Controllers (Matter Spec § 6)
|
|
916
921
|
*/
|
|
917
922
|
private async registerSection6Switches() {
|
|
918
|
-
this.
|
|
919
|
-
this.
|
|
920
|
-
this.
|
|
923
|
+
this.debugLog('═'.repeat(80))
|
|
924
|
+
this.infoLog('Section 6: Switches & Controllers (Matter Spec § 6)')
|
|
925
|
+
this.debugLog('═'.repeat(80))
|
|
921
926
|
|
|
922
927
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
923
928
|
|
|
@@ -928,9 +933,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
928
933
|
}
|
|
929
934
|
|
|
930
935
|
if (accessories.length > 0) {
|
|
931
|
-
this.
|
|
936
|
+
this.infoLog(`✓ Registered ${accessories.length} switch/controller device(s)`)
|
|
932
937
|
for (const acc of accessories) {
|
|
933
|
-
this.
|
|
938
|
+
this.infoLog(` - ${acc.displayName}`)
|
|
934
939
|
}
|
|
935
940
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
936
941
|
}
|
|
@@ -940,9 +945,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
940
945
|
* Section 7: Sensors (Matter Spec § 7)
|
|
941
946
|
*/
|
|
942
947
|
private async registerSection7Sensors() {
|
|
943
|
-
this.
|
|
944
|
-
this.
|
|
945
|
-
this.
|
|
948
|
+
this.debugLog('═'.repeat(80))
|
|
949
|
+
this.infoLog('Section 7: Sensors (Matter Spec § 7)')
|
|
950
|
+
this.debugLog('═'.repeat(80))
|
|
946
951
|
|
|
947
952
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
948
953
|
|
|
@@ -989,9 +994,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
989
994
|
}
|
|
990
995
|
|
|
991
996
|
if (accessories.length > 0) {
|
|
992
|
-
this.
|
|
997
|
+
this.infoLog(`✓ Registered ${accessories.length} sensor device(s)`)
|
|
993
998
|
for (const acc of accessories) {
|
|
994
|
-
this.
|
|
999
|
+
this.infoLog(` - ${acc.displayName}`)
|
|
995
1000
|
}
|
|
996
1001
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
997
1002
|
}
|
|
@@ -1001,9 +1006,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1001
1006
|
* Section 8: Closure Devices (Matter Spec § 8)
|
|
1002
1007
|
*/
|
|
1003
1008
|
private async registerSection8Closure() {
|
|
1004
|
-
this.
|
|
1005
|
-
this.
|
|
1006
|
-
this.
|
|
1009
|
+
this.debugLog('═'.repeat(80))
|
|
1010
|
+
this.infoLog('Section 8: Closure Devices (Matter Spec § 8)')
|
|
1011
|
+
this.debugLog('═'.repeat(80))
|
|
1007
1012
|
|
|
1008
1013
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
1009
1014
|
|
|
@@ -1026,9 +1031,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1026
1031
|
}
|
|
1027
1032
|
|
|
1028
1033
|
if (accessories.length > 0) {
|
|
1029
|
-
this.
|
|
1034
|
+
this.infoLog(`✓ Registered ${accessories.length} closure device(s)`)
|
|
1030
1035
|
for (const acc of accessories) {
|
|
1031
|
-
this.
|
|
1036
|
+
this.infoLog(` - ${acc.displayName}`)
|
|
1032
1037
|
}
|
|
1033
1038
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
1034
1039
|
}
|
|
@@ -1038,9 +1043,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1038
1043
|
* Section 9: HVAC (Matter Spec § 9)
|
|
1039
1044
|
*/
|
|
1040
1045
|
private async registerSection9HVAC() {
|
|
1041
|
-
this.
|
|
1042
|
-
this.
|
|
1043
|
-
this.
|
|
1046
|
+
this.debugLog('═'.repeat(80))
|
|
1047
|
+
this.infoLog('Section 9: HVAC (Matter Spec § 9)')
|
|
1048
|
+
this.debugLog('═'.repeat(80))
|
|
1044
1049
|
|
|
1045
1050
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
1046
1051
|
|
|
@@ -1057,9 +1062,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1057
1062
|
}
|
|
1058
1063
|
|
|
1059
1064
|
if (accessories.length > 0) {
|
|
1060
|
-
this.
|
|
1065
|
+
this.infoLog(`✓ Registered ${accessories.length} HVAC device(s)`)
|
|
1061
1066
|
for (const acc of accessories) {
|
|
1062
|
-
this.
|
|
1067
|
+
this.infoLog(` - ${acc.displayName}`)
|
|
1063
1068
|
}
|
|
1064
1069
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
1065
1070
|
}
|
|
@@ -1072,9 +1077,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1072
1077
|
* Use those codes to pair the vacuum as a separate bridge in your Home app.
|
|
1073
1078
|
*/
|
|
1074
1079
|
private async registerSection12Robotic() {
|
|
1075
|
-
this.
|
|
1076
|
-
this.
|
|
1077
|
-
this.
|
|
1080
|
+
this.debugLog('═'.repeat(80))
|
|
1081
|
+
this.infoLog('Section 12: Robotic Devices (Matter Spec § 12)')
|
|
1082
|
+
this.debugLog('═'.repeat(80))
|
|
1078
1083
|
|
|
1079
1084
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
1080
1085
|
|
|
@@ -1085,9 +1090,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1085
1090
|
}
|
|
1086
1091
|
|
|
1087
1092
|
if (accessories.length > 0) {
|
|
1088
|
-
this.
|
|
1093
|
+
this.infoLog(`✓ Registered ${accessories.length} robot vacuum device(s)`)
|
|
1089
1094
|
for (const acc of accessories) {
|
|
1090
|
-
this.
|
|
1095
|
+
this.infoLog(` - ${acc.displayName} (standalone for Apple Home compatibility)`)
|
|
1091
1096
|
}
|
|
1092
1097
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
1093
1098
|
}
|
|
@@ -1101,9 +1106,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1101
1106
|
* like managing multiple logical components within a single device.
|
|
1102
1107
|
*/
|
|
1103
1108
|
private async registerCustomDevices() {
|
|
1104
|
-
this.
|
|
1105
|
-
this.
|
|
1106
|
-
this.
|
|
1109
|
+
this.debugLog('═'.repeat(80))
|
|
1110
|
+
this.infoLog('Custom Devices')
|
|
1111
|
+
this.debugLog('═'.repeat(80))
|
|
1107
1112
|
|
|
1108
1113
|
const accessories: Array<MatterAccessory<Record<string, unknown>>> = []
|
|
1109
1114
|
|
|
@@ -1114,9 +1119,9 @@ export class SwitchBotMatterPlatform implements DynamicPlatformPlugin {
|
|
|
1114
1119
|
}
|
|
1115
1120
|
|
|
1116
1121
|
if (accessories.length > 0) {
|
|
1117
|
-
this.
|
|
1122
|
+
this.infoLog(`✓ Registered ${accessories.length} custom device(s)`)
|
|
1118
1123
|
for (const acc of accessories) {
|
|
1119
|
-
this.
|
|
1124
|
+
this.infoLog(` - ${acc.displayName}`)
|
|
1120
1125
|
}
|
|
1121
1126
|
await this.api.matter.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories)
|
|
1122
1127
|
}
|