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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/baseMatterAccessory.test.d.ts +2 -0
  2. package/dist/baseMatterAccessory.test.d.ts.map +1 -0
  3. package/dist/baseMatterAccessory.test.js +71 -0
  4. package/dist/baseMatterAccessory.test.js.map +1 -0
  5. package/dist/devices-matter/BaseMatterAccessory.d.ts +15 -0
  6. package/dist/devices-matter/BaseMatterAccessory.d.ts.map +1 -1
  7. package/dist/devices-matter/BaseMatterAccessory.js +120 -0
  8. package/dist/devices-matter/BaseMatterAccessory.js.map +1 -1
  9. package/dist/devices-matter/ColorLightAccessory.d.ts.map +1 -1
  10. package/dist/devices-matter/ColorLightAccessory.js +12 -12
  11. package/dist/devices-matter/ColorLightAccessory.js.map +1 -1
  12. package/dist/devices-matter/ColorTemperatureLightAccessory.d.ts.map +1 -1
  13. package/dist/devices-matter/ColorTemperatureLightAccessory.js +5 -7
  14. package/dist/devices-matter/ColorTemperatureLightAccessory.js.map +1 -1
  15. package/dist/devices-matter/DimmableLightAccessory.js +9 -9
  16. package/dist/devices-matter/DimmableLightAccessory.js.map +1 -1
  17. package/dist/devices-matter/ExtendedColorLightAccessory.d.ts.map +1 -1
  18. package/dist/devices-matter/ExtendedColorLightAccessory.js +14 -15
  19. package/dist/devices-matter/ExtendedColorLightAccessory.js.map +1 -1
  20. package/dist/devices-matter/OnOffLightAccessory.d.ts.map +1 -1
  21. package/dist/devices-matter/OnOffLightAccessory.js +8 -16
  22. package/dist/devices-matter/OnOffLightAccessory.js.map +1 -1
  23. package/dist/devices-matter/OnOffOutletAccessory.d.ts +2 -0
  24. package/dist/devices-matter/OnOffOutletAccessory.d.ts.map +1 -1
  25. package/dist/devices-matter/OnOffOutletAccessory.js +10 -7
  26. package/dist/devices-matter/OnOffOutletAccessory.js.map +1 -1
  27. package/dist/devices-matter/OnOffSwitchAccessory.js +2 -2
  28. package/dist/devices-matter/OnOffSwitchAccessory.js.map +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +4 -63
  31. package/dist/index.js.map +1 -1
  32. package/dist/platform-matter.d.ts.map +1 -1
  33. package/dist/platform-matter.js +37 -22
  34. package/dist/platform-matter.js.map +1 -1
  35. package/dist/utils.d.ts +35 -0
  36. package/dist/utils.d.ts.map +1 -1
  37. package/dist/utils.js +98 -0
  38. package/dist/utils.js.map +1 -1
  39. package/dist/utils.test.d.ts +2 -0
  40. package/dist/utils.test.d.ts.map +1 -0
  41. package/dist/utils.test.js +95 -0
  42. package/dist/utils.test.js.map +1 -0
  43. package/docs/variables/default.html +1 -1
  44. package/package.json +1 -1
  45. package/src/baseMatterAccessory.test.ts +88 -0
  46. package/src/devices-matter/BaseMatterAccessory.ts +118 -0
  47. package/src/devices-matter/ColorLightAccessory.ts +12 -12
  48. package/src/devices-matter/ColorTemperatureLightAccessory.ts +5 -7
  49. package/src/devices-matter/DimmableLightAccessory.ts +9 -9
  50. package/src/devices-matter/ExtendedColorLightAccessory.ts +14 -15
  51. package/src/devices-matter/OnOffLightAccessory.ts +8 -16
  52. package/src/devices-matter/OnOffOutletAccessory.ts +12 -7
  53. package/src/devices-matter/OnOffSwitchAccessory.ts +2 -2
  54. package/src/index.ts +4 -64
  55. package/src/platform-matter.ts +36 -22
  56. package/src/utils.test.ts +96 -0
  57. package/src/utils.ts +97 -0
