@switchbot/homebridge-switchbot 5.0.0-beta.111 → 5.0.0-beta.113
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/MIGRATION.md +10 -0
- package/README.md +43 -0
- package/TODO.md +263 -0
- package/config.schema.json +27 -10
- package/dist/device-types.d.ts.map +1 -1
- package/dist/device-types.js +93 -63
- package/dist/device-types.js.map +1 -1
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +55 -33
- package/dist/deviceFactory.js.map +1 -1
- package/dist/devices/genericDevice.d.ts +12 -1
- package/dist/devices/genericDevice.d.ts.map +1 -1
- package/dist/devices/genericDevice.js +121 -1
- package/dist/devices/genericDevice.js.map +1 -1
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +51 -0
- package/dist/errors.js.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/endpoints/devices.js +80 -1
- package/dist/homebridge-ui/endpoints/devices.js.map +1 -1
- package/dist/homebridge-ui/endpoints/discovery.d.ts.map +1 -1
- package/dist/homebridge-ui/endpoints/discovery.js +73 -41
- package/dist/homebridge-ui/endpoints/discovery.js.map +1 -1
- package/dist/homebridge-ui/public/css/styles.css +209 -16
- package/dist/homebridge-ui/public/index.html +87 -56
- package/dist/homebridge-ui/public/js/api.d.ts +24 -1
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/api.js +33 -2
- package/dist/homebridge-ui/public/js/api.js.map +1 -1
- package/dist/homebridge-ui/public/js/api.ts +52 -3
- package/dist/homebridge-ui/public/js/app.js +1604 -143
- package/dist/homebridge-ui/public/js/app.js.map +3 -3
- package/dist/homebridge-ui/public/js/app.ts +2 -1
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/devices.js +2 -0
- package/dist/homebridge-ui/public/js/devices.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices.ts +13 -1
- package/dist/homebridge-ui/public/js/discovery.d.ts +1 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.js +1244 -124
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.ts +1344 -142
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/modals.js +42 -0
- package/dist/homebridge-ui/public/js/modals.js.map +1 -1
- package/dist/homebridge-ui/public/js/modals.ts +50 -1
- package/dist/homebridge-ui/public/js/render.d.ts +3 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/render.js +389 -36
- package/dist/homebridge-ui/public/js/render.js.map +1 -1
- package/dist/homebridge-ui/public/js/render.ts +421 -38
- package/dist/platform.d.ts +1 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +3 -4
- package/dist/platform.js.map +1 -1
- package/dist/switchbotClient.d.ts.map +1 -1
- package/dist/switchbotClient.js +51 -5
- package/dist/switchbotClient.js.map +1 -1
- package/docs/assets/highlight.css +9 -2
- package/docs/index.html +28 -2
- package/docs/variables/default.html +1 -1
- package/package.json +9 -8
- package/src/device-types.ts +95 -64
- package/src/deviceFactory.ts +55 -33
- package/src/devices/genericDevice.ts +113 -1
- package/src/errors.ts +43 -0
- package/src/homebridge-ui/endpoints/devices.ts +82 -1
- package/src/homebridge-ui/endpoints/discovery.ts +78 -44
- package/src/homebridge-ui/public/css/styles.css +209 -16
- package/src/homebridge-ui/public/index.html +87 -56
- package/src/homebridge-ui/public/js/api.ts +52 -3
- package/src/homebridge-ui/public/js/app.ts +2 -1
- package/src/homebridge-ui/public/js/devices.ts +13 -1
- package/src/homebridge-ui/public/js/discovery.ts +1344 -142
- package/src/homebridge-ui/public/js/modals.ts +50 -1
- package/src/homebridge-ui/public/js/render.ts +421 -38
- package/src/platform.ts +3 -4
- package/src/switchbotClient.ts +44 -9
- package/test/e2e/run-e2e.spec.ts +12 -10
- package/test/helpers/matter-harness.ts +2 -2
- package/test/matter-integration.spec.ts +21 -0
- package/todo/COMPLETED.md +313 -0
- package/todo/TODO.md +80 -66
- package/switchbot-homebridge-switchbot-5.0.0.tgz +0 -0
package/src/switchbotClient.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SwitchBotPluginConfig } from './settings.js'
|
|
2
|
+
import { SwitchbotOperationError, SwitchbotAuthenticationError, CharacteristicMissingError } from './errors.js'
|
|
2
3
|
|
|
3
4
|
export interface ISwitchBotClient {
|
|
4
5
|
init(): Promise<void>
|
|
@@ -93,8 +94,17 @@ export class SwitchBotClient implements ISwitchBotClient {
|
|
|
93
94
|
if (this.client?.getDevice) {
|
|
94
95
|
try {
|
|
95
96
|
return await this.client.getDevice(id)
|
|
96
|
-
} catch (e) {
|
|
97
|
-
|
|
97
|
+
} catch (e: any) {
|
|
98
|
+
if (e instanceof SwitchbotAuthenticationError) {
|
|
99
|
+
this.logger?.error?.(`Authentication error for getDevice(${id}):`, e.message)
|
|
100
|
+
throw e
|
|
101
|
+
} else if (e instanceof SwitchbotOperationError) {
|
|
102
|
+
this.logger?.warn?.(`Operation error for getDevice(${id}):`, e.message, e.code)
|
|
103
|
+
} else if (e instanceof CharacteristicMissingError) {
|
|
104
|
+
this.logger?.warn?.(`Characteristic missing for getDevice(${id}):`, e.characteristic)
|
|
105
|
+
} else {
|
|
106
|
+
this.logger?.warn?.(`Client getDevice failed for ${id}, trying OpenAPI fallback:`, e)
|
|
107
|
+
}
|
|
98
108
|
}
|
|
99
109
|
}
|
|
100
110
|
// Fallback: call OpenAPI via HTTP
|
|
@@ -104,7 +114,7 @@ export class SwitchBotClient implements ISwitchBotClient {
|
|
|
104
114
|
const resp = await this.fetchWithTimeoutAndRetry(url, opts)
|
|
105
115
|
return resp.json()
|
|
106
116
|
}
|
|
107
|
-
throw new
|
|
117
|
+
throw new SwitchbotOperationError('No SwitchBot client available', 'no_client')
|
|
108
118
|
}
|
|
109
119
|
|
|
110
120
|
async getDevices(): Promise<any[]> {
|
|
@@ -149,7 +159,14 @@ export class SwitchBotClient implements ISwitchBotClient {
|
|
|
149
159
|
try {
|
|
150
160
|
const out = await this._doSetDeviceState(id, entry.body)
|
|
151
161
|
for (const r of entry.resolvers) r.resolve(out)
|
|
152
|
-
} catch (e) {
|
|
162
|
+
} catch (e: any) {
|
|
163
|
+
if (e instanceof SwitchbotAuthenticationError) {
|
|
164
|
+
this.logger?.error?.(`Authentication error for setDeviceState(${id}):`, e.message)
|
|
165
|
+
} else if (e instanceof SwitchbotOperationError) {
|
|
166
|
+
this.logger?.warn?.(`Operation error for setDeviceState(${id}):`, e.message, e.code)
|
|
167
|
+
} else if (e instanceof CharacteristicMissingError) {
|
|
168
|
+
this.logger?.warn?.(`Characteristic missing for setDeviceState(${id}):`, e.characteristic)
|
|
169
|
+
}
|
|
153
170
|
for (const r of entry.resolvers) r.reject(e)
|
|
154
171
|
}
|
|
155
172
|
}, this.writeDebounceMs)
|
|
@@ -166,8 +183,17 @@ export class SwitchBotClient implements ISwitchBotClient {
|
|
|
166
183
|
const result = await this.client.setDeviceState(id, body)
|
|
167
184
|
this.logger?.debug?.(`[${id}] client.setDeviceState() response:`, result)
|
|
168
185
|
return result
|
|
169
|
-
} catch (e) {
|
|
170
|
-
|
|
186
|
+
} catch (e: any) {
|
|
187
|
+
if (e instanceof SwitchbotAuthenticationError) {
|
|
188
|
+
this.logger?.error?.(`Authentication error for setDeviceState(${id}):`, e.message)
|
|
189
|
+
throw e
|
|
190
|
+
} else if (e instanceof SwitchbotOperationError) {
|
|
191
|
+
this.logger?.warn?.(`Operation error for setDeviceState(${id}):`, e.message, e.code)
|
|
192
|
+
} else if (e instanceof CharacteristicMissingError) {
|
|
193
|
+
this.logger?.warn?.(`Characteristic missing for setDeviceState(${id}):`, e.characteristic)
|
|
194
|
+
} else {
|
|
195
|
+
this.logger?.warn?.(`Client setDeviceState failed for ${id}, trying fallback:`, e)
|
|
196
|
+
}
|
|
171
197
|
}
|
|
172
198
|
}
|
|
173
199
|
|
|
@@ -178,8 +204,17 @@ export class SwitchBotClient implements ISwitchBotClient {
|
|
|
178
204
|
const result = await this.client.sendCommand(id, body)
|
|
179
205
|
this.logger?.debug?.(`[${id}] client.sendCommand() response:`, result)
|
|
180
206
|
return result
|
|
181
|
-
} catch (e) {
|
|
182
|
-
|
|
207
|
+
} catch (e: any) {
|
|
208
|
+
if (e instanceof SwitchbotAuthenticationError) {
|
|
209
|
+
this.logger?.error?.(`Authentication error for sendCommand(${id}):`, e.message)
|
|
210
|
+
throw e
|
|
211
|
+
} else if (e instanceof SwitchbotOperationError) {
|
|
212
|
+
this.logger?.warn?.(`Operation error for sendCommand(${id}):`, e.message, e.code)
|
|
213
|
+
} else if (e instanceof CharacteristicMissingError) {
|
|
214
|
+
this.logger?.warn?.(`Characteristic missing for sendCommand(${id}):`, e.characteristic)
|
|
215
|
+
} else {
|
|
216
|
+
this.logger?.warn?.(`Client sendCommand failed for ${id}, trying OpenAPI:`, e)
|
|
217
|
+
}
|
|
183
218
|
}
|
|
184
219
|
}
|
|
185
220
|
|
|
@@ -203,7 +238,7 @@ export class SwitchBotClient implements ISwitchBotClient {
|
|
|
203
238
|
return result
|
|
204
239
|
}
|
|
205
240
|
|
|
206
|
-
throw new
|
|
241
|
+
throw new SwitchbotOperationError('No SwitchBot client available for setDeviceState', 'no_client')
|
|
207
242
|
}
|
|
208
243
|
|
|
209
244
|
async destroy(): Promise<void> {
|
package/test/e2e/run-e2e.spec.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import { execFile } from 'node:child_process'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { promisify } from 'node:util'
|
|
4
|
+
import { describe, it } from 'vitest'
|
|
5
5
|
|
|
6
6
|
const execFileP = promisify(execFile)
|
|
7
7
|
|
|
8
|
-
describe('
|
|
8
|
+
describe('e2e scripts (manual-run harness)', () => {
|
|
9
9
|
if (!process.env.RUN_E2E) {
|
|
10
|
-
|
|
10
|
+
it.skip('e2e disabled - set RUN_E2E=true to enable', () => {})
|
|
11
11
|
return
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
it('should run configured e2e scripts sequentially', async () => {
|
|
15
15
|
const repoRoot = path.resolve(__dirname, '../../')
|
|
16
16
|
const scriptsDir = path.join(repoRoot, 'scripts', 'e2e')
|
|
17
17
|
|
|
18
|
-
const scriptsToRun: { envVar: string
|
|
18
|
+
const scriptsToRun: { envVar: string, script: string }[] = [
|
|
19
19
|
{ envVar: 'LIGHT_ACCESSORY_ID', script: 'light-e2e.sh' },
|
|
20
20
|
{ envVar: 'FAN_ACCESSORY_ID', script: 'fan-e2e.sh' },
|
|
21
21
|
{ envVar: 'CURTAIN_ACCESSORY_ID', script: 'curtain-e2e.sh' },
|
|
@@ -32,7 +32,7 @@ describe('E2E scripts (manual-run harness)', () => {
|
|
|
32
32
|
|
|
33
33
|
const scriptPath = path.join(scriptsDir, s.script)
|
|
34
34
|
// Forward environment so scripts can read HB_URL / HB_TOKEN / <ACCESSORY_ID>
|
|
35
|
-
const env =
|
|
35
|
+
const env = { ...process.env }
|
|
36
36
|
|
|
37
37
|
try {
|
|
38
38
|
// eslint-disable-next-line no-console
|
|
@@ -40,7 +40,9 @@ describe('E2E scripts (manual-run harness)', () => {
|
|
|
40
40
|
const { stdout, stderr } = await execFileP('bash', [scriptPath], { env })
|
|
41
41
|
// eslint-disable-next-line no-console
|
|
42
42
|
console.log(stdout)
|
|
43
|
-
if (stderr)
|
|
43
|
+
if (stderr) {
|
|
44
|
+
console.error(stderr)
|
|
45
|
+
}
|
|
44
46
|
} catch (e: any) {
|
|
45
47
|
// bubble up as test failure
|
|
46
48
|
throw new Error(`Script ${s.script} failed: ${e.message}`)
|
|
@@ -47,7 +47,7 @@ export function makeFakeApiWithoutMatter() {
|
|
|
47
47
|
isMatterEnabled: () => false,
|
|
48
48
|
hap: makeFakeHap(),
|
|
49
49
|
platformAccessory: PlatformAccessory,
|
|
50
|
-
registerPlatformAccessories: (
|
|
51
|
-
on: (
|
|
50
|
+
registerPlatformAccessories: () => {},
|
|
51
|
+
on: () => {},
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -47,6 +47,27 @@ describe('Matter integration harness', () => {
|
|
|
47
47
|
expect(wcType).not.toBe(4)
|
|
48
48
|
})
|
|
49
49
|
|
|
50
|
+
it('registers RGBIC Neon Wire Rope Light as lightstrip with conformant ColorControl defaults', async () => {
|
|
51
|
+
const matterApi = makeFakeMatterApi()
|
|
52
|
+
const api = makeFakeApiWithMatter(matterApi)
|
|
53
|
+
|
|
54
|
+
const platform = new SwitchBotMatterPlatform(console as any, {
|
|
55
|
+
devices: [{ id: 'neon-1', type: 'RGBIC Neon Wire Rope Light', name: 'Family Room Neon Wire Rope Light' }],
|
|
56
|
+
enableMatter: true,
|
|
57
|
+
preferMatter: true,
|
|
58
|
+
} as any, api as any)
|
|
59
|
+
|
|
60
|
+
await (platform as any).registerMatterAccessories()
|
|
61
|
+
|
|
62
|
+
const regs = matterApi.getRegistered()
|
|
63
|
+
expect(regs.length).toBeGreaterThanOrEqual(1)
|
|
64
|
+
const neon = regs.find((r: any) => r?.context?.deviceId === 'neon-1')
|
|
65
|
+
expect(neon).toBeDefined()
|
|
66
|
+
expect(neon?.context?.type).toBe('lightstrip')
|
|
67
|
+
expect(neon?.clusters?.colorControl).toBeDefined()
|
|
68
|
+
expect(neon?.clusters?.colorControl?.colorMode).toBe(0)
|
|
69
|
+
})
|
|
70
|
+
|
|
50
71
|
it('registers Matter accessories when Matter API available', async () => {
|
|
51
72
|
// Instantiate the real Matter platform directly to test its registration path
|
|
52
73
|
const matterApi = makeFakeMatterApi()
|
package/todo/COMPLETED.md
CHANGED
|
@@ -1,9 +1,309 @@
|
|
|
1
|
+
# Batch Import & Discovery UI Enhancements ✅ COMPLETED
|
|
2
|
+
|
|
3
|
+
- [x] Add checkboxes to select multiple devices
|
|
4
|
+
- Users can now select multiple discovered devices using checkboxes in the discovery UI for batch actions.
|
|
5
|
+
- [x] Add "Add Selected to Config" button
|
|
6
|
+
- A prominent "Add Selected to Config" button enables batch import of all selected devices, streamlining onboarding.
|
|
7
|
+
- [x] Implement bulk configuration with smart defaults
|
|
8
|
+
- When importing multiple devices, the system applies smart defaults (type, name, MAC, etc.) and auto-fills config fields, reducing manual entry and errors.
|
|
9
|
+
- [x] Show firmware update available indicators
|
|
10
|
+
- Devices with available firmware updates display an orange "Update Available" badge in the discovery UI.
|
|
11
|
+
- [x] Show offline/unreachable warnings
|
|
12
|
+
- Devices that are offline or unreachable show a red "Offline" badge, based on status or last-seen timestamp.
|
|
13
|
+
- [x] Add "Needs Attention" section at top
|
|
14
|
+
- Devices needing action (low battery, firmware update, offline) are grouped in a "Needs Attention" section at the top of the discovery UI for quick access.
|
|
15
|
+
|
|
16
|
+
**Status:** All batch import and discovery UI features are implemented and live. Only battery level trending (historical data) remains as a future enhancement.
|
|
17
|
+
# Integration: node-switchbot Beta Updates (March 2026)
|
|
18
|
+
|
|
19
|
+
### Duplicate Detection ✅ COMPLETED
|
|
20
|
+
|
|
21
|
+
- [x] The UI disables the "Add to Config" button and shows an "Already Added" badge for devices already in the config, preventing duplicate entries. Badges for recommended connection (BLE/API) are also shown based on signal/device type.
|
|
22
|
+
|
|
23
|
+
**Status:** Duplicate detection is enforced in the UI, so users cannot add the same device twice. Connection recommendation badges are also displayed.
|
|
24
|
+
# Integration: node-switchbot Beta Updates (March 2026)
|
|
25
|
+
|
|
26
|
+
### One-Click Device Import ✅ COMPLETED
|
|
27
|
+
|
|
28
|
+
- [x] Add "Add to Config" button next to each discovered device. Dramatically speeds up onboarding, reduces manual steps for users.
|
|
29
|
+
|
|
30
|
+
**Status:** Each discovered device in the UI now has an "Add to Config" button. This enables one-click import directly from the discovery list.
|
|
31
|
+
|
|
32
|
+
### Auto-populate Device Config Modal ✅ COMPLETED
|
|
33
|
+
|
|
34
|
+
- [x] When importing, the config modal is auto-filled with discovered values (name, type, MAC, etc). Reduces user error and makes adding devices nearly frictionless.
|
|
35
|
+
|
|
36
|
+
**Status:** The import modal pre-fills all relevant fields with discovered device data, streamlining the import process.
|
|
37
|
+
|
|
38
|
+
### Pre-fill MAC Address for BLE Devices ✅ COMPLETED
|
|
39
|
+
|
|
40
|
+
- [x] The import modal auto-fills the MAC address field with the discovered device's address, ensuring BLE devices are always added with the correct MAC.
|
|
41
|
+
|
|
42
|
+
**Status:** The MAC address is pre-filled in the config modal for BLE devices, preventing user error and connection issues.
|
|
43
|
+
|
|
44
|
+
### Duplicate Detection ✅ COMPLETED
|
|
45
|
+
|
|
46
|
+
- [x] The UI disables the "Add to Config" button and shows an "Already Added" badge for devices already in the config, preventing duplicate entries.
|
|
47
|
+
|
|
48
|
+
**Status:** Duplicate detection is enforced in the UI, so users cannot add the same device twice.
|
|
49
|
+
# Integration: node-switchbot Beta Updates (March 2026)
|
|
50
|
+
|
|
51
|
+
### Duplicate Detection ✅ COMPLETED
|
|
52
|
+
|
|
53
|
+
- [x] The UI disables the "Add to Config" button and shows an "Already Added" badge for devices already in the config, preventing duplicate entries.
|
|
54
|
+
|
|
55
|
+
**Status:** Duplicate detection is enforced in the UI, so users cannot add the same device twice.
|
|
56
|
+
# Integration: node-switchbot Beta Updates (March 2026)
|
|
57
|
+
|
|
58
|
+
### Pre-fill MAC Address for BLE Devices ✅ COMPLETED
|
|
59
|
+
|
|
60
|
+
- [x] The import modal auto-fills the MAC address field with the discovered device's address, ensuring BLE devices are always added with the correct MAC.
|
|
61
|
+
|
|
62
|
+
**Status:** The MAC address is pre-filled in the config modal for BLE devices, preventing user error and connection issues.
|
|
63
|
+
# Integration: node-switchbot Beta Updates (March 2026)
|
|
64
|
+
|
|
65
|
+
### One-Click Device Import ✅ COMPLETED
|
|
66
|
+
|
|
67
|
+
- [x] Add "Add to Config" button next to each discovered device. Dramatically speeds up onboarding, reduces manual steps for users.
|
|
68
|
+
|
|
69
|
+
**Status:** Each discovered device in the UI now has an "Add to Config" button. This enables one-click import directly from the discovery list.
|
|
70
|
+
|
|
71
|
+
### Auto-populate Device Config Modal ✅ COMPLETED
|
|
72
|
+
|
|
73
|
+
- [x] When importing, the config modal is auto-filled with discovered values (name, type, MAC, etc). Reduces user error and makes adding devices nearly frictionless.
|
|
74
|
+
|
|
75
|
+
**Status:** The import modal pre-fills all relevant fields with discovered device data, streamlining the import process.
|
|
76
|
+
# Integration: node-switchbot Beta Updates (March 2026)
|
|
77
|
+
- [x] Update device registry and class mapping to match node-switchbot
|
|
78
|
+
- [x] Add notification handling for BLE devices (per-command notification futures, unsolicited notification logging)
|
|
79
|
+
|
|
80
|
+
- [x] Map new device types to Homebridge plugin (HubMini Matter, Hub3, Keypad Vision/Pro, Plug Mini EU, Roller Shade, Garage Door Opener, Floor Lamp, Art Frame, RGBICWW variants, K10/K11/K20/S10/S20 vacuums, Lock Lite/Vision/Pro/WiFi, Circulator Fan, Smart Thermostat Radiator, Climate Panel, Evaporative Humidifier, Strip Light 3, etc.)
|
|
81
|
+
- [x] Expose new device features in UI (air quality, preset modes, calibration, direction, multi-command, extended info, segmented control, etc.)
|
|
82
|
+
- [x] Integrate BLE encryption for all supported devices (relay, lock, air purifier, light strip, bulb, etc.)
|
|
83
|
+
# BLE Response Length Validation ✅ COMPLETED
|
|
84
|
+
|
|
85
|
+
- [x] Implement response length validation for BLE status parsing
|
|
86
|
+
|
|
87
|
+
**Status:** All BLE status parsing now validates the response buffer/array length before parsing. Invalid responses are logged and rejected, improving robustness and diagnostics for all BLE devices.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
# Error Class Handling Integration ✅ COMPLETED
|
|
91
|
+
|
|
92
|
+
- [x] Add support for new error classes and improved error handling (SwitchbotOperationError, SwitchbotAuthenticationError, CharacteristicMissingError)
|
|
93
|
+
|
|
94
|
+
**Status:** The plugin now imports and uses node-switchbot v4 error classes, with robust instanceof-based handling and compatible fallbacks. All error types are logged and surfaced appropriately, and the code is ready for future node-switchbot error model changes.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
### Batch Enable/Disable Devices ✅ COMPLETED
|
|
98
|
+
|
|
99
|
+
- [x] Allow batch enable/disable of devices
|
|
100
|
+
|
|
101
|
+
**Status:** The UI now provides 'Enable Selected' and 'Disable Selected' buttons, allowing users to batch enable or disable devices directly from the discovery view.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### Batch Operation Progress Indicator ✅ COMPLETED
|
|
106
|
+
|
|
107
|
+
- [x] Show progress for batch operations
|
|
108
|
+
|
|
109
|
+
**Status:** The UI now displays a progress indicator during batch add/configure operations, giving users real-time feedback on operation status and completion.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### Real-Time RSSI Updates During Scan ✅ COMPLETED
|
|
114
|
+
|
|
115
|
+
- [x] Update RSSI values in real-time during scan
|
|
116
|
+
|
|
117
|
+
**Status:** The UI now polls for BLE scan results and updates device RSSI values live during the scan window, providing real-time signal strength feedback.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### Needs Attention Section in Discovery UI ✅ COMPLETED
|
|
122
|
+
|
|
123
|
+
- [x] Add 'Needs Attention' section at the top of the device discovery UI
|
|
124
|
+
|
|
125
|
+
**Status:** Devices with low battery (<20%), firmware updates available, or offline/unreachable status are now aggregated and displayed in a prominent 'Needs Attention' section at the top of the discovery UI. This helps users quickly identify and address devices that require action.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
1
129
|
# Completed TODOs
|
|
2
130
|
|
|
131
|
+
### Firmware Update Available Indicator ✅ COMPLETED
|
|
132
|
+
|
|
133
|
+
### Offline/Unreachable Warning Indicator ✅ COMPLETED
|
|
134
|
+
|
|
135
|
+
- [x] Show offline/unreachable warnings
|
|
136
|
+
|
|
137
|
+
**Status:** Devices that are offline or unreachable (either via a boolean property or if last seen > 1 hour ago) now display a red 'Offline' badge in the discovery UI next to the device name.
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
- [x] Show firmware update available indicators
|
|
141
|
+
|
|
142
|
+
**Status:** Devices with a firmware update available now display an orange 'Update Available' badge in the discovery UI next to the device name.
|
|
143
|
+
|
|
144
|
+
|
|
3
145
|
This file tracks all completed features and improvements for the SwitchBot Homebridge Plugin.
|
|
4
146
|
|
|
5
147
|
---
|
|
6
148
|
|
|
149
|
+
## Recent Completed Work
|
|
150
|
+
|
|
151
|
+
### Connection Testing (First Slice) ✅ COMPLETED
|
|
152
|
+
|
|
153
|
+
- [x] Added "Test Connection" button per device (discovered and configured cards)
|
|
154
|
+
- [x] Added backend connectivity check endpoint (`/test-connection`)
|
|
155
|
+
- [x] Attempted basic status read via device fetch during test
|
|
156
|
+
- [x] Added success/failure indicator with inline result details
|
|
157
|
+
- [x] Displayed measured connection latency (ms)
|
|
158
|
+
- [x] Displayed connection method result (BLE/OpenAPI/Auto)
|
|
159
|
+
|
|
160
|
+
**Status:** Users can now run per-device connection checks directly from the UI and immediately see method and latency results.
|
|
161
|
+
|
|
162
|
+
### Matter Neon Wire Rope Light Registration Verification ✅ COMPLETED
|
|
163
|
+
|
|
164
|
+
- [x] **Verify Matter registration for "Family Room Neon Wire Rope Light" succeeds without behavior rollback**
|
|
165
|
+
- [x] Added targeted Matter integration regression test for `RGBIC Neon Wire Rope Light`
|
|
166
|
+
- [x] Verified normalization to Matter type `lightstrip`
|
|
167
|
+
- [x] Verified `colorControl.colorMode` default is present (`0`) to satisfy conformance
|
|
168
|
+
- [x] Validated registration path end-to-end with Matter harness
|
|
169
|
+
|
|
170
|
+
**Status:** Neon Wire Rope Light registration now has regression coverage and registers with conformant ColorControl defaults.
|
|
171
|
+
|
|
172
|
+
### Matter Lightstrip Conformance ✅ COMPLETED
|
|
173
|
+
|
|
174
|
+
- [x] **Fix Matter lightstrip registration conformance requiring `colorControl.colorMode`**
|
|
175
|
+
- [x] **Issue:** Matter accessory initialization failed for color lightstrip devices with conformance errors
|
|
176
|
+
- [x] **Error:** `Conformance "M": Matter requires you to set this attribute ... colorControl.state.colorMode`
|
|
177
|
+
- [x] **Fix:** Added required `colorMode` default for lightstrip color control state while avoiding disallowed default writes
|
|
178
|
+
|
|
179
|
+
**Status:** Lightstrip accessories now provide required ColorControl state for Matter initialization.
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
### Battery Warnings in Device List ✅ COMPLETED
|
|
183
|
+
|
|
184
|
+
- [x] Show battery warnings (< 20%) with yellow/red indicators
|
|
185
|
+
|
|
186
|
+
**Status:** Devices with battery below 20% now display a yellow (10–19%) or red (<10%) warning badge in the discovery UI, with a tooltip for low/critical battery.
|
|
187
|
+
|
|
188
|
+
### Streaming BLE Device Discovery ✅ COMPLETED
|
|
189
|
+
|
|
190
|
+
- [x] Show devices as they're discovered (streaming results via polling)
|
|
191
|
+
|
|
192
|
+
**Status:** Devices now appear in the UI as soon as they're discovered during BLE scan, providing a real-time streaming experience.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### Discovery Better Loading States ✅ COMPLETED
|
|
197
|
+
|
|
198
|
+
- [x] Show progress indicator phases: `Scanning BLE` → `Fetching OpenAPI` → `Complete`
|
|
199
|
+
- [x] Added spinner/progress visuals for each phase
|
|
200
|
+
- [x] Display partial discovery results while later phases continue
|
|
201
|
+
- [x] Show elapsed time for current phase and total discovery time
|
|
202
|
+
- [x] Added cancel button for long discovery runs
|
|
203
|
+
|
|
204
|
+
**Status:** Discovery UX now provides real-time progress and immediate partial feedback.
|
|
205
|
+
|
|
206
|
+
### Discovery Device Grouping ✅ COMPLETED
|
|
207
|
+
|
|
208
|
+
- [x] Implemented grouping by connection type
|
|
209
|
+
- [x] Implemented grouping by hub
|
|
210
|
+
- [x] Added expandable/collapsible group headers
|
|
211
|
+
- [x] Added group counts in headers
|
|
212
|
+
- [x] Persisted expanded/collapsed state in localStorage
|
|
213
|
+
|
|
214
|
+
**Status:** Discovery lists are grouped, collapsible, and stateful across sessions.
|
|
215
|
+
|
|
216
|
+
### Discovery Connection Recommendations ✅ COMPLETED
|
|
217
|
+
|
|
218
|
+
- [x] Added `⚡ Recommended: BLE` badge for strong RSSI devices
|
|
219
|
+
- [x] Added `☁️ Recommended: API` badge for hub-dependent devices
|
|
220
|
+
- [x] Added recommendation tooltips explaining reasoning
|
|
221
|
+
- [x] Applied device-type-aware recommendation heuristics
|
|
222
|
+
|
|
223
|
+
**Status:** Discovery cards now provide actionable connection guidance.
|
|
224
|
+
|
|
225
|
+
### Configurable BLE Scan ✅ COMPLETED
|
|
226
|
+
|
|
227
|
+
- [x] Added scan duration settings (3s/5s/10s/15s)
|
|
228
|
+
- [x] Added option to disable BLE scanning
|
|
229
|
+
- [x] Added adjustable BLE timeout setting
|
|
230
|
+
- [x] Persisted BLE scan preferences in localStorage
|
|
231
|
+
- [x] Added Bluetooth availability status indicator
|
|
232
|
+
|
|
233
|
+
**Status:** BLE discovery behavior is user-configurable and persisted.
|
|
234
|
+
|
|
235
|
+
### Discovery History/Cache ✅ COMPLETED
|
|
236
|
+
|
|
237
|
+
- [x] Cache last discovery results for 5 minutes
|
|
238
|
+
- [x] Show "Last scanned: X minutes ago" with timestamp
|
|
239
|
+
- [x] Add "Refresh" button to re-scan
|
|
240
|
+
- [x] Show cached results immediately on page load
|
|
241
|
+
- [x] Auto-refresh option with configurable interval
|
|
242
|
+
|
|
243
|
+
**Status:** Discovery now restores recent results instantly and supports manual/automatic refresh.
|
|
244
|
+
|
|
245
|
+
### Discovery UX Polish ✅ COMPLETED
|
|
246
|
+
|
|
247
|
+
- [x] Added `Hide Added` discovery filter to exclude already-configured devices
|
|
248
|
+
- [x] Improved BLE settings row alignment (`Scan`, `Timeout`, and units)
|
|
249
|
+
- [x] Reduced extra spacing between BLE settings row and Bluetooth adapter status
|
|
250
|
+
- [x] Hide `Scan` and `Timeout` controls when `Disable BLE scan` is enabled
|
|
251
|
+
|
|
252
|
+
**Status:** Discovery controls are cleaner and faster to use for repeat configuration workflows.
|
|
253
|
+
|
|
254
|
+
### Detailed Device Info Panel ✅ COMPLETED
|
|
255
|
+
|
|
256
|
+
- [x] Added click-to-expand toggle button (▾) to device cards with rotation animation
|
|
257
|
+
- [x] Created expandable details panel showing extended device information:
|
|
258
|
+
- [x] Device ID with copy button
|
|
259
|
+
- [x] MAC Address with copy button
|
|
260
|
+
- [x] Device Type
|
|
261
|
+
- [x] Model
|
|
262
|
+
- [x] Hub ID (if applicable)
|
|
263
|
+
- [x] Battery level (if available)
|
|
264
|
+
- [x] Firmware version (if available)
|
|
265
|
+
- [x] Cloud Service status (enabled/disabled)
|
|
266
|
+
- [x] Last Seen timestamp (human-readable format)
|
|
267
|
+
- [x] Implemented copy-to-clipboard functionality with visual feedback (📋 → ✓ for 2s)
|
|
268
|
+
- [x] Styled details panel with SwitchBot theme (light gray background, compact rows)
|
|
269
|
+
- [x] Persisted expand/collapse state in-session (resets on page reload)
|
|
270
|
+
|
|
271
|
+
**Status:** Device cards now provide quick access to extended metadata with one-click copying of ID and MAC. Details panel uses clean, readable table layout within the card.
|
|
272
|
+
|
|
273
|
+
### Extended Details in Configured Devices ✅ COMPLETED
|
|
274
|
+
|
|
275
|
+
- [x] Added expandable toggle (▾) to configured device cards in config section
|
|
276
|
+
- [x] Details panel shows same extended information as discovered devices:
|
|
277
|
+
- [x] Device ID with copy button
|
|
278
|
+
- [x] MAC Address with copy button
|
|
279
|
+
- [x] Device Type
|
|
280
|
+
- [x] Model
|
|
281
|
+
- [x] Hub ID (if applicable)
|
|
282
|
+
- [x] Battery level (if available)
|
|
283
|
+
- [x] Firmware version (if available)
|
|
284
|
+
- [x] Cloud Service status
|
|
285
|
+
- [x] Last Seen timestamp
|
|
286
|
+
- [x] Toggle button rotates when expanded/collapsed (smooth animation)
|
|
287
|
+
- [x] Details available directly from card without opening Edit modal
|
|
288
|
+
|
|
289
|
+
**Status:** Configured devices now have the same quick-access details panel as discovered devices, making it easy to view metadata without opening the Edit dialog.
|
|
290
|
+
|
|
291
|
+
### Real-Time BLE Scanning (Partial) ✅ PARTIALLY COMPLETED
|
|
292
|
+
|
|
293
|
+
- [x] Added animated "pulsing" indicator during active BLE scan using CSS animation
|
|
294
|
+
- [x] Implemented "X devices found..." counter that displays during scan
|
|
295
|
+
- Shows BLE device count after BLE phase completes
|
|
296
|
+
- Updates to merged count when OpenAPI phase completes
|
|
297
|
+
- Auto-hides when discovery finishes
|
|
298
|
+
- [x] Counter shows pulse animation (1.5s opacity fade cycle) while scanning
|
|
299
|
+
- [x] Gracefully removes pulse animation and hides counter on cancellation/error
|
|
300
|
+
- [ ] Real-time streaming results via polling (partial implementation - displays final count per phase)
|
|
301
|
+
- [ ] Real-time RSSI updates during scan (requires server-side streaming support)
|
|
302
|
+
|
|
303
|
+
**Status:** Discovery now shows visual feedback with a pulsing "X devices found" counter. Full streaming of individual results per-device would require backend support for Server-Sent Events (SSE) or WebSocket streaming. Current implementation displays phase-wise device counts (BLE count → merged final count).
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
7
307
|
## Code Refactoring & Architecture
|
|
8
308
|
|
|
9
309
|
### Server-Side Refactoring ✅ COMPLETED
|
|
@@ -181,6 +481,19 @@ This file tracks all completed features and improvements for the SwitchBot Homeb
|
|
|
181
481
|
|
|
182
482
|
## Bug Fixes & Technical Debt
|
|
183
483
|
|
|
484
|
+
### Fix Discovery Not Showing Devices ✅ COMPLETED
|
|
485
|
+
|
|
486
|
+
- [x] **Issue:** No devices appear in discovery results after clicking "Discover Devices"
|
|
487
|
+
- [x] **Root Cause:** Discovery UI cleared the `#discoveredList` div (including the `<ul id="discoveredDevices">` element), but then tried to replace a non-existent element when rendering discovered devices
|
|
488
|
+
- [x] **Effect:** `document.getElementById('discoveredDevices')?.replaceWith(ul)` silently failed due to optional chaining, leaving the list empty
|
|
489
|
+
|
|
490
|
+
**Implementation:**
|
|
491
|
+
- Modified `discoverDevices()` in `discovery.ts` to create a new `<ul id="discoveredDevices">` container if it doesn't exist after clearing controls
|
|
492
|
+
- Updated `updateDiscoveryView()` to check if the element exists before using `replaceWith()`, with fallback to append if element is missing
|
|
493
|
+
- Added proper element lifecycle management for discovery list rendering
|
|
494
|
+
|
|
495
|
+
**Status:** Discovery now properly displays all discovered devices. Devices appear correctly with filters, sorting, and duplicate detection badges.
|
|
496
|
+
|
|
184
497
|
### Fix lint & lint:fix scripts ✅ COMPLETED
|
|
185
498
|
|
|
186
499
|
- [x] Update ESLint configuration to include `src/homebridge-ui/**/*.ts` files
|