@switchbot/homebridge-switchbot 5.0.0-beta.108 → 5.0.0-beta.109

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 (148) hide show
  1. package/TODO.md +564 -0
  2. package/config.schema.json +100 -25
  3. package/dist/device-types.d.ts +15 -0
  4. package/dist/device-types.d.ts.map +1 -0
  5. package/dist/device-types.js +145 -0
  6. package/dist/device-types.js.map +1 -0
  7. package/dist/deviceFactory.d.ts +1 -1
  8. package/dist/deviceFactory.d.ts.map +1 -1
  9. package/dist/deviceFactory.js +55 -17
  10. package/dist/deviceFactory.js.map +1 -1
  11. package/dist/devices/genericDevice.d.ts +1 -1
  12. package/dist/devices/genericDevice.d.ts.map +1 -1
  13. package/dist/devices/genericDevice.js +4 -2
  14. package/dist/devices/genericDevice.js.map +1 -1
  15. package/dist/homebridge-ui/endpoints/config.d.ts +6 -0
  16. package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -0
  17. package/dist/homebridge-ui/endpoints/config.js +73 -0
  18. package/dist/homebridge-ui/endpoints/config.js.map +1 -0
  19. package/dist/homebridge-ui/endpoints/credentials.d.ts +6 -0
  20. package/dist/homebridge-ui/endpoints/credentials.d.ts.map +1 -0
  21. package/dist/homebridge-ui/endpoints/credentials.js +65 -0
  22. package/dist/homebridge-ui/endpoints/credentials.js.map +1 -0
  23. package/dist/homebridge-ui/endpoints/devices.d.ts +6 -0
  24. package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -0
  25. package/dist/homebridge-ui/endpoints/devices.js +285 -0
  26. package/dist/homebridge-ui/endpoints/devices.js.map +1 -0
  27. package/dist/homebridge-ui/endpoints/discovery.d.ts +7 -0
  28. package/dist/homebridge-ui/endpoints/discovery.d.ts.map +1 -0
  29. package/dist/homebridge-ui/endpoints/discovery.js +171 -0
  30. package/dist/homebridge-ui/endpoints/discovery.js.map +1 -0
  31. package/dist/homebridge-ui/public/index.html +144 -624
  32. package/dist/homebridge-ui/public/js/api.d.ts +15 -0
  33. package/dist/homebridge-ui/public/js/api.d.ts.map +1 -0
  34. package/dist/homebridge-ui/public/js/api.js +164 -0
  35. package/dist/homebridge-ui/public/js/api.js.map +1 -0
  36. package/dist/homebridge-ui/public/js/api.ts +189 -0
  37. package/dist/homebridge-ui/public/js/app.d.ts +2 -0
  38. package/dist/homebridge-ui/public/js/app.d.ts.map +1 -0
  39. package/dist/homebridge-ui/public/js/app.js +1069 -0
  40. package/dist/homebridge-ui/public/js/app.js.map +7 -0
  41. package/dist/homebridge-ui/public/js/app.ts +21 -0
  42. package/dist/homebridge-ui/public/js/constants.d.ts +2 -0
  43. package/dist/homebridge-ui/public/js/constants.d.ts.map +1 -0
  44. package/dist/homebridge-ui/public/js/constants.js +2 -0
  45. package/dist/homebridge-ui/public/js/constants.js.map +1 -0
  46. package/dist/homebridge-ui/public/js/constants.ts +1 -0
  47. package/dist/homebridge-ui/public/js/credentials.d.ts +3 -0
  48. package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -0
  49. package/dist/homebridge-ui/public/js/credentials.js +96 -0
  50. package/dist/homebridge-ui/public/js/credentials.js.map +1 -0
  51. package/dist/homebridge-ui/public/js/credentials.ts +100 -0
  52. package/dist/homebridge-ui/public/js/devices-delete.d.ts +2 -0
  53. package/dist/homebridge-ui/public/js/devices-delete.d.ts.map +1 -0
  54. package/dist/homebridge-ui/public/js/devices-delete.js +99 -0
  55. package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -0
  56. package/dist/homebridge-ui/public/js/devices-delete.ts +113 -0
  57. package/dist/homebridge-ui/public/js/devices.d.ts +8 -0
  58. package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -0
  59. package/dist/homebridge-ui/public/js/devices.js +71 -0
  60. package/dist/homebridge-ui/public/js/devices.js.map +1 -0
  61. package/dist/homebridge-ui/public/js/devices.ts +78 -0
  62. package/dist/homebridge-ui/public/js/discovery.d.ts +3 -0
  63. package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -0
  64. package/dist/homebridge-ui/public/js/discovery.js +107 -0
  65. package/dist/homebridge-ui/public/js/discovery.js.map +1 -0
  66. package/dist/homebridge-ui/public/js/discovery.ts +123 -0
  67. package/dist/homebridge-ui/public/js/logger.d.ts +6 -0
  68. package/dist/homebridge-ui/public/js/logger.d.ts.map +1 -0
  69. package/dist/homebridge-ui/public/js/logger.js +12 -0
  70. package/dist/homebridge-ui/public/js/logger.js.map +1 -0
  71. package/dist/homebridge-ui/public/js/logger.ts +11 -0
  72. package/dist/homebridge-ui/public/js/modal.d.ts +5 -0
  73. package/dist/homebridge-ui/public/js/modal.d.ts.map +1 -0
  74. package/dist/homebridge-ui/public/js/modal.js +26 -0
  75. package/dist/homebridge-ui/public/js/modal.js.map +1 -0
  76. package/dist/homebridge-ui/public/js/modal.ts +28 -0
  77. package/dist/homebridge-ui/public/js/modals.d.ts +2 -0
  78. package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -0
  79. package/dist/homebridge-ui/public/js/modals.js +132 -0
  80. package/dist/homebridge-ui/public/js/modals.js.map +1 -0
  81. package/dist/homebridge-ui/public/js/modals.ts +153 -0
  82. package/dist/homebridge-ui/public/js/render.d.ts +6 -0
  83. package/dist/homebridge-ui/public/js/render.d.ts.map +1 -0
  84. package/dist/homebridge-ui/public/js/render.js +166 -0
  85. package/dist/homebridge-ui/public/js/render.js.map +1 -0
  86. package/dist/homebridge-ui/public/js/render.ts +190 -0
  87. package/dist/homebridge-ui/public/js/toast.d.ts +6 -0
  88. package/dist/homebridge-ui/public/js/toast.d.ts.map +1 -0
  89. package/dist/homebridge-ui/public/js/toast.js +29 -0
  90. package/dist/homebridge-ui/public/js/toast.js.map +1 -0
  91. package/dist/homebridge-ui/public/js/toast.ts +37 -0
  92. package/dist/homebridge-ui/public/js/types.d.ts +23 -0
  93. package/dist/homebridge-ui/public/js/types.d.ts.map +1 -0
  94. package/dist/homebridge-ui/public/js/types.js +2 -0
  95. package/dist/homebridge-ui/public/js/types.js.map +1 -0
  96. package/dist/homebridge-ui/public/js/types.ts +26 -0
  97. package/dist/homebridge-ui/server.d.ts +1 -3
  98. package/dist/homebridge-ui/server.d.ts.map +1 -1
  99. package/dist/homebridge-ui/server.js +10 -561
  100. package/dist/homebridge-ui/server.js.map +1 -1
  101. package/dist/homebridge-ui/utils/config-parser.d.ts +35 -0
  102. package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -0
  103. package/dist/homebridge-ui/utils/config-parser.js +87 -0
  104. package/dist/homebridge-ui/utils/config-parser.js.map +1 -0
  105. package/dist/homebridge-ui/utils/logger.d.ts +7 -0
  106. package/dist/homebridge-ui/utils/logger.d.ts.map +1 -0
  107. package/dist/homebridge-ui/utils/logger.js +17 -0
  108. package/dist/homebridge-ui/utils/logger.js.map +1 -0
  109. package/dist/platform.d.ts.map +1 -1
  110. package/dist/platform.js +6 -2
  111. package/dist/platform.js.map +1 -1
  112. package/dist/switchbotClient.d.ts.map +1 -1
  113. package/dist/switchbotClient.js +2 -0
  114. package/dist/switchbotClient.js.map +1 -1
  115. package/docs/variables/default.html +1 -1
  116. package/eslint.config.js +5 -0
  117. package/nodemon.json +2 -2
  118. package/package.json +20 -10
  119. package/scripts/build-ui.js +36 -0
  120. package/scripts/free-dev-ports.mjs +105 -0
  121. package/scripts/sync-device-types.mjs +28 -0
  122. package/src/device-types.ts +145 -0
  123. package/src/deviceFactory.ts +71 -31
  124. package/src/devices/genericDevice.ts +5 -2
  125. package/src/homebridge-ui/endpoints/config.ts +79 -0
  126. package/src/homebridge-ui/endpoints/credentials.ts +74 -0
  127. package/src/homebridge-ui/endpoints/devices.ts +321 -0
  128. package/src/homebridge-ui/endpoints/discovery.ts +191 -0
  129. package/src/homebridge-ui/public/index.html +144 -624
  130. package/src/homebridge-ui/public/js/api.ts +189 -0
  131. package/src/homebridge-ui/public/js/app.ts +21 -0
  132. package/src/homebridge-ui/public/js/constants.ts +1 -0
  133. package/src/homebridge-ui/public/js/credentials.ts +100 -0
  134. package/src/homebridge-ui/public/js/devices-delete.ts +113 -0
  135. package/src/homebridge-ui/public/js/devices.ts +78 -0
  136. package/src/homebridge-ui/public/js/discovery.ts +123 -0
  137. package/src/homebridge-ui/public/js/logger.ts +11 -0
  138. package/src/homebridge-ui/public/js/modal.ts +28 -0
  139. package/src/homebridge-ui/public/js/modals.ts +153 -0
  140. package/src/homebridge-ui/public/js/render.ts +190 -0
  141. package/src/homebridge-ui/public/js/toast.ts +37 -0
  142. package/src/homebridge-ui/public/js/types.ts +26 -0
  143. package/src/homebridge-ui/server.ts +11 -647
  144. package/src/homebridge-ui/utils/config-parser.ts +108 -0
  145. package/src/homebridge-ui/utils/logger.ts +17 -0
  146. package/src/platform.ts +6 -2
  147. package/src/switchbotClient.ts +2 -0
  148. package/switchbot-homebridge-switchbot-5.0.0.tgz +0 -0
