Skip to content

Commit de0fee9

Browse files
author
homebridge-bot
committed
v5.0.0
Device management UI πŸ” Discover devices from SwitchBot API βž• Add devices to config automatically ✏️ Edit device names πŸ—‘οΈ Delete devices πŸ“‹ Copy device IDs All without manually editing config files
1 parent 2c24403 commit de0fee9

File tree

186 files changed

+7140
-120387
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

186 files changed

+7140
-120387
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
name: E2E Verification Results
3+
about: Submit manual E2E test results for homebridge-switchbot changes (Matter + node-switchbot v4)
4+
title: "[E2E] <device-type> verification"
5+
labels: e2e, testing
6+
assignees: ''
7+
---
8+
9+
### Environment
10+
- Homebridge version:
11+
- Plugin commit / branch:
12+
- macOS version:
13+
- Bluetooth available: (yes/no)
14+
- openApiToken used: (yes/no)
15+
16+
### Device under test
17+
- Device type: (Light / Fan / Curtain / Lock)
18+
- Device model:
19+
- Connection used: (BLE / OpenAPI)
20+
21+
### Steps performed
22+
- Start Homebridge with plugin linked/built
23+
- Verified Matter registration: (yes/no)
24+
- Verified HAP fallback when Matter unavailable: (yes/no)
25+
- Operations tested: (list)
26+
27+
### Results
28+
- Observed behavior (brief):
29+
- Any errors in plugin logs (paste relevant snippets):
30+
31+
### Verdict
32+
- Pass/Fail:
33+
- Notes and follow-ups:
34+
35+
### Attachments
36+
- Logs, screenshots, videos

