feat(ui): detect legacy v4 config format and surface incompatibility warning#1360
Conversation
Agent-Logs-Url: https://github.com/OpenWonderLabs/homebridge-switchbot/sessions/7e7e0142-74c0-4c7c-b0f3-8607f9eba799 Co-authored-by: donavanbecker <9875439+donavanbecker@users.noreply.github.com>
Agent-Logs-Url: https://github.com/OpenWonderLabs/homebridge-switchbot/sessions/7e7e0142-74c0-4c7c-b0f3-8607f9eba799 Co-authored-by: donavanbecker <9875439+donavanbecker@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds legacy v4 config detection to the Homebridge UI (and server logs) so users get a clear incompatibility warning instead of silently seeing “no devices”.
Changes:
- Introduces a shared
isV4Config()utility to detect v4-stylecredentials/options.devicesshapes. - Surfaces v4 detection in the UI via a warning banner and in server logs/response metadata.
- Adds unit tests covering known v4 config shapes from the bug report.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/homebridge-ui/utils/v4-detection.ts |
New shared pure helper to detect legacy v4 config shapes. |
src/homebridge-ui/utils/config-parser.ts |
Re-exports isV4Config for server-side utilities to consume. |
src/homebridge-ui/endpoints/config.ts |
Detects v4 configs during /devices scan, logs warning, and returns v4ConfigDetected. |
src/homebridge-ui/public/js/api.ts |
Adds detectV4Config() using the UI API + shared isV4Config(). |
src/homebridge-ui/public/js/app.ts |
Calls v4 detection at init and shows the warning banner when applicable. |
src/homebridge-ui/public/index.html |
Adds hidden v4 incompatibility banner with migration steps and link. |
src/homebridge-ui/public/css/styles.css |
Styles the v4 warning banner for dark/light modes. |
test/homebridge-ui/config-parser.spec.ts |
New Vitest coverage for isV4Config() behavior. |
package-lock.json |
Lockfile updated (contains additional dependency graph churn beyond the feature). |
| <li>Remove the <code>credentials</code> and <code>options</code> wrapper objects</li> | ||
| </ul> | ||
| <p> | ||
| See the <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/latest/MIGRATION.md" target="_blank" rel="noopener">Migration Guide</a> for full details. |
There was a problem hiding this comment.
The banner links to MIGRATION.md, but the current migration guide (repo root MIGRATION.md:18-20) states “Existing configs do not need changes” and doesn’t mention credentials/options.devices. Either update the linked doc in this PR or adjust the link/text so the user is sent to documentation that matches these migration steps.
| See the <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/latest/MIGRATION.md" target="_blank" rel="noopener">Migration Guide</a> for full details. | |
| Follow the migration steps above to update your config to the v5 format before saving changes in this UI. |
| = platform.options !== undefined | ||
| && typeof platform.options === 'object' | ||
| && Array.isArray(platform.options.devices) | ||
| return hasCredentials || hasOptionsDevices |
There was a problem hiding this comment.
isV4Config will return true for any config that still contains a credentials object even if it has already been migrated to v5 fields (e.g. openApiToken/openApiSecret and root devices). That makes the banner/log message (“not compatible with v5+”) incorrect for mixed configs. Consider tightening detection to require legacy fields and absence of the v5 equivalents (or at least absence of root devices).
| return hasCredentials || hasOptionsDevices | |
| // v5+ configs flatten credentials and move devices to the platform root | |
| const hasRootDevices = Array.isArray(platform.devices) | |
| const hasOpenApiToken = typeof platform.openApiToken === 'string' && platform.openApiToken.length > 0 | |
| const hasOpenApiSecret = typeof platform.openApiSecret === 'string' && platform.openApiSecret.length > 0 | |
| const hasV5Fields = hasRootDevices || hasOpenApiToken || hasOpenApiSecret | |
| return (hasCredentials || hasOptionsDevices) && !hasV5Fields |
| } | ||
|
|
||
| // Detect legacy v4 config format | ||
| if (isV4Config(p)) { |
There was a problem hiding this comment.
This warning will be logged once per matching platform block, which can spam logs if multiple SwitchBot blocks exist. Since you already track v4ConfigDetected, consider only logging the warning the first time (e.g. guard with if (!v4ConfigDetected && isV4Config(p))).
| if (isV4Config(p)) { | |
| if (!v4ConfigDetected && isV4Config(p)) { |
| const config = configArr.find(isSwitchBotPlatformConfig) | ||
| if (!config || typeof config !== 'object') { | ||
| return false | ||
| } | ||
| return isV4Config(config) |
There was a problem hiding this comment.
detectV4Config() only checks the first SwitchBot config block (find). If users have multiple SwitchBot platform blocks and the first one is v5 while another is legacy v4, the warning banner will not show. Consider scanning all matching blocks (e.g. some(isSwitchBotPlatformConfig && isV4Config)) and returning true if any are v4.
| const config = configArr.find(isSwitchBotPlatformConfig) | |
| if (!config || typeof config !== 'object') { | |
| return false | |
| } | |
| return isV4Config(config) | |
| return configArr.some(config => isSwitchBotPlatformConfig(config) && isV4Config(config)) |
| <div id="v4ConfigWarning" class="v4-config-warning" style="display: none"> | ||
| <strong>⚠️ Incompatible v4 Configuration Detected</strong> | ||
| <p> | ||
| Your config.json appears to be in the <strong>v4 format</strong> (using <code>credentials</code> and | ||
| <code>options.devices</code> fields). This format is <strong>not compatible with v5 or newer</strong> of the | ||
| SwitchBot plugin. Devices will not be recognised until the config is updated. |
There was a problem hiding this comment.
Because this banner is shown dynamically, it likely won’t be announced by screen readers. Consider adding an appropriate ARIA role/live region (e.g. role="alert" and/or aria-live) and ensuring the heading/structure is accessible when displayed.
v4 configs nest credentials under
credentials{}and devices underoptions.devices[]; v5+ expectsopenApiToken/openApiSecretat the platform root and a top-leveldevices[]. When a v4 config is present, the plugin silently finds no devices — no error, no indication of what's wrong.Changes
src/homebridge-ui/utils/v4-detection.ts— new shared pure utilityisV4Config(platform): detects v4 format via presence ofcredentialsobject oroptions.devicesarray; no Node.js deps so it bundles cleanly for the browsersrc/homebridge-ui/utils/config-parser.ts— re-exportsisV4Configfrom the new shared modulesrc/homebridge-ui/endpoints/config.ts— server-side/devicesendpoint now callsisV4Config, logs a warning, and includesv4ConfigDetected: truein the responsesrc/homebridge-ui/public/js/api.ts— newdetectV4Config()async function queries the Homebridge plugin config via the UI API and delegates to the sharedisV4Config()src/homebridge-ui/public/js/app.ts— callscheckV4Config()at init; reveals the warning banner when v4 is detectedsrc/homebridge-ui/public/index.html— hidden#v4ConfigWarningbanner with step-by-step migration instructions; shown programmaticallysrc/homebridge-ui/public/css/styles.css— warning banner styles with dark/light theme supporttest/homebridge-ui/config-parser.spec.ts— unit tests forisV4Config()covering the exact config shape from the bug reportExample v4 config that triggers the warning:
{ "platform": "SwitchBot", "credentials": { "notice": "Keep your token a secret!" }, "options": { "devices": [{ "deviceId": "xxxxxxxx", "configDeviceType": "Curtain", "connectionType": "BLE" }] } }The banner directs users to flatten to
openApiToken,openApiSecret, anddevices[]and renameconnectionType→connectionPreference.