@@ -0,0 +1,108 @@
1
+ import type { HomebridgePluginUiServer } from '@homebridge/plugin-ui-utils'
2
+
3
+ import fs from 'node:fs/promises'
4
+
5
+ import { uiLog } from './logger.js'
6
+
7
+ // Module-scope regex pattern to avoid recompilation
8
+ export const SWITCHBOT_PLATFORM_REGEX = /switchbot/i
9
+
10
+ /**
11
+ * Get reference to the devices array in platform config
12
+ */
13
+ export function getDevicesRef(platform: any): any[] {
14
+ if (!platform || typeof platform !== 'object') {
15
+ return []
16
+ }
17
+
18
+ if (Array.isArray(platform.devices)) {
19
+ return platform.devices
20
+ }
21
+
22
+ platform.devices = []
23
+ return platform.devices
24
+ }
25
+
26
+ /**
27
+ * Get all device arrays from platform config
28
+ */
29
+ export function getDeviceArrays(platform: any): any[][] {
30
+ const rootDevices = getDevicesRef(platform)
31
+ return [rootDevices]
32
+ }
33
+
34
+ /**
35
+ * Get all unique devices from platform config
36
+ */
37
+ export function getAllDevices(platform: any): any[] {
38
+ const all = getDevicesRef(platform)
39
+ const seen = new Set<string>()
40
+
41
+ return all.filter((d: any) => {
42
+ const id = String(d?.deviceId ?? d?.id ?? '').trim().toLowerCase()
43
+ if (!id || seen.has(id)) {
44
+ return false
45
+ }
46
+ seen.add(id)
47
+ return true
48
+ })
49
+ }
50
+
51
+ /**
52
+ * Get credential from platform config
53
+ */
54
+ export function getCredential(platform: any, key: 'openApiToken' | 'openApiSecret'): string | undefined {
55
+ return platform?.[key]
56
+ }
57
+
58
+ /**
59
+ * Set credential in platform config
60
+ */
61
+ export function setCredential(platform: any, key: 'openApiToken' | 'openApiSecret', value: string): void {
62
+ if (!platform || typeof platform !== 'object') {
63
+ return
64
+ }
65
+
66
+ platform[key] = value
67
+ }
68
+
69
+ /**
70
+ * Find and parse the SwitchBot platform config from Homebridge config file
71
+ */
72
+ export async function getSwitchBotPlatformConfig(server: HomebridgePluginUiServer) {
73
+ const cfgPath = server.homebridgeConfigPath
74
+ if (!cfgPath) {
75
+ throw new Error('HOMEBRIDGE_CONFIG_PATH not set')
76
+ }
77
+
78
+ const raw = await fs.readFile(cfgPath, 'utf-8')
79
+ const cfg = JSON.parse(raw)
80
+
81
+ const platforms = Array.isArray(cfg.platforms) ? cfg.platforms : []
82
+
83
+ const candidates = platforms.filter((p: any) => {
84
+ const platformName = p.platform || p.name || ''
85
+ return !!platformName && (SWITCHBOT_PLATFORM_REGEX.test(String(platformName)) || String(platformName).toLowerCase() === '@switchbot/homebridge-switchbot')
86
+ })
87
+
88
+ uiLog.info(`Found ${candidates.length} SwitchBot candidate(s)`)
89
+
90
+ const platform = candidates.find((p: any) => {
91
+ const name = String(p.platform || '').toLowerCase()
92
+ return name === 'switchbot' || name.includes('switchbot')
93
+ })
94
+
95
+ if (!platform) {
96
+ throw new Error('SwitchBot platform not found in config. Please add the plugin configuration first.')
97
+ }
98
+
99
+ uiLog.info(`Using SwitchBot platform: ${platform.name || platform.platform || 'SwitchBot'}`)
100
+ return { platform, cfg, cfgPath }
101
+ }
102
+
103
+ /**
104
+ * Save the Homebridge config file
105
+ */
106
+ export async function saveConfig(cfgPath: string, cfg: any): Promise<void> {
107
+ await fs.writeFile(cfgPath, JSON.stringify(cfg, null, 2), 'utf-8')
108
+ }
@@ -0,0 +1,17 @@
1
+ /* eslint-disable no-console */
2
+ const PREFIX = '[SwitchBot UI]'
3
+
4
+ export const uiLog = {
5
+ info: (message: string, ...parameters: any[]) => {
6
+ console.log(PREFIX, message, ...parameters)
7
+ },
8
+ warn: (message: string, ...parameters: any[]) => {
9
+ console.warn(PREFIX, message, ...parameters)
10
+ },
11
+ error: (message: string, ...parameters: any[]) => {
12
+ console.error(PREFIX, message, ...parameters)
13
+ },
14
+ debug: (message: string, ...parameters: any[]) => {
15
+ console.debug(PREFIX, message, ...parameters)
16
+ },
17
+ }
package/src/platform.ts CHANGED
@@ -96,10 +96,14 @@ const DEVICE_MATTER_CLUSTERS: Record<string, any> = {
96
96
  },
