@switchbot/homebridge-switchbot 5.0.0-beta.5 → 5.0.0-beta.51
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/CHANGELOG.md +15 -0
- package/README.md +45 -3
- package/config.schema.json +866 -13754
- package/dist/devices-hap/airpurifier.d.ts.map +1 -1
- package/dist/devices-hap/airpurifier.js +12 -6
- package/dist/devices-hap/airpurifier.js.map +1 -1
- package/dist/devices-hap/blindtilt.js +3 -3
- package/dist/devices-hap/bot.d.ts.map +1 -1
- package/dist/devices-hap/bot.js +16 -5
- package/dist/devices-hap/bot.js.map +1 -1
- package/dist/devices-hap/ceilinglight.d.ts.map +1 -1
- package/dist/devices-hap/ceilinglight.js +13 -7
- package/dist/devices-hap/ceilinglight.js.map +1 -1
- package/dist/devices-hap/colorbulb.d.ts.map +1 -1
- package/dist/devices-hap/colorbulb.js +49 -9
- package/dist/devices-hap/colorbulb.js.map +1 -1
- package/dist/devices-hap/contact.js +3 -3
- package/dist/devices-hap/curtain.js +2 -2
- package/dist/devices-hap/curtain.js.map +1 -1
- package/dist/devices-hap/device.d.ts +18 -8
- package/dist/devices-hap/device.d.ts.map +1 -1
- package/dist/devices-hap/device.js +141 -69
- package/dist/devices-hap/device.js.map +1 -1
- package/dist/devices-hap/fan.d.ts.map +1 -1
- package/dist/devices-hap/fan.js +12 -6
- package/dist/devices-hap/fan.js.map +1 -1
- package/dist/devices-hap/hub.d.ts.map +1 -1
- package/dist/devices-hap/hub.js +6 -5
- package/dist/devices-hap/hub.js.map +1 -1
- package/dist/devices-hap/humidifier.d.ts +5 -0
- package/dist/devices-hap/humidifier.d.ts.map +1 -1
- package/dist/devices-hap/humidifier.js +92 -4
- package/dist/devices-hap/humidifier.js.map +1 -1
- package/dist/devices-hap/iosensor.d.ts.map +1 -1
- package/dist/devices-hap/iosensor.js +36 -21
- package/dist/devices-hap/iosensor.js.map +1 -1
- package/dist/devices-hap/lightstrip.d.ts.map +1 -1
- package/dist/devices-hap/lightstrip.js +38 -8
- package/dist/devices-hap/lightstrip.js.map +1 -1
- package/dist/devices-hap/lock.d.ts.map +1 -1
- package/dist/devices-hap/lock.js +14 -6
- package/dist/devices-hap/lock.js.map +1 -1
- package/dist/devices-hap/meter.d.ts.map +1 -1
- package/dist/devices-hap/meter.js +6 -5
- package/dist/devices-hap/meter.js.map +1 -1
- package/dist/devices-hap/meterplus.d.ts.map +1 -1
- package/dist/devices-hap/meterplus.js +6 -5
- package/dist/devices-hap/meterplus.js.map +1 -1
- package/dist/devices-hap/meterpro.d.ts.map +1 -1
- package/dist/devices-hap/meterpro.js +7 -6
- package/dist/devices-hap/meterpro.js.map +1 -1
- package/dist/devices-hap/motion.js +3 -3
- package/dist/devices-hap/plug.d.ts.map +1 -1
- package/dist/devices-hap/plug.js +11 -6
- package/dist/devices-hap/plug.js.map +1 -1
- package/dist/devices-hap/relayswitch.js +3 -3
- package/dist/devices-hap/robotvacuumcleaner.d.ts.map +1 -1
- package/dist/devices-hap/robotvacuumcleaner.js +13 -6
- package/dist/devices-hap/robotvacuumcleaner.js.map +1 -1
- package/dist/devices-hap/waterdetector.js +3 -3
- package/dist/devices-matter/BaseMatterAccessory.d.ts +27 -0
- package/dist/devices-matter/BaseMatterAccessory.d.ts.map +1 -1
- package/dist/devices-matter/BaseMatterAccessory.js +169 -5
- package/dist/devices-matter/BaseMatterAccessory.js.map +1 -1
- package/dist/devices-matter/ColorLightAccessory.d.ts.map +1 -1
- package/dist/devices-matter/ColorLightAccessory.js +12 -12
- package/dist/devices-matter/ColorLightAccessory.js.map +1 -1
- package/dist/devices-matter/ColorTemperatureLightAccessory.d.ts.map +1 -1
- package/dist/devices-matter/ColorTemperatureLightAccessory.js +5 -7
- package/dist/devices-matter/ColorTemperatureLightAccessory.js.map +1 -1
- package/dist/devices-matter/DimmableLightAccessory.js +9 -9
- package/dist/devices-matter/DimmableLightAccessory.js.map +1 -1
- package/dist/devices-matter/ExtendedColorLightAccessory.d.ts.map +1 -1
- package/dist/devices-matter/ExtendedColorLightAccessory.js +14 -15
- package/dist/devices-matter/ExtendedColorLightAccessory.js.map +1 -1
- package/dist/devices-matter/OnOffLightAccessory.d.ts.map +1 -1
- package/dist/devices-matter/OnOffLightAccessory.js +8 -16
- package/dist/devices-matter/OnOffLightAccessory.js.map +1 -1
- package/dist/devices-matter/OnOffOutletAccessory.d.ts +2 -0
- package/dist/devices-matter/OnOffOutletAccessory.d.ts.map +1 -1
- package/dist/devices-matter/OnOffOutletAccessory.js +10 -7
- package/dist/devices-matter/OnOffOutletAccessory.js.map +1 -1
- package/dist/devices-matter/OnOffSwitchAccessory.js +2 -2
- package/dist/devices-matter/OnOffSwitchAccessory.js.map +1 -1
- package/dist/devices-matter/RoboticVacuumAccessory.d.ts +11 -2
- package/dist/devices-matter/RoboticVacuumAccessory.d.ts.map +1 -1
- package/dist/devices-matter/RoboticVacuumAccessory.js +26 -17
- package/dist/devices-matter/RoboticVacuumAccessory.js.map +1 -1
- package/dist/homebridge-ui/public/index.html +64 -2
- package/dist/homebridge-ui/server.js +77 -9
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -7
- package/dist/index.js.map +1 -1
- package/dist/irdevice/irdevice.d.ts +11 -10
- package/dist/irdevice/irdevice.d.ts.map +1 -1
- package/dist/irdevice/irdevice.js +76 -35
- package/dist/irdevice/irdevice.js.map +1 -1
- package/dist/platform-hap.d.ts +26 -15
- package/dist/platform-hap.d.ts.map +1 -1
- package/dist/platform-hap.js +333 -153
- package/dist/platform-hap.js.map +1 -1
- package/dist/platform-matter.d.ts +98 -6
- package/dist/platform-matter.d.ts.map +1 -1
- package/dist/platform-matter.js +1885 -253
- package/dist/platform-matter.js.map +1 -1
- package/dist/settings.d.ts +58 -7
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js.map +1 -1
- package/dist/test/apiRequestTracker.test.d.ts +2 -0
- package/dist/test/apiRequestTracker.test.d.ts.map +1 -0
- package/dist/test/apiRequestTracker.test.js +392 -0
- package/dist/test/apiRequestTracker.test.js.map +1 -0
- package/dist/test/hap/device-webhook-context.test.d.ts +2 -0
- package/dist/test/hap/device-webhook-context.test.d.ts.map +1 -0
- package/dist/test/hap/device-webhook-context.test.js +128 -0
- package/dist/test/hap/device-webhook-context.test.js.map +1 -0
- package/dist/test/hap/platform-hap.logging.test.d.ts +2 -0
- package/dist/test/hap/platform-hap.logging.test.d.ts.map +1 -0
- package/dist/test/hap/platform-hap.logging.test.js +33 -0
- package/dist/test/hap/platform-hap.logging.test.js.map +1 -0
- package/dist/test/hap/platform-hap.test.d.ts +2 -0
- package/dist/test/hap/platform-hap.test.d.ts.map +1 -0
- package/dist/test/hap/platform-hap.test.js +62 -0
- package/dist/test/hap/platform-hap.test.js.map +1 -0
- package/dist/test/helpers/platform-fixtures.d.ts +9 -0
- package/dist/test/helpers/platform-fixtures.d.ts.map +1 -0
- package/dist/test/helpers/platform-fixtures.js +30 -0
- package/dist/test/helpers/platform-fixtures.js.map +1 -0
- package/dist/test/homebridge-ui/server.test.d.ts +2 -0
- package/dist/test/homebridge-ui/server.test.d.ts.map +1 -0
- package/dist/test/homebridge-ui/server.test.js +445 -0
- package/dist/test/homebridge-ui/server.test.js.map +1 -0
- package/dist/{index.test.d.ts.map → test/index.test.d.ts.map} +1 -1
- package/dist/test/index.test.js +19 -0
- package/dist/test/index.test.js.map +1 -0
- package/dist/test/matter/devices-matter/baseMatterAccessory.test.d.ts +2 -0
- package/dist/test/matter/devices-matter/baseMatterAccessory.test.d.ts.map +1 -0
- package/dist/test/matter/devices-matter/baseMatterAccessory.test.js +71 -0
- package/dist/test/matter/devices-matter/baseMatterAccessory.test.js.map +1 -0
- package/dist/test/matter/platform-matter.additional.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.additional.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.additional.test.js +35 -0
- package/dist/test/matter/platform-matter.additional.test.js.map +1 -0
- package/dist/test/matter/platform-matter.bleparse.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.bleparse.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.bleparse.test.js +43 -0
- package/dist/test/matter/platform-matter.bleparse.test.js.map +1 -0
- package/dist/test/matter/platform-matter.cleanup.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.cleanup.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.cleanup.test.js +70 -0
- package/dist/test/matter/platform-matter.cleanup.test.js.map +1 -0
- package/dist/test/matter/platform-matter.keepstale.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.keepstale.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.keepstale.test.js +27 -0
- package/dist/test/matter/platform-matter.keepstale.test.js.map +1 -0
- package/dist/test/matter/platform-matter.logging.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.logging.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.logging.test.js +29 -0
- package/dist/test/matter/platform-matter.logging.test.js.map +1 -0
- package/dist/test/matter/platform-matter.mapping.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.mapping.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.mapping.test.js +43 -0
- package/dist/test/matter/platform-matter.mapping.test.js.map +1 -0
- package/dist/test/matter/platform-matter.openapi-mapping.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.openapi-mapping.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.openapi-mapping.test.js +84 -0
- package/dist/test/matter/platform-matter.openapi-mapping.test.js.map +1 -0
- package/dist/test/matter/platform-matter.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.test.js +117 -0
- package/dist/test/matter/platform-matter.test.js.map +1 -0
- package/dist/test/matter/platform-matter.unregister.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.unregister.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.unregister.test.js +30 -0
- package/dist/test/matter/platform-matter.unregister.test.js.map +1 -0
- package/dist/test/matter/platform-matter.webhook.test.d.ts +2 -0
- package/dist/test/matter/platform-matter.webhook.test.d.ts.map +1 -0
- package/dist/test/matter/platform-matter.webhook.test.js +46 -0
- package/dist/test/matter/platform-matter.webhook.test.js.map +1 -0
- package/dist/test/utils.test.d.ts +2 -0
- package/dist/test/utils.test.d.ts.map +1 -0
- package/dist/test/utils.test.js +95 -0
- package/dist/test/utils.test.js.map +1 -0
- package/dist/test/verifyconfig.test.d.ts.map +1 -0
- package/dist/{verifyconfig.test.js → test/verifyconfig.test.js} +2 -2
- package/dist/test/verifyconfig.test.js.map +1 -0
- package/dist/utils.d.ts +204 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +713 -33
- package/dist/utils.js.map +1 -1
- package/docs/assets/highlight.css +14 -0
- package/docs/assets/main.js +2 -2
- package/docs/index.html +31 -2
- package/docs/variables/default.html +1 -1
- package/package.json +15 -15
- package/src/devices-hap/airpurifier.ts +11 -6
- package/src/devices-hap/blindtilt.ts +3 -3
- package/src/devices-hap/bot.ts +15 -5
- package/src/devices-hap/ceilinglight.ts +12 -7
- package/src/devices-hap/colorbulb.ts +46 -10
- package/src/devices-hap/contact.ts +3 -3
- package/src/devices-hap/curtain.ts +2 -2
- package/src/devices-hap/device.ts +149 -70
- package/src/devices-hap/fan.ts +11 -6
- package/src/devices-hap/hub.ts +6 -5
- package/src/devices-hap/humidifier.ts +97 -4
- package/src/devices-hap/iosensor.ts +36 -21
- package/src/devices-hap/lightstrip.ts +35 -8
- package/src/devices-hap/lock.ts +13 -6
- package/src/devices-hap/meter.ts +6 -5
- package/src/devices-hap/meterplus.ts +6 -5
- package/src/devices-hap/meterpro.ts +7 -6
- package/src/devices-hap/motion.ts +3 -3
- package/src/devices-hap/plug.ts +10 -6
- package/src/devices-hap/relayswitch.ts +3 -3
- package/src/devices-hap/robotvacuumcleaner.ts +12 -6
- package/src/devices-hap/waterdetector.ts +3 -3
- package/src/devices-matter/BaseMatterAccessory.ts +176 -5
- package/src/devices-matter/ColorLightAccessory.ts +12 -12
- package/src/devices-matter/ColorTemperatureLightAccessory.ts +5 -7
- package/src/devices-matter/DimmableLightAccessory.ts +9 -9
- package/src/devices-matter/ExtendedColorLightAccessory.ts +14 -15
- package/src/devices-matter/OnOffLightAccessory.ts +8 -16
- package/src/devices-matter/OnOffOutletAccessory.ts +12 -7
- package/src/devices-matter/OnOffSwitchAccessory.ts +2 -2
- package/src/devices-matter/RoboticVacuumAccessory.ts +27 -17
- package/src/homebridge-ui/public/index.html +64 -2
- package/src/homebridge-ui/server.ts +80 -9
- package/src/index.ts +4 -7
- package/src/irdevice/irdevice.ts +74 -35
- package/src/platform-hap.ts +365 -169
- package/src/platform-matter.ts +1938 -256
- package/src/settings.ts +62 -3
- package/src/test/apiRequestTracker.test.ts +417 -0
- package/src/test/hap/device-webhook-context.test.ts +136 -0
- package/src/test/hap/platform-hap.logging.test.ts +36 -0
- package/src/test/hap/platform-hap.test.ts +70 -0
- package/src/test/helpers/platform-fixtures.ts +33 -0
- package/src/test/homebridge-ui/server.test.ts +486 -0
- package/src/test/index.test.ts +24 -0
- package/src/test/matter/devices-matter/baseMatterAccessory.test.ts +88 -0
- package/src/test/matter/platform-matter.additional.test.ts +44 -0
- package/src/test/matter/platform-matter.bleparse.test.ts +47 -0
- package/src/test/matter/platform-matter.cleanup.test.ts +86 -0
- package/src/test/matter/platform-matter.keepstale.test.ts +37 -0
- package/src/test/matter/platform-matter.logging.test.ts +33 -0
- package/src/test/matter/platform-matter.mapping.test.ts +57 -0
- package/src/test/matter/platform-matter.openapi-mapping.test.ts +109 -0
- package/src/test/matter/platform-matter.test.ts +144 -0
- package/src/test/matter/platform-matter.unregister.test.ts +39 -0
- package/src/test/matter/platform-matter.webhook.test.ts +54 -0
- package/src/test/utils.test.ts +96 -0
- package/src/{verifyconfig.test.ts → test/verifyconfig.test.ts} +12 -11
- package/src/utils.ts +777 -36
- package/dist/index.test.js +0 -14
- package/dist/index.test.js.map +0 -1
- package/dist/verifyconfig.test.d.ts.map +0 -1
- package/dist/verifyconfig.test.js.map +0 -1
- package/src/index.test.ts +0 -19
- /package/dist/{index.test.d.ts → test/index.test.d.ts} +0 -0
- /package/dist/{verifyconfig.test.d.ts → test/verifyconfig.test.d.ts} +0 -0
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { API, Logger, MatterRequests } from 'homebridge'
|
|
7
7
|
|
|
8
|
+
import { hs2rgb } from '../utils.js'
|
|
8
9
|
import { BaseMatterAccessory } from './BaseMatterAccessory.js'
|
|
9
10
|
|
|
10
11
|
export class ColorLightAccessory extends BaseMatterAccessory {
|
|
@@ -56,38 +57,37 @@ export class ColorLightAccessory extends BaseMatterAccessory {
|
|
|
56
57
|
|
|
57
58
|
private async handleOn(): Promise<void> {
|
|
58
59
|
this.logInfo('turning on.')
|
|
59
|
-
|
|
60
|
+
await this.sendOnCommand()
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
private async handleOff(): Promise<void> {
|
|
63
64
|
this.logInfo('turning off.')
|
|
64
|
-
|
|
65
|
+
await this.sendOffCommand()
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
private async handleSetLevel(request: MatterRequests.MoveToLevel): Promise<void> {
|
|
68
69
|
this.logInfo(`MoveToLevel request: ${JSON.stringify(request)}`)
|
|
69
70
|
const { level } = request
|
|
70
71
|
const brightnessPercent = Math.round((level / 254) * 100)
|
|
71
|
-
this.
|
|
72
|
-
// TODO: await myLightAPI.setBrightness(brightnessPercent)
|
|
72
|
+
await this.sendSetBrightness(brightnessPercent)
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
private async handleSetColor(request: MatterRequests.MoveToColor): Promise<void> {
|
|
76
76
|
this.logInfo(`MoveToColor request: ${JSON.stringify(request)}`)
|
|
77
|
-
const { colorX, colorY
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
const { colorX, colorY } = request
|
|
78
|
+
const hueApprox = Math.round((colorX / 65535) * 360)
|
|
79
|
+
const satApprox = Math.round((colorY / 65535) * 100)
|
|
80
|
+
const [r, g, b] = hs2rgb(hueApprox, satApprox)
|
|
81
|
+
await this.sendSetColor(r, g, b)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
private async handleSetHueSaturation(request: MatterRequests.MoveToHueAndSaturation): Promise<void> {
|
|
85
85
|
this.logInfo(`MoveToHueAndSaturation request: ${JSON.stringify(request)}`)
|
|
86
|
-
const { hue, saturation
|
|
86
|
+
const { hue, saturation } = request
|
|
87
87
|
const hueDegrees = Math.round((hue / 254) * 360)
|
|
88
88
|
const saturationPercent = Math.round((saturation / 254) * 100)
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
const [r, g, b] = hs2rgb(hueDegrees, saturationPercent)
|
|
90
|
+
await this.sendSetColor(r, g, b)
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
public updateOnOffState(isOn: boolean): void {
|
|
@@ -52,28 +52,26 @@ export class ColorTemperatureLightAccessory extends BaseMatterAccessory {
|
|
|
52
52
|
|
|
53
53
|
private async handleOn(): Promise<void> {
|
|
54
54
|
this.logInfo('turning on.')
|
|
55
|
-
|
|
55
|
+
await this.sendOnCommand()
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
private async handleOff(): Promise<void> {
|
|
59
59
|
this.logInfo('turning off.')
|
|
60
|
-
|
|
60
|
+
await this.sendOffCommand()
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
private async handleSetLevel(request: MatterRequests.MoveToLevel): Promise<void> {
|
|
64
64
|
this.logInfo(`MoveToLevel request: ${JSON.stringify(request)}`)
|
|
65
65
|
const { level } = request
|
|
66
66
|
const brightnessPercent = Math.round((level / 254) * 100)
|
|
67
|
-
this.
|
|
68
|
-
// TODO: await myLightAPI.setBrightness(brightnessPercent)
|
|
67
|
+
await this.sendSetBrightness(brightnessPercent)
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
private async handleSetColorTemperature(request: MatterRequests.MoveToColorTemperature): Promise<void> {
|
|
72
71
|
this.logInfo(`MoveToColorTemperature request: ${JSON.stringify(request)}`)
|
|
73
|
-
const { colorTemperatureMireds
|
|
72
|
+
const { colorTemperatureMireds } = request
|
|
74
73
|
const kelvin = Math.round(1000000 / colorTemperatureMireds)
|
|
75
|
-
this.
|
|
76
|
-
// TODO: await myLightAPI.setColorTemperature(kelvin, transitionTime)
|
|
74
|
+
await this.sendSetColorTemperature(kelvin)
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
public updateOnOffState(isOn: boolean): void {
|
|
@@ -69,10 +69,10 @@ export class DimmableLightAccessory extends BaseMatterAccessory {
|
|
|
69
69
|
this.logInfo('turning on.')
|
|
70
70
|
|
|
71
71
|
try {
|
|
72
|
-
//
|
|
73
|
-
|
|
72
|
+
// Use platform helper (OpenAPI/BLE) when available
|
|
73
|
+
await this.sendOnCommand()
|
|
74
74
|
|
|
75
|
-
this.logInfo('physical device turned on.')
|
|
75
|
+
this.logInfo('physical device turned on (via platform helper).')
|
|
76
76
|
} catch (error) {
|
|
77
77
|
this.logError('failed to turn on:', error)
|
|
78
78
|
throw error
|
|
@@ -86,10 +86,10 @@ export class DimmableLightAccessory extends BaseMatterAccessory {
|
|
|
86
86
|
this.logInfo('turning off.')
|
|
87
87
|
|
|
88
88
|
try {
|
|
89
|
-
//
|
|
90
|
-
|
|
89
|
+
// Use platform helper (OpenAPI/BLE) when available
|
|
90
|
+
await this.sendOffCommand()
|
|
91
91
|
|
|
92
|
-
this.logInfo('physical device turned off.')
|
|
92
|
+
this.logInfo('physical device turned off (via platform helper).')
|
|
93
93
|
} catch (error) {
|
|
94
94
|
this.logError('failed to turn off:', error)
|
|
95
95
|
throw error
|
|
@@ -110,10 +110,10 @@ export class DimmableLightAccessory extends BaseMatterAccessory {
|
|
|
110
110
|
this.logInfo(`setting brightness to ${brightnessPercent}% (level: ${level}), transitionTime: ${transitionTime}.`)
|
|
111
111
|
|
|
112
112
|
try {
|
|
113
|
-
//
|
|
114
|
-
|
|
113
|
+
// Use platform helper (OpenAPI/BLE) when available
|
|
114
|
+
await this.sendSetBrightness(brightnessPercent)
|
|
115
115
|
|
|
116
|
-
this.logInfo(`physical device brightness set to ${brightnessPercent}
|
|
116
|
+
this.logInfo(`physical device brightness set to ${brightnessPercent}% (via platform helper).`)
|
|
117
117
|
} catch (error) {
|
|
118
118
|
this.logError('Failed to set brightness:', error)
|
|
119
119
|
throw error
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { API, Logger, MatterRequests } from 'homebridge'
|
|
7
7
|
|
|
8
|
+
import { hs2rgb } from '../utils.js'
|
|
8
9
|
import { BaseMatterAccessory } from './BaseMatterAccessory.js'
|
|
9
10
|
|
|
10
11
|
export class ExtendedColorLightAccessory extends BaseMatterAccessory {
|
|
@@ -61,46 +62,44 @@ export class ExtendedColorLightAccessory extends BaseMatterAccessory {
|
|
|
61
62
|
|
|
62
63
|
private async handleOn(): Promise<void> {
|
|
63
64
|
this.logInfo('turning on.')
|
|
64
|
-
|
|
65
|
+
await this.sendOnCommand()
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
private async handleOff(): Promise<void> {
|
|
68
69
|
this.logInfo('turning off.')
|
|
69
|
-
|
|
70
|
+
await this.sendOffCommand()
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
private async handleSetLevel(request: MatterRequests.MoveToLevel): Promise<void> {
|
|
73
74
|
this.logInfo(`MoveToLevel request: ${JSON.stringify(request)}`)
|
|
74
75
|
const { level } = request
|
|
75
76
|
const brightnessPercent = Math.round((level / 254) * 100)
|
|
76
|
-
this.
|
|
77
|
-
// TODO: await myLightAPI.setBrightness(brightnessPercent)
|
|
77
|
+
await this.sendSetBrightness(brightnessPercent)
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
private async handleSetColor(request: MatterRequests.MoveToColor): Promise<void> {
|
|
81
81
|
this.logInfo(`MoveToColor request: ${JSON.stringify(request)}`)
|
|
82
|
-
const { colorX, colorY
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
const { colorX, colorY } = request
|
|
83
|
+
const hueApprox = Math.round((colorX / 65535) * 360)
|
|
84
|
+
const satApprox = Math.round((colorY / 65535) * 100)
|
|
85
|
+
const [r, g, b] = hs2rgb(hueApprox, satApprox)
|
|
86
|
+
await this.sendSetColor(r, g, b)
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
private async handleSetHueSaturation(request: MatterRequests.MoveToHueAndSaturation): Promise<void> {
|
|
90
90
|
this.logInfo(`MoveToHueAndSaturation request: ${JSON.stringify(request)}`)
|
|
91
|
-
const { hue, saturation
|
|
91
|
+
const { hue, saturation } = request
|
|
92
92
|
const hueDegrees = Math.round((hue / 254) * 360)
|
|
93
93
|
const saturationPercent = Math.round((saturation / 254) * 100)
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const [r, g, b] = hs2rgb(hueDegrees, saturationPercent)
|
|
95
|
+
await this.sendSetColor(r, g, b)
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
private async handleSetColorTemperature(request: MatterRequests.MoveToColorTemperature): Promise<void> {
|
|
99
99
|
this.logInfo(`MoveToColorTemperature request: ${JSON.stringify(request)}`)
|
|
100
|
-
const { colorTemperatureMireds
|
|
100
|
+
const { colorTemperatureMireds } = request
|
|
101
101
|
const kelvin = Math.round(1000000 / colorTemperatureMireds)
|
|
102
|
-
this.
|
|
103
|
-
// TODO: await myLightAPI.setColorTemperature(kelvin, transitionTime)
|
|
102
|
+
await this.sendSetColorTemperature(kelvin)
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
public updateOnOffState(isOn: boolean): void {
|
|
@@ -27,12 +27,8 @@ export class OnOffLightAccessory extends BaseMatterAccessory {
|
|
|
27
27
|
const clusters = opts?.clusters ?? { onOff: { onOff: true } }
|
|
28
28
|
const handlers = opts?.handlers ?? {
|
|
29
29
|
onOff: {
|
|
30
|
-
on: async () =>
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
off: async () => {
|
|
34
|
-
log.debug(`${displayName} off handler invoked (default no-op).`)
|
|
35
|
-
},
|
|
30
|
+
on: async () => this.handleOnCommand(),
|
|
31
|
+
off: async () => this.handleOffCommand(),
|
|
36
32
|
},
|
|
37
33
|
}
|
|
38
34
|
|
|
@@ -61,14 +57,10 @@ export class OnOffLightAccessory extends BaseMatterAccessory {
|
|
|
61
57
|
this.logInfo('turning on.')
|
|
62
58
|
|
|
63
59
|
try {
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
// await fetch('https://api.mydevice.com/light/on', { method: 'POST' })
|
|
67
|
-
// await fetch('http://192.168.1.50/api/light/on')
|
|
68
|
-
// mqttClient.publish('home/light/command', JSON.stringify({ state: 'ON' }))
|
|
69
|
-
// await myLightAPI.turnOn(this.context.deviceId)
|
|
60
|
+
// Delegate to the platform-provided helper (OpenAPI/BLE) when available
|
|
61
|
+
await this.sendOnCommand()
|
|
70
62
|
|
|
71
|
-
this.logInfo('physical device turned on.')
|
|
63
|
+
this.logInfo('physical device turned on (via platform helper).')
|
|
72
64
|
|
|
73
65
|
// State automatically updated by Homebridge after handler completes
|
|
74
66
|
} catch (error) {
|
|
@@ -84,10 +76,10 @@ export class OnOffLightAccessory extends BaseMatterAccessory {
|
|
|
84
76
|
this.logInfo('turning off.')
|
|
85
77
|
|
|
86
78
|
try {
|
|
87
|
-
//
|
|
88
|
-
|
|
79
|
+
// Delegate to the platform-provided helper (OpenAPI/BLE) when available
|
|
80
|
+
await this.sendOffCommand()
|
|
89
81
|
|
|
90
|
-
this.logInfo('physical device turned off.')
|
|
82
|
+
this.logInfo('physical device turned off (via platform helper).')
|
|
91
83
|
|
|
92
84
|
// State automatically updated by Homebridge after handler completes
|
|
93
85
|
} catch (error) {
|
|
@@ -13,13 +13,8 @@ export class OnOffOutletAccessory extends BaseMatterAccessory {
|
|
|
13
13
|
const clusters = opts?.clusters ?? { onOff: { onOff: false } }
|
|
14
14
|
const handlers = opts?.handlers ?? {
|
|
15
15
|
onOff: {
|
|
16
|
-
on: async () =>
|
|
17
|
-
|
|
18
|
-
log.debug(`${displayName} on handler invoked (default no-op).`)
|
|
19
|
-
},
|
|
20
|
-
off: async () => {
|
|
21
|
-
log.debug(`${displayName} off handler invoked (default no-op).`)
|
|
22
|
-
},
|
|
16
|
+
on: async () => this.handleOn(),
|
|
17
|
+
off: async () => this.handleOff(),
|
|
23
18
|
},
|
|
24
19
|
}
|
|
25
20
|
|
|
@@ -43,4 +38,14 @@ export class OnOffOutletAccessory extends BaseMatterAccessory {
|
|
|
43
38
|
public updateOnOffState(isOn: boolean): void {
|
|
44
39
|
this.updateState(this.api.matter.clusterNames.OnOff, { onOff: isOn })
|
|
45
40
|
}
|
|
41
|
+
|
|
42
|
+
private async handleOn(): Promise<void> {
|
|
43
|
+
this.logInfo('turning on.')
|
|
44
|
+
await this.sendOnCommand()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private async handleOff(): Promise<void> {
|
|
48
|
+
this.logInfo('turning off.')
|
|
49
|
+
await this.sendOffCommand()
|
|
50
|
+
}
|
|
46
51
|
}
|
|
@@ -37,12 +37,12 @@ export class OnOffSwitchAccessory extends BaseMatterAccessory {
|
|
|
37
37
|
|
|
38
38
|
private async handleOn(): Promise<void> {
|
|
39
39
|
this.logInfo('turning on.')
|
|
40
|
-
|
|
40
|
+
await this.sendOnCommand()
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
private async handleOff(): Promise<void> {
|
|
44
44
|
this.logInfo('turning off.')
|
|
45
|
-
|
|
45
|
+
await this.sendOffCommand()
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
public updateOnOffState(isOn: boolean): void {
|
|
@@ -33,14 +33,6 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
|
|
|
33
33
|
constructor(api: API, log: Logger, opts?: Partial<import('./BaseMatterAccessory').BaseMatterAccessoryConfig & { deviceId?: string }>) {
|
|
34
34
|
const serialNumber = opts?.serialNumber ?? 'VACUUM-001'
|
|
35
35
|
const clusters = opts?.clusters ?? {
|
|
36
|
-
powerSource: {
|
|
37
|
-
status: 0,
|
|
38
|
-
order: 0,
|
|
39
|
-
description: 'Battery',
|
|
40
|
-
batPercentRemaining: 100,
|
|
41
|
-
batChargeLevel: 2,
|
|
42
|
-
batReplaceability: 1,
|
|
43
|
-
},
|
|
44
36
|
rvcRunMode: {
|
|
45
37
|
supportedModes: [
|
|
46
38
|
{ label: 'Idle', mode: 0, modeTags: [{ value: 16384 }] },
|
|
@@ -387,21 +379,39 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
|
|
|
387
379
|
|
|
388
380
|
/**
|
|
389
381
|
* Update battery percentage
|
|
390
|
-
*
|
|
382
|
+
*
|
|
383
|
+
* Note: The Matter specification for RoboticVacuumCleaner does not include
|
|
384
|
+
* the PowerSource cluster. Battery information for robotic vacuums should be
|
|
385
|
+
* communicated through device-specific status reporting or via the RVC
|
|
386
|
+
* operational state cluster.
|
|
387
|
+
*
|
|
388
|
+
* This method is retained for API compatibility but does not update any
|
|
389
|
+
* Matter cluster state.
|
|
390
|
+
*
|
|
391
|
+
* @param percentageOrBatPercentRemaining - Battery percentage (0-100) or batPercentRemaining (0-200)
|
|
391
392
|
*/
|
|
392
|
-
public async updateBatteryPercentage(
|
|
393
|
-
//
|
|
394
|
-
const
|
|
393
|
+
public async updateBatteryPercentage(percentageOrBatPercentRemaining: number): Promise<void> {
|
|
394
|
+
// Accept either 0–100 (percentage) or 0–200 (batPercentRemaining) to be robust
|
|
395
|
+
const isBatPercent = Number(percentageOrBatPercentRemaining) > 100
|
|
396
|
+
const percentage = isBatPercent
|
|
397
|
+
? Math.max(0, Math.min(100, Math.round(Number(percentageOrBatPercentRemaining) / 2)))
|
|
398
|
+
: Math.max(0, Math.min(100, Math.round(Number(percentageOrBatPercentRemaining))))
|
|
395
399
|
|
|
396
400
|
// Determine charge level based on percentage
|
|
397
|
-
let
|
|
401
|
+
let chargeLevel = 0 // Ok
|
|
398
402
|
if (percentage < 20) {
|
|
399
|
-
|
|
403
|
+
chargeLevel = 2 // Critical
|
|
400
404
|
} else if (percentage < 40) {
|
|
401
|
-
|
|
405
|
+
chargeLevel = 1 // Warning
|
|
402
406
|
}
|
|
403
407
|
|
|
404
|
-
|
|
405
|
-
this.logInfo(`battery
|
|
408
|
+
// Log battery status only - PowerSource cluster is not supported for RoboticVacuumCleaner
|
|
409
|
+
this.logInfo(`battery status: ${percentage}% (${chargeLevel === 0 ? 'Ok' : chargeLevel === 1 ? 'Warning' : 'Critical'})`)
|
|
410
|
+
|
|
411
|
+
// Store battery info in context for reference
|
|
412
|
+
if (this.context) {
|
|
413
|
+
(this.context as any).batteryPercentage = percentage
|
|
414
|
+
;(this.context as any).batteryChargeLevel = chargeLevel
|
|
415
|
+
}
|
|
406
416
|
}
|
|
407
417
|
}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
</form>
|
|
44
44
|
<table class="table w-100" id="deviceTable" style="display: none">
|
|
45
45
|
<thead>
|
|
46
|
-
<tr
|
|
46
|
+
<tr>
|
|
47
47
|
<th scope="col" style="width: 40%">Device Name</th>
|
|
48
48
|
<th scope="col" style="width: 60%" id="displayName"></th>
|
|
49
49
|
</tr>
|
|
@@ -69,6 +69,18 @@
|
|
|
69
69
|
<th scope="row">Connection Type</th>
|
|
70
70
|
<td id="connectionType"></td>
|
|
71
71
|
</tr>
|
|
72
|
+
<tr>
|
|
73
|
+
<th scope="row">Refresh Rate</th>
|
|
74
|
+
<td id="refreshRate"></td>
|
|
75
|
+
</tr>
|
|
76
|
+
<tr>
|
|
77
|
+
<th scope="row">Update Rate</th>
|
|
78
|
+
<td id="updateRate"></td>
|
|
79
|
+
</tr>
|
|
80
|
+
<tr>
|
|
81
|
+
<th scope="row">Push Rate</th>
|
|
82
|
+
<td id="pushRate"></td>
|
|
83
|
+
</tr>
|
|
72
84
|
</tbody>
|
|
73
85
|
</table>
|
|
74
86
|
<p class="text-center">External accessories will not be displayed here.</p>
|
|
@@ -122,6 +134,41 @@
|
|
|
122
134
|
(async () => {
|
|
123
135
|
try {
|
|
124
136
|
const currentConfig = await homebridge.getPluginConfig();
|
|
137
|
+
|
|
138
|
+
// Defensive wrapper: ensure token/secret aren't accidentally cleared by
|
|
139
|
+
// the UI/schema form. Some versions of config UI can omit sensitive
|
|
140
|
+
// fields from the submitted payload; when that happens we copy the
|
|
141
|
+
// existing values from `currentConfig` into the outgoing payload so
|
|
142
|
+
// saved config does not inadvertently remove credentials.
|
|
143
|
+
try {
|
|
144
|
+
if (typeof homebridge.updatePluginConfig === 'function') {
|
|
145
|
+
const _origUpdatePluginConfig = homebridge.updatePluginConfig.bind(homebridge)
|
|
146
|
+
homebridge.updatePluginConfig = async (cfg) => {
|
|
147
|
+
try {
|
|
148
|
+
if (Array.isArray(cfg) && cfg.length > 0 && Array.isArray(currentConfig) && currentConfig.length > 0) {
|
|
149
|
+
const incoming = cfg[0] || {}
|
|
150
|
+
const existing = currentConfig[0] || {}
|
|
151
|
+
incoming.credentials = incoming.credentials || {}
|
|
152
|
+
// Preserve token/secret when incoming payload leaves them blank/undefined
|
|
153
|
+
if ((incoming.credentials.token === undefined || String(incoming.credentials.token).trim() === '') && existing.credentials && existing.credentials.token) {
|
|
154
|
+
incoming.credentials.token = existing.credentials.token
|
|
155
|
+
}
|
|
156
|
+
if ((incoming.credentials.secret === undefined || String(incoming.credentials.secret).trim() === '') && existing.credentials && existing.credentials.secret) {
|
|
157
|
+
incoming.credentials.secret = existing.credentials.secret
|
|
158
|
+
}
|
|
159
|
+
cfg[0] = incoming
|
|
160
|
+
}
|
|
161
|
+
} catch (e) {
|
|
162
|
+
// Swallow any wrapper errors but log to console for debugging
|
|
163
|
+
// (do not expose secrets).
|
|
164
|
+
console.error('updatePluginConfig wrapper error', e)
|
|
165
|
+
}
|
|
166
|
+
return await _origUpdatePluginConfig(cfg)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} catch (e) {
|
|
170
|
+
console.error('Failed to attach updatePluginConfig wrapper', e)
|
|
171
|
+
}
|
|
125
172
|
showIntro = () => {
|
|
126
173
|
const introLink = document.getElementById('introLink');
|
|
127
174
|
introLink.addEventListener('click', () => {
|
|
@@ -144,10 +191,25 @@
|
|
|
144
191
|
document.getElementById('menuSettings').classList.add('btn-primary');
|
|
145
192
|
document.getElementById('pageSupport').style.display = 'none';
|
|
146
193
|
document.getElementById('pageDevices').style.display = 'block';
|
|
147
|
-
|
|
194
|
+
let cachedAccessories =
|
|
148
195
|
typeof homebridge.getCachedAccessories === 'function'
|
|
149
196
|
? await homebridge.getCachedAccessories()
|
|
150
197
|
: await homebridge.request('/getCachedAccessories');
|
|
198
|
+
|
|
199
|
+
// If no HAP cached accessories were returned, try the Matter cached list using the new native method
|
|
200
|
+
if ((!cachedAccessories || cachedAccessories.length === 0)) {
|
|
201
|
+
try {
|
|
202
|
+
// Use the new native getCachedMatterAccessories() method from @homebridge/plugin-ui-utils v2.1.1-beta.0+
|
|
203
|
+
const matter = typeof homebridge.getCachedMatterAccessories === 'function'
|
|
204
|
+
? await homebridge.getCachedMatterAccessories()
|
|
205
|
+
: await homebridge.request('/getCachedMatterAccessories'); // Fallback to custom handler for older UI versions
|
|
206
|
+
if (Array.isArray(matter) && matter.length > 0) {
|
|
207
|
+
cachedAccessories = matter
|
|
208
|
+
}
|
|
209
|
+
} catch (e) {
|
|
210
|
+
// ignore
|
|
211
|
+
}
|
|
212
|
+
}
|
|
151
213
|
if (cachedAccessories.length > 0) {
|
|
152
214
|
cachedAccessories.sort((a, b) => {
|
|
153
215
|
return a.displayName.toLowerCase() > b.displayName.toLowerCase() ? 1 : b.displayName.toLowerCase() > a.displayName.toLowerCase() ? -1 : 0;
|
|
@@ -9,9 +9,12 @@ class PluginUiServer extends HomebridgePluginUiServer {
|
|
|
9
9
|
A native method getCachedAccessories() was introduced in config-ui-x v4.37.0
|
|
10
10
|
The following is for users who have a lower version of config-ui-x
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
const getCachedAccessoriesHandler = () => {
|
|
13
13
|
try {
|
|
14
|
-
|
|
14
|
+
// Some Homebridge versions store cached accessories with the scoped
|
|
15
|
+
// plugin name ("@switchbot/homebridge-switchbot"); others may use
|
|
16
|
+
// the unscoped id ("homebridge-switchbot"). Check both.
|
|
17
|
+
const pluginNames = ['@switchbot/homebridge-switchbot', 'homebridge-switchbot']
|
|
15
18
|
const devicesToReturn = []
|
|
16
19
|
|
|
17
20
|
// The path and file of the cached accessories
|
|
@@ -22,21 +25,89 @@ class PluginUiServer extends HomebridgePluginUiServer {
|
|
|
22
25
|
// read the cached accessories file
|
|
23
26
|
const cachedAccessories: any[] = JSON.parse(fs.readFileSync(accFile, 'utf8'))
|
|
24
27
|
|
|
25
|
-
cachedAccessories.forEach((
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
cachedAccessories.forEach((entry: any) => {
|
|
29
|
+
// entry shape varies by UI version
|
|
30
|
+
const pluginName = entry.plugin || entry?.accessory?.plugin || entry?.accessory?.pluginName
|
|
31
|
+
const acc = entry.accessory ?? entry
|
|
32
|
+
if (pluginNames.includes(pluginName)) {
|
|
33
|
+
devicesToReturn.push(acc as never)
|
|
30
34
|
}
|
|
31
35
|
})
|
|
32
36
|
}
|
|
33
37
|
// Return the array
|
|
38
|
+
console.warn(`[Homebridge UI] getCachedAccessories returning ${devicesToReturn.length} device(s)`)
|
|
34
39
|
return devicesToReturn
|
|
35
|
-
} catch {
|
|
40
|
+
} catch (e: any) {
|
|
36
41
|
// Just return an empty accessory list in case of any errors
|
|
42
|
+
console.error(`[Homebridge UI] getCachedAccessories error: ${e?.message ?? e}`)
|
|
37
43
|
return []
|
|
38
44
|
}
|
|
39
|
-
}
|
|
45
|
+
}
|
|
46
|
+
this.onRequest('getCachedAccessories', getCachedAccessoriesHandler)
|
|
47
|
+
// Also register with a leading slash for compatibility with some UIs
|
|
48
|
+
this.onRequest('/getCachedAccessories', getCachedAccessoriesHandler)
|
|
49
|
+
// Provide Matter cached accessories if Homebridge stores them separately.
|
|
50
|
+
const getCachedMatterAccessoriesHandler = () => {
|
|
51
|
+
try {
|
|
52
|
+
const pluginNames = ['@switchbot/homebridge-switchbot', 'homebridge-switchbot']
|
|
53
|
+
const devicesToReturn: any[] = []
|
|
54
|
+
|
|
55
|
+
const accFile = `${this.homebridgeStoragePath}/accessories/cachedAccessories`
|
|
56
|
+
const matterFile = `${this.homebridgeStoragePath}/accessories/cachedMatterAccessories`
|
|
57
|
+
|
|
58
|
+
// Log all files in the accessories directory for debugging
|
|
59
|
+
try {
|
|
60
|
+
const accessoriesDir = `${this.homebridgeStoragePath}/accessories`
|
|
61
|
+
if (fs.existsSync(accessoriesDir)) {
|
|
62
|
+
const files = fs.readdirSync(accessoriesDir)
|
|
63
|
+
console.warn(`[Homebridge UI] Files in accessories directory: ${files.join(', ')}`)
|
|
64
|
+
}
|
|
65
|
+
} catch (e: any) {
|
|
66
|
+
console.error(`[Homebridge UI] Error listing accessories directory: ${e?.message ?? e}`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.warn(`[Homebridge UI] Checking for cached files:`)
|
|
70
|
+
console.warn(`[Homebridge UI] - cachedAccessories: ${fs.existsSync(accFile)}`)
|
|
71
|
+
console.warn(`[Homebridge UI] - cachedMatterAccessories: ${fs.existsSync(matterFile)}`)
|
|
72
|
+
|
|
73
|
+
const readAndCollect = (filePath: string) => {
|
|
74
|
+
if (!fs.existsSync(filePath)) {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const parsed: any[] = JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
79
|
+
console.warn(`[Homebridge UI] - ${filePath}: found ${parsed.length} total entries`)
|
|
80
|
+
let matchCount = 0
|
|
81
|
+
parsed.forEach((entry: any) => {
|
|
82
|
+
// Entry shape varies between Homebridge versions; try common locations
|
|
83
|
+
const pluginName = entry.plugin || entry?.accessory?.plugin || entry?.accessory?.pluginName
|
|
84
|
+
const acc = entry.accessory ?? entry
|
|
85
|
+
if (pluginNames.includes(pluginName)) {
|
|
86
|
+
devicesToReturn.push(acc as never)
|
|
87
|
+
matchCount++
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
console.warn(`[Homebridge UI] - ${filePath}: matched ${matchCount} SwitchBot entries`)
|
|
91
|
+
} catch (e: any) {
|
|
92
|
+
// ignore parse errors for a single file
|
|
93
|
+
console.error(`[Homebridge UI] - ${filePath}: parse error - ${e?.message ?? e}`)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Read both canonical files (some Homebridge versions use one or the other)
|
|
98
|
+
readAndCollect(accFile)
|
|
99
|
+
readAndCollect(matterFile)
|
|
100
|
+
|
|
101
|
+
console.warn(`[Homebridge UI] getCachedMatterAccessories returning ${devicesToReturn.length} device(s)`)
|
|
102
|
+
return devicesToReturn
|
|
103
|
+
} catch (e: any) {
|
|
104
|
+
console.error(`[Homebridge UI] getCachedMatterAccessories error: ${e?.message ?? e}`)
|
|
105
|
+
return []
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
this.onRequest('getCachedMatterAccessories', getCachedMatterAccessoriesHandler)
|
|
109
|
+
// Also register with a leading slash for compatibility with some UIs
|
|
110
|
+
this.onRequest('/getCachedMatterAccessories', getCachedMatterAccessoriesHandler)
|
|
40
111
|
this.ready()
|
|
41
112
|
}
|
|
42
113
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,14 +7,11 @@ import type { API } from 'homebridge'
|
|
|
7
7
|
import { SwitchBotHAPPlatform } from './platform-hap.js'
|
|
8
8
|
import { SwitchBotMatterPlatform } from './platform-matter.js'
|
|
9
9
|
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js'
|
|
10
|
+
import { createPlatformProxy } from './utils.js'
|
|
10
11
|
|
|
11
12
|
// Register our platform with homebridge.
|
|
12
13
|
export default (api: API): void => {
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const log = (api as any).logger ?? console
|
|
17
|
-
log.info?.(`Homebridge SwitchBot Plugin initializing in ${isMatter ? 'Matter' : 'HAP'} mode.`)
|
|
18
|
-
// If Matter is enabled register the Matter platform, otherwise use HAP platform.
|
|
19
|
-
api.registerPlatform(PLUGIN_NAME, PLATFORM_NAME, isMatter ? SwitchBotMatterPlatform : SwitchBotHAPPlatform)
|
|
14
|
+
// Create and register a small proxy that selects the correct platform (HAP or Matter) at runtime.
|
|
15
|
+
const ProxyCtor = createPlatformProxy(SwitchBotHAPPlatform, SwitchBotMatterPlatform)
|
|
16
|
+
api.registerPlatform(PLUGIN_NAME, PLATFORM_NAME, ProxyCtor as any)
|
|
20
17
|
}
|