@@ -0,0 +1,96 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+
3
+ import { createPlatformProxy, detectMatter } from './utils.js'
4
+
5
+ describe('detectMatter', () => {
6
+ it('returns enabled true when api.isMatterEnabled is a function that returns true', () => {
7
+ const api: any = { isMatterEnabled: () => true }
8
+ const info = detectMatter(api)
9
+ expect(info.enabled).toBe(true)
10
+ expect(info.reason).toMatch(/isMatterEnabled\(\)/)
11
+ })
12
+
13
+ it('returns enabled true when api.isMatterEnabled is a truthy property', () => {
14
+ const api: any = { isMatterEnabled: true }
15
+ const info = detectMatter(api)
16
+ expect(info.enabled).toBe(true)
17
+ expect(info.reason).toMatch(/property present/)
18
+ })
19
+
20
+ it('uses server fallback when present', () => {
21
+ const api: any = { server: { isMatterEnabled: () => false } }
22
+ const info = detectMatter(api)
23
+ expect(info.enabled).toBe(false)
24
+ expect(info.reason).toMatch(/server.isMatterEnabled\(\)/)
25
+ })
26
+
27
+ it('returns enabled false with a reason when no API is present', () => {
28
+ const api: any = {}
29
+ const info = detectMatter(api)
30
+ expect(info.enabled).toBe(false)
31
+ expect(typeof info.reason).toBe('string')
32
+ })
33
+ })
34
+
35
+ describe('createPlatformProxy', () => {
36
+ it('selects HAP platform when Matter is disabled and delegates configureAccessory', () => {
37
+ class HapStub {
38
+ public static created = false
39
+ public configured: any = undefined
40
+ constructor(public log: any, public config: any, public api: any) {
41
+ HapStub.created = true
42
+ }
43
+
44
+ configureAccessory(acc: any) {
45
+ this.configured = acc
46
+ }
47
+ }
48
+
49
+ class MatterStub {
50
+ constructor() {
51
+ throw new Error('should not be constructed')
52
+ }
53
+ }
54
+
55
+ const ProxyCtor = createPlatformProxy(HapStub as any, MatterStub as any)
56
+ const log = { info: vi.fn() }
57
+ const api = { isMatterEnabled: false }
58
+ const proxy = new (ProxyCtor as any)(log, {}, api)
59
+
60
+ // delegate should be instance of HapStub
61
+ expect(HapStub.created).toBe(true)
62
+ expect(typeof proxy.delegate.configureAccessory).toBe('function')
63
+ proxy.configureAccessory('accessory')
64
+ expect(proxy.delegate.configured).toBe('accessory')
65
+ // log should mention HAP
66
+ expect((log.info as any).mock.calls[0][0]).toMatch(/HAP/)
67
+ })
68
+
69
+ it('selects Matter platform when isMatterEnabled is true', () => {
70
+ class HapStub2 {
71
+ constructor() {
72
+ throw new Error('should not be constructed')
73
+ }
74
+ }
75
+
76
+ class MatterStub2 {
77
+ public configured: any = undefined
78
+ constructor(public log: any, public config: any, public api: any) {}
79
+
80
+ configureMatterAccessory(acc: any) {
81
+ this.configured = acc
82
+ }
83
+ }
84
+
85
+ const ProxyCtor = createPlatformProxy(HapStub2 as any, MatterStub2 as any)
86
+ const log = { info: vi.fn() }
87
+ const api = { isMatterEnabled: () => true }
88
+ const proxy = new (ProxyCtor as any)(log, {}, api)
89
+
90
+ // delegate should be instance of MatterStub2
91
+ expect(typeof proxy.delegate.configureMatterAccessory).toBe('function')
92
+ ;(proxy as any).configureMatterAccessory('macc')
93
+ expect(proxy.delegate.configured).toBe('macc')
94
+ expect((log.info as any).mock.calls[0][0]).toMatch(/Matter/)
95
+ })
96
+ })
package/src/utils.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  *
3
3
  * util.ts: @switchbot/homebridge-switchbot platform class.
4
4
  */
5
+ import type { API } from 'homebridge'
5
6
  import type { blindTilt, curtain, curtain3, device } from 'node-switchbot'
6
7
 
7
8
  import type { devicesConfig } from './settings.js'
@@ -716,3 +717,99 @@ export function cleanDeviceConfig(deviceConfig?: Record<string, Record<string, a
716
717
  }
717
718
  return undefined
718
719
  }
