@switchbot/homebridge-switchbot 5.0.0-beta.99 → 5.1.0-beta.0
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/.changeset/config.json +14 -0
- package/.github/copilot-instructions.md +39 -0
- package/.github/workflows/ci.yml +4 -1
- package/.github/workflows/manual-e2e.yml +6 -3
- package/.github/workflows/release.yml +64 -15
- package/.github/workflows/stale.yml +2 -4
- package/.husky/pre-push +15 -0
- package/CHANGELOG.md +140 -135
- package/MIGRATION.md +21 -6
- package/README.md +109 -3
- package/TODO.md +263 -0
- package/config.schema.json +240 -36
- package/dist/SwitchBotHAPPlatform.d.ts +133 -0
- package/dist/SwitchBotHAPPlatform.d.ts.map +1 -0
- package/dist/SwitchBotHAPPlatform.js +584 -0
- package/dist/SwitchBotHAPPlatform.js.map +1 -0
- package/dist/SwitchBotMatterPlatform.d.ts +142 -0
- package/dist/SwitchBotMatterPlatform.d.ts.map +1 -0
- package/dist/SwitchBotMatterPlatform.js +569 -0
- package/dist/SwitchBotMatterPlatform.js.map +1 -0
- package/dist/device-types.d.ts +31 -0
- package/dist/device-types.d.ts.map +1 -0
- package/dist/device-types.js +246 -0
- package/dist/device-types.js.map +1 -0
- package/dist/deviceCommandMapper.d.ts +10 -0
- package/dist/deviceCommandMapper.d.ts.map +1 -0
- package/dist/deviceCommandMapper.js +319 -0
- package/dist/deviceCommandMapper.js.map +1 -0
- package/dist/deviceFactory.d.ts +3 -2
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +107 -29
- package/dist/deviceFactory.js.map +1 -1
- package/dist/devices/genericDevice.d.ts +59 -37
- package/dist/devices/genericDevice.d.ts.map +1 -1
- package/dist/devices/genericDevice.js +376 -78
- package/dist/devices/genericDevice.js.map +1 -1
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/homebridge-ui/device-types.js +246 -0
- package/dist/homebridge-ui/device-types.js.map +1 -0
- package/dist/homebridge-ui/deviceCommandMapper.js +319 -0
- package/dist/homebridge-ui/deviceCommandMapper.js.map +1 -0
- package/dist/homebridge-ui/endpoints/config.d.ts +3 -0
- package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/config.js +90 -0
- package/dist/homebridge-ui/endpoints/config.js.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts +6 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.js +144 -0
- package/dist/homebridge-ui/endpoints/devices.js.map +1 -0
- package/dist/homebridge-ui/endpoints/discovery.d.ts +7 -0
- package/dist/homebridge-ui/endpoints/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/discovery.js +219 -0
- package/dist/homebridge-ui/endpoints/discovery.js.map +1 -0
- package/dist/homebridge-ui/errors.js +32 -0
- package/dist/homebridge-ui/errors.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js +90 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/devices.js +144 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/devices.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/discovery.js +219 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/discovery.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/server.js +11 -0
- package/dist/homebridge-ui/homebridge-ui/server.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js +108 -0
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/device-migration.js +111 -0
- package/dist/homebridge-ui/homebridge-ui/utils/device-migration.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/logger.js +17 -0
- package/dist/homebridge-ui/homebridge-ui/utils/logger.js.map +1 -0
- package/dist/homebridge-ui/public/css/styles.css +483 -0
- package/dist/homebridge-ui/public/index.html +197 -621
- package/dist/homebridge-ui/public/js/advanced-settings.d.ts +3 -0
- package/dist/homebridge-ui/public/js/advanced-settings.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/advanced-settings.js +95 -0
- package/dist/homebridge-ui/public/js/advanced-settings.js.map +1 -0
- package/dist/homebridge-ui/public/js/advanced-settings.ts +94 -0
- package/dist/homebridge-ui/public/js/api.d.ts +72 -0
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/api.js +313 -0
- package/dist/homebridge-ui/public/js/api.js.map +1 -0
- package/dist/homebridge-ui/public/js/api.ts +385 -0
- package/dist/homebridge-ui/public/js/app.d.ts +2 -0
- package/dist/homebridge-ui/public/js/app.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/app.js +3798 -0
- package/dist/homebridge-ui/public/js/app.js.map +7 -0
- package/dist/homebridge-ui/public/js/app.ts +22 -0
- package/dist/homebridge-ui/public/js/constants.d.ts +2 -0
- package/dist/homebridge-ui/public/js/constants.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/constants.js +2 -0
- package/dist/homebridge-ui/public/js/constants.js.map +1 -0
- package/dist/homebridge-ui/public/js/constants.ts +1 -0
- package/dist/homebridge-ui/public/js/credentials.d.ts +3 -0
- package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.js +99 -0
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.ts +105 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts +3 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.js +199 -0
- package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.ts +227 -0
- package/dist/homebridge-ui/public/js/devices.d.ts +9 -0
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/devices.js +104 -0
- package/dist/homebridge-ui/public/js/devices.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices.ts +112 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts +9 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.js +1201 -0
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.ts +1335 -0
- package/dist/homebridge-ui/public/js/logger.d.ts +7 -0
- package/dist/homebridge-ui/public/js/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/logger.js +17 -0
- package/dist/homebridge-ui/public/js/logger.js.map +1 -0
- package/dist/homebridge-ui/public/js/logger.ts +17 -0
- package/dist/homebridge-ui/public/js/modal.d.ts +5 -0
- package/dist/homebridge-ui/public/js/modal.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modal.js +35 -0
- package/dist/homebridge-ui/public/js/modal.js.map +1 -0
- package/dist/homebridge-ui/public/js/modal.ts +35 -0
- package/dist/homebridge-ui/public/js/modals.d.ts +16 -0
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modals.js +728 -0
- package/dist/homebridge-ui/public/js/modals.js.map +1 -0
- package/dist/homebridge-ui/public/js/modals.ts +823 -0
- package/dist/homebridge-ui/public/js/render.d.ts +71 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/render.js +961 -0
- package/dist/homebridge-ui/public/js/render.js.map +1 -0
- package/dist/homebridge-ui/public/js/render.ts +1085 -0
- package/dist/homebridge-ui/public/js/toast.d.ts +6 -0
- package/dist/homebridge-ui/public/js/toast.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/toast.js +38 -0
- package/dist/homebridge-ui/public/js/toast.js.map +1 -0
- package/dist/homebridge-ui/public/js/toast.ts +44 -0
- package/dist/homebridge-ui/public/js/types.d.ts +23 -0
- package/dist/homebridge-ui/public/js/types.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/types.js +2 -0
- package/dist/homebridge-ui/public/js/types.js.map +1 -0
- package/dist/homebridge-ui/public/js/types.ts +26 -0
- package/dist/homebridge-ui/server.d.ts +1 -3
- package/dist/homebridge-ui/server.d.ts.map +1 -1
- package/dist/homebridge-ui/server.js +8 -471
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/homebridge-ui/settings.js +8 -0
- package/dist/homebridge-ui/settings.js.map +1 -0
- package/dist/homebridge-ui/switchbotClient.js +247 -0
- package/dist/homebridge-ui/switchbotClient.js.map +1 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts +39 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/config-parser.js +108 -0
- package/dist/homebridge-ui/utils/config-parser.js.map +1 -0
- package/dist/homebridge-ui/utils/device-migration.d.ts +35 -0
- package/dist/homebridge-ui/utils/device-migration.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/device-migration.js +111 -0
- package/dist/homebridge-ui/utils/device-migration.js.map +1 -0
- package/dist/homebridge-ui/utils/logger.d.ts +7 -0
- package/dist/homebridge-ui/utils/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/logger.js +17 -0
- package/dist/homebridge-ui/utils/logger.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/settings.d.ts +12 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +1 -0
- package/dist/settings.js.map +1 -1
- package/dist/switchbotClient.d.ts +12 -10
- package/dist/switchbotClient.d.ts.map +1 -1
- package/dist/switchbotClient.js +156 -103
- package/dist/switchbotClient.js.map +1 -1
- package/dist/utils.d.ts +81 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1148 -4
- package/dist/utils.js.map +1 -1
- package/docs/assets/highlight.css +29 -15
- package/docs/assets/main.js +1 -1
- package/docs/index.html +100 -6
- package/docs/variables/default.html +3 -1
- package/eslint.config.js +9 -5
- package/nodemon.json +2 -2
- package/package.json +34 -21
- package/scripts/build-ui.js +37 -0
- package/scripts/free-dev-ports.mjs +105 -0
- package/scripts/generate-matter-maps.js +34 -17
- package/scripts/sync-device-types.mjs +31 -0
- package/src/SwitchBotHAPPlatform.ts +583 -0
- package/src/SwitchBotMatterPlatform.ts +566 -0
- package/src/device-types.js +246 -0
- package/src/device-types.js.map +1 -0
- package/src/device-types.ts +261 -0
- package/src/deviceCommandMapper.js +319 -0
- package/src/deviceCommandMapper.js.map +1 -0
- package/src/deviceCommandMapper.ts +333 -0
- package/src/deviceFactory.ts +125 -45
- package/src/devices/genericDevice.ts +411 -69
- package/src/errors.js +32 -0
- package/src/errors.js.map +1 -0
- package/src/errors.ts +35 -0
- package/src/homebridge-ui/endpoints/config.ts +110 -0
- package/src/homebridge-ui/endpoints/devices.ts +153 -0
- package/src/homebridge-ui/endpoints/discovery.ts +240 -0
- package/src/homebridge-ui/public/css/styles.css +483 -0
- package/src/homebridge-ui/public/index.html +197 -621
- package/src/homebridge-ui/public/js/advanced-settings.ts +94 -0
- package/src/homebridge-ui/public/js/api.ts +385 -0
- package/src/homebridge-ui/public/js/app.ts +22 -0
- package/src/homebridge-ui/public/js/constants.ts +1 -0
- package/src/homebridge-ui/public/js/credentials.ts +105 -0
- package/src/homebridge-ui/public/js/devices-delete.ts +227 -0
- package/src/homebridge-ui/public/js/devices.ts +112 -0
- package/src/homebridge-ui/public/js/discovery.ts +1335 -0
- package/src/homebridge-ui/public/js/logger.ts +17 -0
- package/src/homebridge-ui/public/js/modal.ts +35 -0
- package/src/homebridge-ui/public/js/modals.ts +823 -0
- package/src/homebridge-ui/public/js/render.ts +1085 -0
- package/src/homebridge-ui/public/js/toast.ts +44 -0
- package/src/homebridge-ui/public/js/types.ts +26 -0
- package/src/homebridge-ui/server.ts +9 -554
- package/src/homebridge-ui/utils/config-parser.ts +125 -0
- package/src/homebridge-ui/utils/device-migration.ts +144 -0
- package/src/homebridge-ui/utils/logger.ts +17 -0
- package/src/index.ts +12 -2
- package/src/settings.js +8 -0
- package/src/settings.js.map +1 -0
- package/src/settings.ts +14 -0
- package/src/switchbotClient.js +247 -0
- package/src/switchbotClient.js.map +1 -0
- package/src/switchbotClient.ts +177 -114
- package/src/utils.ts +1164 -5
- package/test/client/switchbot-client-debounce.spec.ts +35 -0
- package/test/client/switchbot-client-openapi.spec.ts +19 -0
- package/test/client/switchbotClient.spec.ts +64 -0
- package/test/device/device-mapping.spec.ts +23 -0
- package/test/device/deviceBase.spec.ts +26 -0
- package/test/device/deviceFactory-edge.spec.ts +15 -0
- package/test/device/deviceFactory.spec.ts +33 -0
- package/test/device/fan-swing.spec.ts +34 -0
- package/test/device/genericDevice-blepoll.spec.ts +47 -0
- package/test/device/irdevice.spec.ts +9 -0
- package/test/device/lock-users.spec.ts +35 -0
- package/test/device/matter-descriptors.spec.ts +22 -0
- package/test/device/matter-device-state.spec.ts +37 -0
- package/test/e2e/run-e2e.spec.ts +18 -19
- package/test/errors/errors.spec.ts +10 -0
- package/test/helpers/matter-harness.ts +20 -9
- package/test/homebridge-ui/server.spec.ts +9 -0
- package/test/platform/accessory-restore.spec.ts +37 -0
- package/test/platform/matter-childbridge.spec.ts +34 -0
- package/test/platform/matter-integration.spec.ts +33 -0
- package/test/platform/platform-edge.spec.ts +73 -0
- package/test/platform/platform.integration.spec.ts +34 -0
- package/test/utils/utils-extra.spec.ts +10 -0
- package/test/utils/utils.spec.ts +68 -0
- package/todo/TODO.md +80 -0
- package/tsconfig.ui.json +11 -0
- package/.github/workflows/beta-release.yml +0 -52
- package/dist/platform.d.ts +0 -35
- package/dist/platform.d.ts.map +0 -1
- package/dist/platform.js +0 -945
- package/dist/platform.js.map +0 -1
- package/src/platform.ts +0 -963
- package/test/accessory-restore.spec.ts +0 -73
- package/test/device-mapping.spec.ts +0 -37
- package/test/deviceFactory.spec.ts +0 -18
- package/test/fan-swing.spec.ts +0 -29
- package/test/lock-users.spec.ts +0 -44
- package/test/matter-childbridge.spec.ts +0 -55
- package/test/matter-descriptors.spec.ts +0 -97
- package/test/matter-device-state.spec.ts +0 -101
- package/test/matter-integration.spec.ts +0 -70
- package/test/platform.integration.spec.ts +0 -55
- package/test/switchbot-client-debounce.spec.ts +0 -131
- package/test/switchbot-client-openapi.spec.ts +0 -56
- package/test/switchbotClient.spec.ts +0 -10
- package/test/utils.spec.ts +0 -20
package/docs/index.html
CHANGED
|
@@ -19,6 +19,44 @@
|
|
|
19
19
|
<li>Click <strong>Install</strong></li>
|
|
20
20
|
</ol>
|
|
21
21
|
<h2 id="configuration" class="tsd-anchor-link">Configuration<a href="#configuration" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
22
|
+
<h3 id="openapi-pollingrate-advanced-settings-ui" class="tsd-anchor-link">OpenAPI Polling/Rate Advanced Settings (UI)<a href="#openapi-pollingrate-advanced-settings-ui" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
23
|
+
<p>You can now configure global OpenAPI polling and rate-limiting options directly from the Homebridge UI:</p>
|
|
24
|
+
<ul>
|
|
25
|
+
<li>Go to the SwitchBot plugin settings in Homebridge Config UI X.</li>
|
|
26
|
+
<li>Scroll to the <strong>Advanced Settings</strong> section at the bottom of the page.</li>
|
|
27
|
+
<li>Adjust the following options as needed:
|
|
28
|
+
<ul>
|
|
29
|
+
<li><strong>OpenAPI Polling Interval (seconds):</strong> How often to poll devices via OpenAPI for status. Default: 300 (5 min). Min: 30. Can be overridden per device.</li>
|
|
30
|
+
<li><strong>Enable Batched OpenAPI Polling:</strong> Poll all OpenAPI devices in a single batch at the configured interval. Devices with per-device refreshRate are excluded from the batch.</li>
|
|
31
|
+
<li><strong>OpenAPI Batch Polling Interval (seconds):</strong> Interval for batched OpenAPI polling. Falls back to OpenAPI Polling Interval if not set. Default: 300.</li>
|
|
32
|
+
<li><strong>OpenAPI Daily Request Limit:</strong> Maximum OpenAPI requests per day allowed by the plugin. Default: 10000.</li>
|
|
33
|
+
<li><strong>OpenAPI Reserve for Commands:</strong> Requests reserved for user actions. When remaining budget reaches this value, background polling pauses. Default: 1000.</li>
|
|
34
|
+
<li><strong>Reset OpenAPI Counter at Local Midnight:</strong> If true, resets the daily OpenAPI request counter at local midnight. If false, resets at UTC midnight.</li>
|
|
35
|
+
<li><strong>Only Allow Webhooks on Reserve:</strong> When remaining OpenAPI budget reaches the reserve, only webhooks and user commands are allowed. Background polling/discovery pauses.</li>
|
|
36
|
+
<li><strong>OpenAPI Batch Concurrency:</strong> Maximum number of parallel OpenAPI status calls during a batch. Default: 5.</li>
|
|
37
|
+
<li><strong>OpenAPI Batch Jitter (seconds):</strong> Random startup delay before the first batch to reduce synchronized spikes. Default: 0.</li>
|
|
38
|
+
</ul>
|
|
39
|
+
</li>
|
|
40
|
+
</ul>
|
|
41
|
+
<p>Click <strong>Save Advanced Settings</strong> to apply changes. These settings match the options available in <code>config.schema.json</code> and can be overridden per device.</p>
|
|
42
|
+
<!-- Optionally add a screenshot here -->
|
|
43
|
+
<h3 id="per-device-external-publishing-hap-or-matter" class="tsd-anchor-link">Per-Device External Publishing (HAP or Matter)<a href="#per-device-external-publishing-hap-or-matter" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
44
|
+
<p>Each device now supports an <code>externalPublishProtocol</code> option to control whether it is published as an external accessory.</p>
|
|
45
|
+
<ul>
|
|
46
|
+
<li><code>none</code> (default): normal platform registration behavior.</li>
|
|
47
|
+
<li><code>hap</code>: publish this device as a HAP external accessory.</li>
|
|
48
|
+
<li><code>matter</code>: publish this device as a Matter external accessory.</li>
|
|
49
|
+
</ul>
|
|
50
|
+
<p>Behavior notes:</p>
|
|
51
|
+
<ul>
|
|
52
|
+
<li>This is configured per device in the Homebridge UI under <strong>Publish as External Device</strong> when adding or editing a device.</li>
|
|
53
|
+
<li>If the selected external publish API is not available on your Homebridge runtime, the plugin falls back to normal platform registration for that device.</li>
|
|
54
|
+
<li>Use <code>hap</code> for HAP-focused setups and <code>matter</code> for Matter-focused setups; leave as <code>none</code> unless you specifically want external accessory publishing.</li>
|
|
55
|
+
</ul>
|
|
56
|
+
<p>Example device config excerpt:</p>
|
|
57
|
+
<pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-1">"deviceId"</span><span class="hl-0">: </span><span class="hl-2">"E7F8A1B2C3D4"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"configDeviceName"</span><span class="hl-0">: </span><span class="hl-2">"Bedroom Bot"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"configDeviceType"</span><span class="hl-0">: </span><span class="hl-2">"Bot"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"externalPublishProtocol"</span><span class="hl-0">: </span><span class="hl-2">"hap"</span><br/><span class="hl-0">}</span>
|
|
58
|
+
</code><button type="button">Copy</button></pre>
|
|
59
|
+
|
|
22
60
|
<ul>
|
|
23
61
|
<li>
|
|
24
62
|
<h3 id="if-using-openapi-connection" class="tsd-anchor-link">If using OpenAPI Connection<a href="#if-using-openapi-connection" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
@@ -96,7 +134,7 @@
|
|
|
96
134
|
(This is what is intended in documentation for the noble bluetooth package <a href="https://github.com/abandonware/noble#prerequisites">prerequisites</a> by "Add terminal app", however for HomeBridge it is <code>node</code> that needs the permission granted, not <code>terminal</code>.
|
|
97
135
|
Without this step, then you will receive the following error when the swichbot plugin launches, which will cause Homebridge or the child bridge process to restart:</li>
|
|
98
136
|
</ol>
|
|
99
|
-
<pre><code><span class="hl-
|
|
137
|
+
<pre><code><span class="hl-3">Error</span><span class="hl-0">: </span><span class="hl-4">Failed</span><span class="hl-0"> </span><span class="hl-4">to</span><span class="hl-0"> </span><span class="hl-4">initialize</span><span class="hl-0"> </span><span class="hl-4">the</span><span class="hl-0"> </span><span class="hl-4">Noble</span><span class="hl-0"> </span><span class="hl-3">object</span><span class="hl-0">: </span><span class="hl-4">unauthorized</span><br/><span class="hl-0"> </span><span class="hl-4">at</span><span class="hl-0"> </span><span class="hl-4">Noble</span><span class="hl-0">.<</span><span class="hl-5">anonymous</span><span class="hl-0">> (</span><span class="hl-4">file</span><span class="hl-0">:</span><span class="hl-6">///usr/local/lib/node_modules/@switchbot/homebridge-switchbot/node_modules/node-switchbot/src/switchbot.ts:244:19)</span><br/><span class="hl-0"> </span><span class="hl-5">at</span><span class="hl-0"> </span><span class="hl-5">Object</span><span class="hl-0">.</span><span class="hl-5">onceWrapper</span><span class="hl-0"> (</span><span class="hl-4">node</span><span class="hl-0">:</span><span class="hl-5">events</span><span class="hl-0">:</span><span class="hl-7">629</span><span class="hl-0">:</span><span class="hl-7">26</span><span class="hl-0">)</span><br/><span class="hl-0"> </span><span class="hl-5">at</span><span class="hl-0"> </span><span class="hl-5">Noble</span><span class="hl-0">.</span><span class="hl-5">emit</span><span class="hl-0"> (</span><span class="hl-4">node</span><span class="hl-0">:</span><span class="hl-5">events</span><span class="hl-0">:</span><span class="hl-7">514</span><span class="hl-0">:</span><span class="hl-7">28</span><span class="hl-0">)</span><br/><span class="hl-0"> </span><span class="hl-5">at</span><span class="hl-0"> </span><span class="hl-5">Noble</span><span class="hl-0">.</span><span class="hl-5">onStateChange</span><span class="hl-0"> (/</span><span class="hl-5">usr</span><span class="hl-0">/</span><span class="hl-5">local</span><span class="hl-0">/</span><span class="hl-5">lib</span><span class="hl-0">/</span><span class="hl-5">node_modules</span><span class="hl-0">/@</span><span class="hl-5">switchbot</span><span class="hl-0">/</span><span class="hl-5">homebridge</span><span class="hl-0">-</span><span class="hl-5">switchbot</span><span class="hl-0">/</span><span class="hl-5">node_modules</span><span class="hl-0">/@</span><span class="hl-5">stoprocent</span><span class="hl-0">/</span><span class="hl-5">noble</span><span class="hl-0">/</span><span class="hl-5">lib</span><span class="hl-0">/</span><span class="hl-5">noble</span><span class="hl-0">.</span><span class="hl-5">js</span><span class="hl-0">:</span><span class="hl-7">92</span><span class="hl-0">:</span><span class="hl-7">8</span><span class="hl-0">)</span><br/><span class="hl-0"> </span><span class="hl-5">at</span><span class="hl-0"> </span><span class="hl-5">NobleMac</span><span class="hl-0">.</span><span class="hl-5">emit</span><span class="hl-0"> (</span><span class="hl-4">node</span><span class="hl-0">:</span><span class="hl-5">events</span><span class="hl-0">:</span><span class="hl-7">514</span><span class="hl-0">:</span><span class="hl-7">28</span><span class="hl-0">)</span>
|
|
100
138
|
</code><button>Copy</button></pre>
|
|
101
139
|
|
|
102
140
|
</li>
|
|
@@ -281,6 +319,15 @@ Without this step, then you will receive the following error when the swichbot p
|
|
|
281
319
|
</li>
|
|
282
320
|
</ul>
|
|
283
321
|
</li>
|
|
322
|
+
<li><a href="https://us.switch-bot.com/products/switchbot-hub-mini-2">SwitchBot Hub Mini 2</a>
|
|
323
|
+
<ul>
|
|
324
|
+
<li>Supports OpenAPI & Bluetooth Low Energy (BLE) Connections
|
|
325
|
+
<ul>
|
|
326
|
+
<li>Enables Humidity, Temperature, and Light Sensor</li>
|
|
327
|
+
</ul>
|
|
328
|
+
</li>
|
|
329
|
+
</ul>
|
|
330
|
+
</li>
|
|
284
331
|
<li><a href="https://us.switch-bot.com/products/switchbot-hub-3">SwitchBot Hub 3</a>
|
|
285
332
|
<ul>
|
|
286
333
|
<li>Supports OpenAPI & Bluetooth Low Energy (BLE) Connections
|
|
@@ -301,8 +348,34 @@ Without this step, then you will receive the following error when the swichbot p
|
|
|
301
348
|
</ul>
|
|
302
349
|
</li>
|
|
303
350
|
</ul>
|
|
351
|
+
<h2 id="ble-encryption-support" class="tsd-anchor-link">BLE Encryption Support<a href="#ble-encryption-support" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
352
|
+
<h3 id="ble-encryption-key-and-key-id" class="tsd-anchor-link">BLE Encryption Key and Key ID<a href="#ble-encryption-key-and-key-id" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
353
|
+
<p>Some SwitchBot devices (notably newer locks, curtains, and select sensors) require a BLE encryption key and keyId for secure Bluetooth communication. This plugin supports configuring these fields for each device.</p>
|
|
354
|
+
<h4 id="how-to-obtain-ble-encryption-key-and-key-id" class="tsd-anchor-link">How to Obtain BLE Encryption Key and Key ID<a href="#how-to-obtain-ble-encryption-key-and-key-id" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h4>
|
|
355
|
+
<ol>
|
|
356
|
+
<li><strong>Open the SwitchBot App</strong> and select your device.</li>
|
|
357
|
+
<li>Go to <strong>Device Settings</strong> (gear icon).</li>
|
|
358
|
+
<li>Tap <strong>Device Info</strong>.</li>
|
|
359
|
+
<li>If your device supports BLE encryption, you will see fields for <strong>Encryption Key</strong> and <strong>Key ID</strong>. (If not visible, your device may not require encryption or may need a firmware update.)</li>
|
|
360
|
+
<li>Copy the <strong>Encryption Key</strong> and <strong>Key ID</strong> values.</li>
|
|
361
|
+
</ol>
|
|
362
|
+
<h4 id="how-to-configure-in-homebridge" class="tsd-anchor-link">How to Configure in Homebridge<a href="#how-to-configure-in-homebridge" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h4>
|
|
363
|
+
<p>In the Homebridge UI, when adding or editing a SwitchBot device, enter the <strong>Encryption Key</strong> and <strong>Key ID</strong> in the provided fields. These values will be securely used for BLE communication with your device.</p>
|
|
364
|
+
<p><strong>Example device config excerpt:</strong></p>
|
|
365
|
+
<pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-1">"deviceId"</span><span class="hl-0">: </span><span class="hl-2">"E7F8A1B2C3D4"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"deviceName"</span><span class="hl-0">: </span><span class="hl-2">"SwitchBot Lock"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"enableBLE"</span><span class="hl-0">: </span><span class="hl-8">true</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"encryptionKey"</span><span class="hl-0">: </span><span class="hl-2">"0123456789abcdef0123456789abcdef"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"keyId"</span><span class="hl-0">: </span><span class="hl-2">"01"</span><br/><span class="hl-0">}</span>
|
|
366
|
+
</code><button type="button">Copy</button></pre>
|
|
367
|
+
|
|
368
|
+
<h4 id="which-devices-require-ble-encryption" class="tsd-anchor-link">Which Devices Require BLE Encryption?<a href="#which-devices-require-ble-encryption" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h4>
|
|
369
|
+
<ul>
|
|
370
|
+
<li>SwitchBot Lock (and Lock Pro)</li>
|
|
371
|
+
<li>SwitchBot Curtain 3 (and some Curtain 2 with updated firmware)</li>
|
|
372
|
+
<li>Some sensors and new device models (see device info in app)</li>
|
|
373
|
+
</ul>
|
|
374
|
+
<p>If you are unsure, check your device's info in the SwitchBot app. If the fields are present, copy them into the plugin config.</p>
|
|
375
|
+
<p><strong>Note:</strong> If you enter an incorrect key or keyId, BLE communication will fail for that device. Double-check values if you encounter connection issues.</p>
|
|
376
|
+
<hr>
|
|
304
377
|
<h2 id="supported-ir-devices" class="tsd-anchor-link">Supported IR Devices<a href="#supported-ir-devices" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
305
|
-
<h3 id="all-ir-devices-require-switchbot-hub-2-switchbot-hub-3-or-hub-mini" class="tsd-anchor-link"><em>(All IR Devices require <a href="https://us.switch-bot.com/products/switchbot-hub-2">SwitchBot Hub 2</a>, <a href="https://us.switch-bot.com/products/switchbot-hub-3">SwitchBot Hub 3</a>, or <a href="https://www.switch-bot.com/products/switchbot-hub-mini">Hub Mini</a>)</em><a href="#all-ir-devices-require-switchbot-hub-2-switchbot-hub-3-or-hub-mini" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
378
|
+
<h3 id="all-ir-devices-require-switchbot-hub-2-switchbot-hub-mini-2-switchbot-hub-3-or-hub-mini" class="tsd-anchor-link"><em>(All IR Devices require <a href="https://us.switch-bot.com/products/switchbot-hub-2">SwitchBot Hub 2</a>, <a href="https://us.switch-bot.com/products/switchbot-hub-mini-2">SwitchBot Hub Mini 2</a>, <a href="https://us.switch-bot.com/products/switchbot-hub-3">SwitchBot Hub 3</a>, or <a href="https://www.switch-bot.com/products/switchbot-hub-mini">Hub Mini</a>)</em><a href="#all-ir-devices-require-switchbot-hub-2-switchbot-hub-mini-2-switchbot-hub-3-or-hub-mini" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3>
|
|
306
379
|
<ul>
|
|
307
380
|
<li>TV
|
|
308
381
|
<ul>
|
|
@@ -404,13 +477,16 @@ Without this step, then you will receive the following error when the swichbot p
|
|
|
404
477
|
<li>The batch worklist is randomized every cycle to further distribute API load.</li>
|
|
405
478
|
</ul>
|
|
406
479
|
<p>These controls keep API usage smooth and predictable while preserving per-device control when needed.</p>
|
|
407
|
-
<h2 id="whats-new-
|
|
480
|
+
<h2 id="whats-new-with-node-switchbot-v400" class="tsd-anchor-link">What's new with node-switchbot v4.0.0<a href="#whats-new-with-node-switchbot-v400" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
408
481
|
<ul>
|
|
409
482
|
<li>
|
|
410
483
|
<p>Matter-first: when Homebridge Matter is available the plugin now prefers registering Matter accessories (with HAP fallback).</p>
|
|
411
484
|
</li>
|
|
412
485
|
<li>
|
|
413
|
-
<p>Hybrid client: the plugin
|
|
486
|
+
<p>Hybrid client: the plugin uses <code>node-switchbot@^4.0.0</code> with BLE + OpenAPI discovery and OpenAPI fallback.</p>
|
|
487
|
+
</li>
|
|
488
|
+
<li>
|
|
489
|
+
<p>OpenAPI credentials: cloud discovery and cloud fallback paths require both <code>openApiToken</code> and <code>openApiSecret</code>.</p>
|
|
414
490
|
</li>
|
|
415
491
|
<li>
|
|
416
492
|
<p>UI always served: the plugin UI is packaged into <code>dist/homebridge-ui</code> and is always served when Homebridge UI support is present; there is no platform-level opt-out.</p>
|
|
@@ -419,6 +495,9 @@ Without this step, then you will receive the following error when the swichbot p
|
|
|
419
495
|
<p>OpenAPI hardening: OpenAPI calls have AbortController timeouts, jittered exponential backoff, per-device retry limits and cooldowns, and safe response parsing for resilient behavior.</p>
|
|
420
496
|
</li>
|
|
421
497
|
<li>
|
|
498
|
+
<p>v4 resilience enabled in discovery: plugin discovery enables retry, circuit-breaker, and connection-intelligence flags from <code>node-switchbot</code> v4.</p>
|
|
499
|
+
</li>
|
|
500
|
+
<li>
|
|
422
501
|
<p>Write coalescing (debounce): command writes to the same device are coalesced by default to avoid command floods. Configure with <code>writeDebounceMs</code> (milliseconds, default 100). Set to <code>0</code> to disable coalescing.</p>
|
|
423
502
|
</li>
|
|
424
503
|
</ul>
|
|
@@ -432,7 +511,7 @@ Without this step, then you will receive the following error when the swichbot p
|
|
|
432
511
|
<li><code>dailyApiResetLocalMidnight</code> (boolean, default false): if true, resets the daily counter at local midnight; when false, resets at UTC midnight.</li>
|
|
433
512
|
</ul>
|
|
434
513
|
<p>Example (excerpt):</p>
|
|
435
|
-
<pre><code class="json"><span class="hl-
|
|
514
|
+
<pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-1">"options"</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-1">"dailyApiLimit"</span><span class="hl-0">: </span><span class="hl-7">10000</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"dailyApiReserveForCommands"</span><span class="hl-0">: </span><span class="hl-7">1000</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"webhookOnlyOnReserve"</span><span class="hl-0">: </span><span class="hl-8">false</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-1">"dailyApiResetLocalMidnight"</span><span class="hl-0">: </span><span class="hl-8">true</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span>
|
|
436
515
|
</code><button type="button">Copy</button></pre>
|
|
437
516
|
|
|
438
517
|
<h2 id="switchbot-apis" class="tsd-anchor-link">SwitchBot APIs<a href="#switchbot-apis" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
@@ -444,10 +523,25 @@ Without this step, then you will receive the following error when the swichbot p
|
|
|
444
523
|
</ul>
|
|
445
524
|
</li>
|
|
446
525
|
</ul>
|
|
526
|
+
<h2 id="development-tests" class="tsd-anchor-link">Development / Tests<a href="#development-tests" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
527
|
+
<ul>
|
|
528
|
+
<li>
|
|
529
|
+
<p>Run unit tests:</p>
|
|
530
|
+
<pre><code class="bash"><span class="hl-9">npm</span><span class="hl-0"> </span><span class="hl-2">run</span><span class="hl-0"> </span><span class="hl-2">test</span>
|
|
531
|
+
</code><button type="button">Copy</button></pre>
|
|
532
|
+
|
|
533
|
+
</li>
|
|
534
|
+
<li>
|
|
535
|
+
<p>Notes:</p>
|
|
536
|
+
<ul>
|
|
537
|
+
<li>Added Lock Ultra (Cloud + BLE) support with <code>node-switchbot</code> v4.</li>
|
|
538
|
+
</ul>
|
|
539
|
+
</li>
|
|
540
|
+
</ul>
|
|
447
541
|
<h2 id="community" class="tsd-anchor-link">Community<a href="#community" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
448
542
|
<ul>
|
|
449
543
|
<li><a href="https://www.switch-bot.com/">SwitchBot (Official website)</a></li>
|
|
450
544
|
<li><a href="https://www.facebook.com/SwitchBotRobot/">Facebook @SwitchBotRobot</a></li>
|
|
451
545
|
<li><a href="https://twitter.com/switchbot">Twitter @SwitchBot</a></li>
|
|
452
546
|
</ul>
|
|
453
|
-
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#switchbothomebridge-switchbot"><span>@switchbot/homebridge-<wbr/>switchbot</span></a><ul><li><a href="#installation"><span>Installation</span></a></li><li><a href="#configuration"><span>Configuration</span></a></li><li><ul><li><a href="#if-using-openapi-connection"><span>If using <wbr/>Open<wbr/>API <wbr/>Connection</span></a></li><li><a href="#if-using-ble-connection"><span>If using <wbr/>BLE <wbr/>Connection</span></a></li></ul></li><li><a href="#troubleshooting"><span>Troubleshooting</span></a></li><li><ul><li><a href="#if-using-linux-raspberry-pi-os"><span>If using <wbr/>Linux / <wbr/>Raspberry <wbr/>Pi <wbr/>OS</span></a></li><li><a href="#if-using-macos"><span>If using <wbr/>Mac<wbr/>OS</span></a></li></ul></li><li><a href="#supported-switchbot-devices"><span>Supported <wbr/>Switch<wbr/>Bot <wbr/>Devices</span></a></li><li><a href="#supported-ir-devices"><span>Supported <wbr/>IR <wbr/>Devices</span></a></li><li><ul><li><a href="#all-ir-devices-require-switchbot-hub-2-switchbot-hub-3-or-hub-mini"><span>(<wbr/>All <wbr/>IR <wbr/>Devices require <wbr/>Switch<wbr/>Bot <wbr/>Hub 2, <wbr/>Switch<wbr/>Bot <wbr/>Hub 3, or <wbr/>Hub <wbr/>Mini)</span></a></li></ul></li><li><a href="#matter-platform"><span>Matter <wbr/>Platform</span></a></li><li><ul><li><a href="#batched-refresh-and-api-load-control"><span>Batched refresh and <wbr/>API load control</span></a></li></ul></li><li><a href="#whats-new-
|
|
547
|
+
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#switchbothomebridge-switchbot"><span>@switchbot/homebridge-<wbr/>switchbot</span></a><ul><li><a href="#installation"><span>Installation</span></a></li><li><a href="#configuration"><span>Configuration</span></a></li><li><ul><li><a href="#openapi-pollingrate-advanced-settings-ui"><span>Open<wbr/>API <wbr/>Polling/<wbr/>Rate <wbr/>Advanced <wbr/>Settings (<wbr/>UI)</span></a></li><li><a href="#per-device-external-publishing-hap-or-matter"><span>Per-<wbr/>Device <wbr/>External <wbr/>Publishing (<wbr/>HAP or <wbr/>Matter)</span></a></li><li><a href="#if-using-openapi-connection"><span>If using <wbr/>Open<wbr/>API <wbr/>Connection</span></a></li><li><a href="#if-using-ble-connection"><span>If using <wbr/>BLE <wbr/>Connection</span></a></li></ul></li><li><a href="#troubleshooting"><span>Troubleshooting</span></a></li><li><ul><li><a href="#if-using-linux-raspberry-pi-os"><span>If using <wbr/>Linux / <wbr/>Raspberry <wbr/>Pi <wbr/>OS</span></a></li><li><a href="#if-using-macos"><span>If using <wbr/>Mac<wbr/>OS</span></a></li></ul></li><li><a href="#supported-switchbot-devices"><span>Supported <wbr/>Switch<wbr/>Bot <wbr/>Devices</span></a></li><li><a href="#ble-encryption-support"><span>BLE <wbr/>Encryption <wbr/>Support</span></a></li><li><ul><li><a href="#ble-encryption-key-and-key-id"><span>BLE <wbr/>Encryption <wbr/>Key and <wbr/>Key <wbr/>ID</span></a></li><li><ul><li><a href="#how-to-obtain-ble-encryption-key-and-key-id"><span>How to <wbr/>Obtain <wbr/>BLE <wbr/>Encryption <wbr/>Key and <wbr/>Key <wbr/>ID</span></a></li><li><a href="#how-to-configure-in-homebridge"><span>How to <wbr/>Configure in <wbr/>Homebridge</span></a></li><li><a href="#which-devices-require-ble-encryption"><span>Which <wbr/>Devices <wbr/>Require <wbr/>BLE <wbr/>Encryption?</span></a></li></ul></li></ul></li><li><a href="#supported-ir-devices"><span>Supported <wbr/>IR <wbr/>Devices</span></a></li><li><ul><li><a href="#all-ir-devices-require-switchbot-hub-2-switchbot-hub-mini-2-switchbot-hub-3-or-hub-mini"><span>(<wbr/>All <wbr/>IR <wbr/>Devices require <wbr/>Switch<wbr/>Bot <wbr/>Hub 2, <wbr/>Switch<wbr/>Bot <wbr/>Hub <wbr/>Mini 2, <wbr/>Switch<wbr/>Bot <wbr/>Hub 3, or <wbr/>Hub <wbr/>Mini)</span></a></li></ul></li><li><a href="#matter-platform"><span>Matter <wbr/>Platform</span></a></li><li><ul><li><a href="#batched-refresh-and-api-load-control"><span>Batched refresh and <wbr/>API load control</span></a></li></ul></li><li><a href="#whats-new-with-node-switchbot-v400"><span>What's new with node-<wbr/>switchbot v4.0.0</span></a></li><li><a href="#openapi-rate-limiting-and-daily-budget"><span>Open<wbr/>API rate limiting and daily budget</span></a></li><li><a href="#switchbot-apis"><span>Switch<wbr/>Bot <wbr/>AP<wbr/>Is</span></a></li><li><a href="#development-tests"><span>Development / <wbr/>Tests</span></a></li><li><a href="#community"><span>Community</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html">@switchbot/homebridge-switchbot</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=></span> <span class="tsd-signature-type">void</span></div><div class="tsd-
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=></span> <span class="tsd-signature-type">void</span></div><div class="tsd-comment tsd-typography"><p>Registers the SwitchBot platform with Homebridge.</p>
|
|
2
|
+
</div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span><div class="tsd-comment tsd-typography"><p>The Homebridge API instance.</p>
|
|
3
|
+
</div></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/b3af65f017e09fd27d158673c1c37935372c3fd8/src/index.ts#L22">index.ts:22</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">@switchbot/homebridge-switchbot</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
|
package/eslint.config.js
CHANGED
|
@@ -10,15 +10,22 @@ export default antfu(
|
|
|
10
10
|
},
|
|
11
11
|
rules: {
|
|
12
12
|
'curly': ['error', 'multi-line'],
|
|
13
|
+
'import/order': 0,
|
|
13
14
|
'jsdoc/check-alignment': 'error',
|
|
14
15
|
'jsdoc/check-line-alignment': 'error',
|
|
16
|
+
'no-new': 0,
|
|
17
|
+
'no-undef': 0,
|
|
15
18
|
'perfectionist/sort-exports': 'error',
|
|
16
19
|
'perfectionist/sort-imports': [
|
|
17
20
|
'error',
|
|
18
21
|
{
|
|
19
22
|
groups: [
|
|
20
|
-
'type',
|
|
21
|
-
|
|
23
|
+
'type-builtin',
|
|
24
|
+
'type-external',
|
|
25
|
+
'type-internal',
|
|
26
|
+
['type-parent', 'type-sibling', 'type-index'],
|
|
27
|
+
'builtin',
|
|
28
|
+
'external',
|
|
22
29
|
'internal',
|
|
23
30
|
['parent', 'sibling', 'index'],
|
|
24
31
|
'unknown',
|
|
@@ -35,9 +42,6 @@ export default antfu(
|
|
|
35
42
|
'test/no-only-tests': 'error',
|
|
36
43
|
'unicorn/no-useless-spread': 'error',
|
|
37
44
|
'unused-imports/no-unused-vars': ['error', { caughtErrors: 'none' }],
|
|
38
|
-
'no-new': 0, // Disable the no-new rule
|
|
39
|
-
'new-cap': 0, // Disable the new-cap rule
|
|
40
|
-
'no-undef': 0, // Disable the no-undef rule
|
|
41
45
|
},
|
|
42
46
|
},
|
|
43
47
|
)
|
package/nodemon.json
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@switchbot/homebridge-switchbot",
|
|
3
3
|
"displayName": "SwitchBot",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "5.
|
|
5
|
+
"version": "5.1.0-beta.0",
|
|
6
6
|
"description": "The SwitchBot plugin allows you to access your SwitchBot device(s) from HomeKit.",
|
|
7
7
|
"author": "SwitchBot <support@wondertechlabs.com> (https://github.com/SwitchBot)",
|
|
8
8
|
"contributors": [
|
|
@@ -56,20 +56,29 @@
|
|
|
56
56
|
"icon": "https://raw.githubusercontent.com/OpenWonderLabs/homebridge-switchbot/latest/branding/icon.png",
|
|
57
57
|
"engineStrict": true,
|
|
58
58
|
"engines": {
|
|
59
|
-
"homebridge": "^2.0.0-beta.
|
|
60
|
-
"node": "^
|
|
59
|
+
"homebridge": "^2.0.0-beta.86",
|
|
60
|
+
"node": "^22 || ^24"
|
|
61
61
|
},
|
|
62
62
|
"directories": {
|
|
63
63
|
"doc": "docs"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
|
+
"sync:device-types": "node scripts/sync-device-types.mjs",
|
|
66
67
|
"check": "npm install && npm outdated",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
68
|
+
"ports:free": "node scripts/free-dev-ports.mjs",
|
|
69
|
+
"typecheck": "tsc --noEmit",
|
|
70
|
+
"lint": "eslint --no-warn-ignored src/**/*.ts test/**/*.ts src/homebridge-ui/**/*.html src/homebridge-ui/public/js/*.ts && npm run typecheck",
|
|
71
|
+
"lint:src": "eslint --no-warn-ignored src/**/*.ts",
|
|
72
|
+
"lint:test": "eslint --no-warn-ignored test/**/*.ts",
|
|
73
|
+
"lint:ui": "eslint --no-warn-ignored src/homebridge-ui/**/*.html",
|
|
74
|
+
"lint:fix": "eslint --no-warn-ignored src/**/*.ts test/**/*.ts src/homebridge-ui/**/*.html src/homebridge-ui/public/js/*.ts --fix && npm run typecheck",
|
|
75
|
+
"watch": "npm run ports:free && npm run build && npm run build:ui && npm run plugin-ui && npm link && nodemon",
|
|
76
|
+
"watch:ui": "npm run ports:free && bash -c 'npx homebridge -I -U -D ~/.homebridge-dev & HB_PID=$!; sleep 6; UIX_STORAGE_PATH=~/.homebridge-dev node ./node_modules/homebridge-config-ui-x/dist/bin/standalone.js & npm run watch:files'",
|
|
77
|
+
"watch:files": "nodemon",
|
|
78
|
+
"plugin-ui": "mkdir -p ./dist/homebridge-ui/public && if [ -d ./src/homebridge-ui/public ]; then rsync -a ./src/homebridge-ui/public/ ./dist/homebridge-ui/public/; fi && node scripts/build-ui.js",
|
|
79
|
+
"build": "npm run sync:device-types && npm run clean && tsc && npm run plugin-ui",
|
|
80
|
+
"build:ui": "tsc --project tsconfig.ui.json",
|
|
81
|
+
"prepublishOnly": "npm run lint && npm run build && npm run build:ui && npm run plugin-ui && npm run docs && npm run docs:lint",
|
|
73
82
|
"postpublish": "npm run clean && npm ci",
|
|
74
83
|
"clean": "shx rm -rf ./dist",
|
|
75
84
|
"test": "vitest run",
|
|
@@ -82,25 +91,29 @@
|
|
|
82
91
|
"access": "public"
|
|
83
92
|
},
|
|
84
93
|
"dependencies": {
|
|
85
|
-
"@homebridge/plugin-ui-utils": "^2.2.
|
|
86
|
-
"
|
|
94
|
+
"@homebridge/plugin-ui-utils": "^2.2.3",
|
|
95
|
+
"class-validator": "^0.15.1",
|
|
96
|
+
"node-switchbot": "^4.0.0"
|
|
87
97
|
},
|
|
88
98
|
"devDependencies": {
|
|
89
|
-
"@antfu/eslint-config": "^
|
|
90
|
-
"@types/debug": "^4.1.
|
|
99
|
+
"@antfu/eslint-config": "^8.1.1",
|
|
100
|
+
"@types/debug": "^4.1.13",
|
|
91
101
|
"@types/fs-extra": "^11.0.4",
|
|
92
|
-
"@types/node": "^25.
|
|
102
|
+
"@types/node": "^25.6.0",
|
|
93
103
|
"@types/semver": "^7.7.1",
|
|
94
104
|
"@types/source-map-support": "^0.5.10",
|
|
95
|
-
"@vitest/coverage-v8": "^4.
|
|
96
|
-
"
|
|
105
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
106
|
+
"esbuild": "^0.28.0",
|
|
107
|
+
"eslint": "^10.2.0",
|
|
97
108
|
"eslint-plugin-format": "^2.0.1",
|
|
98
|
-
"
|
|
99
|
-
"
|
|
109
|
+
"eslint-plugin-html": "^8.1.4",
|
|
110
|
+
"eslint-plugin-perfectionist": "^5.8.0",
|
|
111
|
+
"homebridge": "^2.0.0-beta.86",
|
|
112
|
+
"homebridge-config-ui-x": "^5.21.0",
|
|
100
113
|
"nodemon": "^3.1.14",
|
|
101
114
|
"shx": "^0.4.0",
|
|
102
|
-
"typedoc": "^0.28.
|
|
103
|
-
"typescript": "^
|
|
104
|
-
"vitest": "^4.
|
|
115
|
+
"typedoc": "^0.28.18",
|
|
116
|
+
"typescript": "^6.0.2",
|
|
117
|
+
"vitest": "^4.1.4"
|
|
105
118
|
}
|
|
106
119
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import esbuild from 'esbuild'
|
|
4
|
+
import fs from 'node:fs'
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
import process from 'node:process'
|
|
7
|
+
import { fileURLToPath } from 'node:url'
|
|
8
|
+
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
|
|
11
|
+
const srcDir = path.resolve(__dirname, '../src/homebridge-ui/public/js')
|
|
12
|
+
const outputDir = path.resolve(__dirname, '../dist/homebridge-ui/public/js')
|
|
13
|
+
|
|
14
|
+
// Ensure output directory exists
|
|
15
|
+
fs.mkdirSync(outputDir, { recursive: true })
|
|
16
|
+
|
|
17
|
+
// Transpile TypeScript to JavaScript with esbuild
|
|
18
|
+
esbuild
|
|
19
|
+
.build({
|
|
20
|
+
entryPoints: [path.join(srcDir, 'app.ts')],
|
|
21
|
+
outfile: path.join(outputDir, 'app.js'),
|
|
22
|
+
bundle: true,
|
|
23
|
+
target: 'es2020',
|
|
24
|
+
platform: 'browser',
|
|
25
|
+
format: 'esm',
|
|
26
|
+
sourcemap: true,
|
|
27
|
+
external: [],
|
|
28
|
+
minify: false,
|
|
29
|
+
logLevel: 'info',
|
|
30
|
+
})
|
|
31
|
+
.then(() => {
|
|
32
|
+
console.log('✓ UI bundling complete')
|
|
33
|
+
})
|
|
34
|
+
.catch((error) => {
|
|
35
|
+
console.error('✗ UI bundling failed:', error)
|
|
36
|
+
process.exit(1)
|
|
37
|
+
})
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { resolve } from 'node:path'
|
|
5
|
+
|
|
6
|
+
function resolvePorts() {
|
|
7
|
+
let bridgePort = 51829
|
|
8
|
+
let uiPort = 8581
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const configPath = resolve(homedir(), '.homebridge-dev', 'config.json')
|
|
12
|
+
const config = JSON.parse(readFileSync(configPath, 'utf8'))
|
|
13
|
+
|
|
14
|
+
if (typeof config?.bridge?.port === 'number') {
|
|
15
|
+
bridgePort = config.bridge.port
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const configUiPlatform = Array.isArray(config?.platforms)
|
|
19
|
+
? config.platforms.find(platform => platform?.platform === 'config')
|
|
20
|
+
: undefined
|
|
21
|
+
|
|
22
|
+
if (typeof configUiPlatform?.port === 'number') {
|
|
23
|
+
uiPort = configUiPlatform.port
|
|
24
|
+
}
|
|
25
|
+
} catch {}
|
|
26
|
+
|
|
27
|
+
return [...new Set([bridgePort, uiPort])]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function pidsForPort(port) {
|
|
31
|
+
try {
|
|
32
|
+
const output = execSync(`lsof -ti tcp:${port}`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim()
|
|
33
|
+
return output ? output.split('\n').filter(Boolean) : []
|
|
34
|
+
} catch {
|
|
35
|
+
return []
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function freePort(port) {
|
|
40
|
+
const initialPids = pidsForPort(port)
|
|
41
|
+
if (initialPids.length === 0) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
execSync(`lsof -ti tcp:${port} | xargs -r kill -TERM`, { stdio: ['ignore', 'ignore', 'ignore'] })
|
|
47
|
+
} catch {}
|
|
48
|
+
|
|
49
|
+
const remainingPids = pidsForPort(port)
|
|
50
|
+
if (remainingPids.length > 0) {
|
|
51
|
+
try {
|
|
52
|
+
execSync(`lsof -ti tcp:${port} | xargs -r kill -KILL`, { stdio: ['ignore', 'ignore', 'ignore'] })
|
|
53
|
+
} catch {}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function cleanupDevProcesses() {
|
|
58
|
+
let output = ''
|
|
59
|
+
try {
|
|
60
|
+
output = execSync('ps -axo pid=,command=', { stdio: ['ignore', 'pipe', 'ignore'] }).toString()
|
|
61
|
+
} catch {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const targetPids = output
|
|
66
|
+
.split('\n')
|
|
67
|
+
.map(line => line.trim())
|
|
68
|
+
.filter(Boolean)
|
|
69
|
+
.map((line) => {
|
|
70
|
+
const firstSpace = line.indexOf(' ')
|
|
71
|
+
if (firstSpace === -1) {
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const pid = Number(line.slice(0, firstSpace).trim())
|
|
76
|
+
const command = line.slice(firstSpace + 1)
|
|
77
|
+
return Number.isFinite(pid) ? { pid, command } : null
|
|
78
|
+
})
|
|
79
|
+
.filter((entry) => {
|
|
80
|
+
if (!entry) {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (entry.pid === process.pid || entry.pid === process.ppid) {
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const isNodemonProcess = entry.command.includes('homebridge-switchbot/node_modules/.bin/nodemon')
|
|
89
|
+
const isConfigUiProcess = entry.command.trim().startsWith('homebridge-config-ui-x')
|
|
90
|
+
return isNodemonProcess || isConfigUiProcess
|
|
91
|
+
})
|
|
92
|
+
.map(entry => entry.pid)
|
|
93
|
+
|
|
94
|
+
for (const pid of targetPids) {
|
|
95
|
+
try {
|
|
96
|
+
process.kill(pid, 'SIGTERM')
|
|
97
|
+
} catch {}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
cleanupDevProcesses()
|
|
102
|
+
|
|
103
|
+
for (const port of resolvePorts()) {
|
|
104
|
+
freePort(port)
|
|
105
|
+
}
|