97
97
  }, // Switch in HAP, RobotVacuumCleaner in Matter
98
98
  curtain: {
99
- windowCovering: {},
99
+ windowCovering: {
100
+ type: 4, // Drapery - safe default for LF conformance
101
+ },
100
102
  }, // WindowCovering → WindowCovering (includes curtain3, rollershade variants via normalization)
101
103
  blindtilt: {
102
- windowCovering: {},
104
+ windowCovering: {
105
+ type: 8, // TiltBlindLiftAndTilt - supports tilt feature
106
+ },
103
107
  }, // WindowCovering with tilt → WindowCovering
104
108
  fan: {
105
109
  onOff: { onOff: false },
@@ -43,6 +43,8 @@ export class SwitchBotClient implements ISwitchBotClient {
43
43
  enableRetry: true, // Retry with exponential backoff
44
44
  enableCircuitBreaker: true, // Circuit breaker per connection type
45
45
  enableMetrics: true, // Connection tracking and statistics
46
+ enableBLE: true, // Enable BLE scanning by default
47
+ scanDuration: 5000, // BLE scan duration in milliseconds
46
48
  ...(typeof (this.cfg as any)?.nodeClientConfig === 'object' && (this.cfg as any).nodeClientConfig),
47
49
  })
48
50
  this.logger?.info?.('SwitchBot client initialized with native resilience features')