720
+
721
+ /**
722
+ * Detect whether Matter is enabled/available on the provided Homebridge API object.
723
+ * This encapsulates the multi-fallback detection used across the project.
724
+ */
725
+ /**
726
+ * Detect whether Matter is enabled on the provided Homebridge API object.
727
+ * Returns an object with an `enabled` boolean and an optional `reason` string
728
+ * describing which check matched (useful for diagnostics).
729
+ */
730
+ export function detectMatter(apiObj: API): { enabled: boolean, reason?: string } {
731
+ try {
732
+ const maybe = (apiObj as any).isMatterEnabled
733
+ if (typeof maybe === 'function') {
734
+ return { enabled: Boolean(maybe.call(apiObj)), reason: 'api.isMatterEnabled() returned truthy' }
735
+ }
736
+ if (typeof maybe !== 'undefined') {
737
+ return { enabled: Boolean(maybe), reason: 'api.isMatterEnabled property present' }
738
+ }
739
+
740
+ const server = (apiObj as any).server ?? (apiObj as any).homebridgeServer ?? (apiObj as any).homebridge_server
741
+ const serverMaybe = server?.isMatterEnabled
742
+ if (typeof serverMaybe === 'function') {
743
+ return { enabled: Boolean(serverMaybe.call(server)), reason: 'server.isMatterEnabled() returned truthy' }
744
+ }
745
+ if (typeof server?.isMatterEnabled !== 'undefined') {
746
+ return { enabled: Boolean(server.isMatterEnabled), reason: 'server.isMatterEnabled property present' }
747
+ }
748
+ } catch (e: any) {
749
+ return { enabled: false, reason: `error during detection: ${String(e?.message ?? e)}` }
750
+ }
751
+ return { enabled: false, reason: 'no isMatterEnabled API or server fallback detected' }
752
+ }
753
+
754
+ /**
755
+ * Backwards-compatible boolean wrapper for detectMatter.
756
+ */
757
+ export function detectMatterEnabled(apiObj: API): boolean {
758
+ return detectMatter(apiObj).enabled
759
+ }
760
+
761
+ /**
762
+ * Create a Platform proxy class that selects between two platform constructors
763
+ * (HAP vs Matter) at runtime using `detectMatter`. Returns a class suitable
764
+ * for passing to `api.registerPlatform`.
765
+ */
766
+ export function createPlatformProxy(HAPCtor: any, MatterCtor: any) {
767
+ return class PlatformProxy {
768
+ delegate: any
769
+
770
+ constructor(public readonly log: any, public readonly config: any, public readonly api: API) {
771
+ const matterInfo = detectMatter(this.api)
772
+ const isMatter = matterInfo.enabled
773
+ const reason = matterInfo.reason ? ` Reason: ${matterInfo.reason}` : ''
774
+ this.log.info?.(`Homebridge SwitchBot Plugin initializing in ${isMatter ? 'Matter' : 'HAP'} mode.${reason}`)
775
+ const PlatformCtor = isMatter ? MatterCtor : HAPCtor
776
+ this.delegate = new PlatformCtor(this.log, this.config, this.api)
777
+ }
778
+
779
+ configureAccessory(accessory: any): void {
780
+ try {
781
+ if (this.delegate && typeof this.delegate.configureAccessory === 'function') {
782
+ return this.delegate.configureAccessory(accessory)
783
+ }
784
+ } catch (e) {
785
+ // swallow — preserve previous behaviour where delegate errors don't bubble here
786
+ }
787
+ }
788
+
789
+ configureMatterAccessory?(accessory: any): void {
790
+ try {
791
+ if (this.delegate && typeof this.delegate.configureMatterAccessory === 'function') {
792
+ return this.delegate.configureMatterAccessory(accessory)
793
+ }
794
+ } catch (e) {
795
+ // swallow — delegate may not implement this or may throw
796
+ }
797
+ }
798
+
799
+ get accessories(): any {
800
+ try {
801
+ return this.delegate?.accessories
802
+ } catch (e) {
803
+ return undefined
804
+ }
805
+ }
806
+
807
+ get matterAccessories(): any {
808
+ try {
809
+ return this.delegate?.matterAccessories
810
+ } catch (e) {
811
+ return undefined
812
+ }
813
+ }
814
+ }
815
+ }