β€Ž.github/workflows/ci.ymlβ€Ž

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ["latest", "beta-*", "main"]
6+
pull_request:
7+
branches: ["latest", "main"]
8+
9+
jobs:
10+
test:
11+
name: Build and Test
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Use Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: '20'
21+
22+
- name: Install dependencies
23+
run: npm ci --legacy-peer-deps
24+
25+
- name: Build
26+
run: npm run build
27+
28+
- name: Run tests
29+
run: npm run test
30+
name: CI
31+
32+
on:
33+
push:
34+
branches: [ main, latest ]
35+
pull_request:
36+
branches: [ main, latest ]
37+
38+
jobs:
39+
build-and-test:
40+
runs-on: ubuntu-latest
41+
strategy:
42+
matrix:
43+
node-version: [20, 22]
44+
45+
steps:
46+
- uses: actions/checkout@v4
47+
48+
- name: Setup Node.js
49+
uses: actions/setup-node@v4
50+
with:
51+
node-version: ${{ matrix.node-version }}
52+
cache: 'npm'
53+
54+
- name: Install dependencies
55+
run: npm ci --legacy-peer-deps
56+
57+
- name: Build
58+
run: npm run build
59+
60+
- name: Run tests
61+
run: npm test
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: Manual E2E (build + optional E2E)
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
run_e2e:
7+
description: 'Set to true to run the E2E scripts (requires network-accessible Homebridge and valid tokens)'
8+
required: false
9+
default: 'false'
10+
hb_url:
11+
description: 'Homebridge UI URL (e.g. http://host:8581)'
12+
required: false
13+
hb_token:
14+
description: 'Homebridge UI token (store as secret or pass here)'
15+
required: false
16+
light_accessory_id:
17+
description: 'Accessory ID for light (when running E2E)'
18+
required: false
19+
fan_accessory_id:
20+
description: 'Accessory ID for fan (when running E2E)'
21+
required: false
22+
curtain_accessory_id:
23+
description: 'Accessory ID for curtain (when running E2E)'
24+
required: false
25+
lock_accessory_id:
26+
description: 'Accessory ID for lock (when running E2E)'
27+
required: false
28+
29+
jobs:
30+
build-and-test:
31+
runs-on: ubuntu-latest
32+
steps:
33+
- name: Checkout
34+
uses: actions/checkout@v4
35+
36+
- name: Setup Node
37+
uses: actions/setup-node@v4
38+
with:
39+
node-version: '18'
40+
41+
- name: Install dependencies
42+
run: npm ci --prefer-offline --no-audit --progress=false
43+
44+
- name: Build
45+
run: npm run build
46+
47+
- name: Run unit tests
48+
run: npm run test
49+
50+
- name: Optional: Run E2E scripts
51+
if: ${{ github.event.inputs.run_e2e == 'true' }}
52+
env:
53+
HB_URL: ${{ github.event.inputs.hb_url }}
54+
HB_TOKEN: ${{ github.event.inputs.hb_token }}
55+
LIGHT_ACCESSORY_ID: ${{ github.event.inputs.light_accessory_id }}
56+
FAN_ACCESSORY_ID: ${{ github.event.inputs.fan_accessory_id }}
57+
CURTAIN_ACCESSORY_ID: ${{ github.event.inputs.curtain_accessory_id }}
58+
LOCK_ACCESSORY_ID: ${{ github.event.inputs.lock_accessory_id }}
59+
LIGHT_ACCESSORY_NAME: ${{ github.event.inputs.light_accessory_name }}
60+
FAN_ACCESSORY_NAME: ${{ github.event.inputs.fan_accessory_name }}
61+
CURTAIN_ACCESSORY_NAME: ${{ github.event.inputs.curtain_accessory_name }}
62+
LOCK_ACCESSORY_NAME: ${{ github.event.inputs.lock_accessory_name }}
63+
run: |
64+
echo "Running E2E scripts on runner ($HB_URL) - ensure the runner can access Homebridge and devices"
65+
# resolve accessory IDs from names when IDs not provided
66+
echo "Resolving accessory IDs from names (if provided)..."
67+
rm -f resolved_ids.env || true
68+
touch resolved_ids.env
69+
70+
resolve() {
71+
idvar="$1"
72+
namevar="$2"
73+
nameval="$(eval echo \"\$$namevar\")"
74+
idval="$(eval echo \"\$$idvar\")"
75+
if [[ -z "$idval" && -n "$nameval" ]]; then
76+
resp=$(curl -sS -H "Authorization: Bearer ${HB_TOKEN}" "${HB_URL}/api/accessories" || true)
77+
found=$(printf '%s' "$resp" | node -e "const fs=require('fs');const name=process.argv[1];try{const j=JSON.parse(fs.readFileSync(0,'utf8'));const arr=Array.isArray(j)?j:(j.accessories||j)||[];for(const a of arr){if(a.displayName===name||a.name===name||(a.context&&a.context.deviceId===name)){if(a.aid){console.log(a.aid);process.exit(0);}else if(a.UUID){console.log(a.UUID);process.exit(0);}}} }catch(e){}" "$nameval" )
78+
if [[ -n "$found" ]]; then
79+
echo "Resolved $idvar=$found"
80+
echo "$idvar=$found" >> resolved_ids.env
81+
export "$idvar"="$found"
82+
else
83+
echo "Could not resolve $namevar='$nameval' to an id"
84+
fi
85+
fi
86+
}
87+
88+
resolve LIGHT_ACCESSORY_ID LIGHT_ACCESSORY_NAME
89+
resolve FAN_ACCESSORY_ID FAN_ACCESSORY_NAME
90+
resolve CURTAIN_ACCESSORY_ID CURTAIN_ACCESSORY_NAME
91+
resolve LOCK_ACCESSORY_ID LOCK_ACCESSORY_NAME
92+
93+
# set RUN_E2E so the conditional Vitest harness executes
94+
export RUN_E2E=true
95+
npm run test
96+
97+
- name: Upload logs (if any)
98+
if: always()
99+
uses: actions/upload-artifact@v4
100+
with:
101+
name: test-logs
102+
path: |
103+
test-output.log

β€ŽCHANGELOG.mdβ€Ž

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
# Changelog
22

3+
## Unreleased β€” beta-4.3.3
4+
5+
### Added
6+
- Matter support (child-bridge) with Matter-first registration and HAP fallback.
7+
- Hybrid `node-switchbot@4` client adapter (BLE + OpenAPI) with OpenAPI fallback.
8+
- Manual and automated E2E scripts for lights, fans, curtains, and locks (`scripts/e2e/*`).
9+
- Conditional Vitest E2E harness (`RUN_E2E=true`) and a manual GitHub Actions workflow to run E2E.
10+
11+
### Changed
12+
- Centralized Matter cluster/attribute numeric ID maps in `src/utils.ts`.
13+
- Device descriptors refactored to use canonical Matter IDs.
14+
- OpenAPI fallback hardened with timeouts, retries, backoff, and per-device retry limits.
15+
16+
### Tests
17+
- Added integration tests and a Matter test harness under `test/`.
18+
19+
### Notes
20+
- This is a beta release; follow migration notes in MIGRATION.md before upgrading.
21+
# Changelog
22+
323
All notable changes to this project will be documented in this file. This project uses [Semantic Versioning](https://semver.org/)
424

525
## [Unreleased]

β€ŽE2E-VERIFICATION.mdβ€Ž

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Manual End-to-End Verification
2+
3+
This guide walks through manual end-to-end verification for representative devices (light, fan, curtain, lock) across BLE and OpenAPI paths, and verifies Matter-first behavior with HAP fallback.
4+
5+
## Prerequisites
6+
7+
- macOS with Bluetooth (for BLE verification)
8+
- Local development environment set up (Node.js, npm)
9+
- Homebridge installed locally or available (for running a test instance)
10+
- SwitchBot devices available (at least one light, one fan, one curtain, one lock) OR corresponding cloud-hub access
11+
- `openApiToken` when testing OpenAPI path
12+
13+
## Quick setup
14+
15+
1. Install dependencies:
16+
17+
```bash
18+
npm install --legacy-peer-deps
19+
```
20+
21+
2. Build the plugin:
22+
23+
```bash
24+
npm run build
25+
```
26+
27+
3. Recommended: run the watch task which links the plugin and restarts on changes (requires a local Homebridge installation):
28+
29+
```bash
30+
npm run watch
31+
```
32+
33+
Alternative (manual linking):
34+
35+
```bash
36+
npm run build && npm link
37+
# then run your Homebridge instance (system/homebridge UI) so it picks up the linked plugin
38+
```
39+
40+
## Example platform config snippets
41+
42+
OpenAPI (cloud) path β€” enable Matter preference:
43+
44+
```json
45+
{
46+
"platform": "SwitchBot",
47+
"openApiToken": "<YOUR_OPENAPI_TOKEN>",
48+
"enableMatter": true,
49+
"preferMatter": true
50+
}
51+
```
52+
53+
BLE (direct) path β€” specify device by MAC address and prefer Matter:
54+
55+
```json
56+
{
57+
"platform": "SwitchBot",
58+
"devices": [
59+
{ "deviceId": "AA:BB:CC:DD:EE:FF", "type": "Light" }
60+
],
61+
"enableMatter": true,
62+
"preferMatter": true
63+
}
64+
```
65+
66+
## Verification checklist
67+
68+
Run the steps below for each device type; repeat once using BLE and once using OpenAPI (where applicable).
69+
70+
- Start Homebridge (with the plugin linked) and verify the plugin logs indicate Matter registration attempt.
71+
- Look for log lines: `Attempting Matter registration for ...` or `Homebridge Matter API not available; will fallback to HAP`.
72+
- Confirm accessories are registered in Matter (if Homebridge Matter child-bridge present) or appear as HAP accessories otherwise.
73+
74+
Device-specific tests
75+
76+
- Light
77+
- Toggle On/Off from Home app (or Homebridge UI) and confirm device responds.
78+
- Set brightness to 25%, 50%, 100% and confirm device reports matching levels.
79+
- If supported, change color temperature and/or color; confirm device applies new values.
80+
81+
- Fan
82+
- Toggle On/Off and verify.
83+
- Change rotation speed in steps (e.g., 25%, 50%, 100%).
84+
- Toggle oscillation / swing and verify position changes.
85+
86+
- Curtain
87+
- Open and Close via Home app / controller and verify movement.
88+
- Set specific position (e.g., 50%) and verify accurate reporting.
89+
90+
- Lock
91+
- Lock and Unlock from controller and verify state.
92+
- If lock user management supported, add/remove a test user per plugin UI and verify expected behavior.
93+
94+
## Logs & debugging
95+
96+
- Enable verbose logs from Homebridge or the plugin. Example: start Homebridge with a higher log level, or watch console output from `npm run watch`.
97+
- Capture logs while you perform each operation; note the request path used by the plugin:
98+
- For OpenAPI: logs will show `https://api.switch-bot.com/v1.0/...` calls.
99+
- For BLE: logs will show local device discovery / BLE connect attempts.
100+
101+
## Run validation script (optional)
102+
103+
You can run the TypeScript build and unit tests to confirm the codebase is healthy before manual tests:
104+
105+
```bash
106+
npm run build && npm run test
107+
```
108+
109+
## Expected outcomes
110+
111+
- Matter-first registration: when Homebridge Matter API is available and `enableMatter` is true, accessories should be registered as Matter child-bridge accessories and re-used if restored from cache.
112+
- HAP fallback: when Matter API is not available, the plugin must continue to register HAP accessories and reuse restored accessories by `accessory.context.deviceId`.
113+
- Hybrid client paths: when `openApiToken` present the plugin should prefer OpenAPI for devices reachable via cloud; when BLE is available and configured the plugin should connect directly via BLE.
114+
- Logs should show robust retry attempts for transient network errors and per-device retry throttling if configured.
115+
116+
## Next steps I can take
117+
118+
- Create small automated verification scripts that use the Homebridge API test harness to toggle characteristic values (requires more test harness code).
119+
- Generate a printable checklist or a GitHub issue template for manual verification results.
120+
121+
If you want, I can add the automated verification scripts now β€” would you prefer a simple script that exercises On/Off and Brightness for lights, or a broader script covering all device types?

β€ŽMIGRATION.mdβ€Ž

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Migration notes β€” v4.3.x β†’ beta
2+
3+
This document highlights important changes and recommended actions before upgrading to the beta containing Matter and `node-switchbot@4` support.
4+
5+
1. Matter-first behavior
6+
- The plugin will prefer registering accessories with Homebridge's Matter child-bridge when `enableMatter: true` and the Homebridge Matter API is available.
7+
- If Matter is not available, the plugin falls back to HAP and will reuse restored accessories by `accessory.context.deviceId`.
8+
9+
2. Configuration keys
10+
- `enableMatter` (boolean) β€” enable Matter child-bridge registration.
11+
- `preferMatter` (boolean) β€” prefer Matter for devices that support Matter descriptors; HAP fallback still available.
12+
- `openApiToken` (string) β€” when present the plugin may prefer OpenAPI calls for cloud-reachable devices.
13+
- `perDeviceMaxRetries`, `requestTimeout`, `maxRetries` β€” network retry/timing options for OpenAPI fallback.
14+
15+
- `writeDebounceMs` (number, milliseconds, default 100) β€” global write coalescing debounce window. Commands sent to the same device within this window are coalesced (last-write-wins) to reduce duplicate network/API commands. Set to `0` to disable coalescing if you require immediate, per-command delivery.
16+
17+
3. Hybrid client
18+
- The plugin dynamically imports `node-switchbot` when available and falls back to OpenAPI when an `openApiToken` is configured.
19+
- If you rely on BLE-only operation, ensure devices and the host have BLE available.
20+
21+
4. UI changes
22+
- A small plugin UI was added; it's only enabled/copied into `dist/homebridge-ui` when `npm run build` is run and the UI files exist in `src/homebridge-ui/public`.
23+
24+
- The UI is always served when Homebridge UI support is present; there is no opt-out flag in the platform config. The server-side guard that previously allowed disabling the UI has been removedβ€”if you need to restrict access, manage it via Homebridge UI / host network access controls.
25+
26+
5. Tests and verification
27+
- Manual E2E scripts are provided in `scripts/e2e/` and a GitHub `workflow_dispatch` job can optionally run them against a reachable Homebridge.
28+
- Run the local test suite before upgrading to confirm TypeScript and unit tests pass: `npm run build && npm run test`.
29+
30+
6. Rollback plan
31+
- If the beta causes issues, revert to the previous stable plugin version by reinstalling the prior package or checking out the stable branch.
32+
33+
7. Regenerating Matter ID maps
34+
35+
- A helper script `scripts/generate-matter-maps.js` is included to generate `src/matter-maps.generated.ts` from official zap/matter JSON metadata. The script expects a JSON input with a `clusters` array and will write mapped `MATTER_CLUSTER_IDS` and `MATTER_ATTRIBUTE_IDS` constants.
36+
- Usage example:
37+
38+
```bash
39+
node scripts/generate-matter-maps.js ./zap-matter.json
40+
```
41+
42+
Place the official metadata JSON as `zap-matter.json` at the repo root (or pass a path) and commit the generated `src/matter-maps.generated.ts` to keep maps up to date.
43+
44+
If you want, I can open a PR with these notes and the changelog stub targeting a beta branch I create next.

0 commit comments

Comments
Β (0)