homebridge-slwf-01pro 0.1.2 → 0.2.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/CHANGELOG.md CHANGED
@@ -7,6 +7,57 @@ This package is a maintained fork of [`homebridge-esphome-ac`](https://github.co
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.2.0] — 2026-05-06
11
+
12
+ Clean separation from upstream `homebridge-esphome-ac`. Breaking config change (one-line edit) but eliminates all namespace collision risk.
13
+
14
+ ### ⚠️ Breaking — config.json edit required
15
+
16
+ The Homebridge platform identifier has been renamed from `"ESPHomeAC"` (shared with upstream) to **`"SLWFOnePro"`** (ours alone). Update your `config.json`:
17
+
18
+ ```diff
19
+ - "platform": "ESPHomeAC",
20
+ + "platform": "SLWFOnePro",
21
+ ```
22
+
23
+ Restart Homebridge after the edit. The plugin detects orphaned cached accessories from the old identifier and logs a clear warning with cleanup instructions on first start.
24
+
25
+ ### Why
26
+
27
+ Before 0.2.0, the platform identifier was shared with upstream `homebridge-esphome-ac` for "drop-in migration" compatibility. In practice this caused two real problems:
28
+
29
+ 1. **Cache collisions** — when both plugins were ever installed in the same Homebridge (even temporarily during a migration), accessories cached under upstream's plugin name became orphans that no live plugin claims, but the platform identifier overlap made it ambiguous which plugin "owned" them.
30
+ 2. **Confusing logs** — Homebridge's startup log lists all installed platforms by `<plugin>.<platformName>`. Both plugins claiming `ESPHomeAC` made the dependency graph unreadable.
31
+
32
+ After 0.2.0, the two plugins are completely independent: separate npm names, separate platform identifiers, no shared state. Both can coexist on the same Homebridge without interfering.
33
+
34
+ ### Added
35
+
36
+ - **`detectOrphanedAccessories(platform)` in `lib/esphome.js`.** Best-effort scan of the bridge's `cachedAccessories.<bridgeId>` files at startup. Warns about:
37
+ - Accessories cached under upstream `homebridge-esphome-ac`
38
+ - Accessories cached under our plugin name but the **legacy** `ESPHomeAC` platform identifier (i.e. pre-0.2.0 entries left after the rename)
39
+ Both warnings include explicit cleanup paths (Homebridge UI step + filesystem path). Best-effort — wrapped in try/catch, never throws, falls through silently if the cache directory doesn't exist or files are malformed.
40
+
41
+ ### Changed
42
+
43
+ - **Platform identifier `ESPHomeAC` → `SLWFOnePro`** in `index.js` `PLATFORM_NAME`, `config.schema.json` `pluginAlias`, `config-sample.json`, README, CLAUDE.md, QA_TESTS.md.
44
+ - **Upstream git remote removed** (`git remote remove upstream`). The fork is intentionally divergent. CLAUDE.md fork rules updated; if anyone needs upstream history they can re-add the remote ad-hoc.
45
+
46
+ ### Migration
47
+
48
+ For anyone on `homebridge-slwf-01pro@0.1.x`:
49
+ 1. `sudo npm install -g homebridge-slwf-01pro@latest`
50
+ 2. Edit `config.json`: `"platform": "ESPHomeAC"` → `"platform": "SLWFOnePro"` (and the `name` field if you used the default).
51
+ 3. Restart Homebridge.
52
+ 4. Log will warn about the orphaned 0.1.x cached accessories. Clean via Homebridge UI → Settings → Remove Single Cached Accessory.
53
+
54
+ For anyone migrating from upstream `homebridge-esphome-ac`:
55
+ 1. `sudo npm uninstall -g homebridge-esphome-ac && sudo npm install -g homebridge-slwf-01pro`
56
+ 2. Same `config.json` edit as above.
57
+ 3. Restart. Log warns about upstream's orphaned cache entries. Clean via UI.
58
+
59
+ ---
60
+
10
61
  ## [0.1.2] — 2026-05-06
11
62
 
12
63
  Critical bug fix surfaced by the first real-hardware test of 0.1.0/0.1.1.
package/README.md CHANGED
@@ -56,8 +56,8 @@ The simplest config — auto-discover everything on the local network:
56
56
  {
57
57
  "platforms": [
58
58
  {
59
- "platform": "ESPHomeAC",
60
- "name": "ESPHomeAC",
59
+ "platform": "SLWFOnePro",
60
+ "name": "SLWFOnePro",
61
61
  "autoDiscover": true
62
62
  }
63
63
  ]
@@ -70,8 +70,8 @@ Or fully manual (required for encrypted devices and any device not on the same b
70
70
  {
71
71
  "platforms": [
72
72
  {
73
- "platform": "ESPHomeAC",
74
- "name": "ESPHomeAC",
73
+ "platform": "SLWFOnePro",
74
+ "name": "SLWFOnePro",
75
75
  "debug": false,
76
76
  "devices": [
77
77
  {
@@ -93,8 +93,8 @@ You can mix both — listed devices in `devices[]` take precedence; auto-discove
93
93
 
94
94
  | Key | Required | Default | Notes |
95
95
  |---|---|---|---|
96
- | `platform` | yes | — | Must be exactly `"ESPHomeAC"` (the platform identifier — same as the upstream plugin so existing configs migrate without edits) |
97
- | `name` | no | `ESPHomeAC` | Display name in Homebridge logs |
96
+ | `platform` | yes | — | Must be exactly `"SLWFOnePro"` (the platform identifier — distinct from upstream `homebridge-esphome-ac`'s `"ESPHomeAC"` to guarantee no namespace collision when both plugins are installed). Pre-0.2.0 configs using `"ESPHomeAC"` need a one-line edit. |
97
+ | `name` | no | `SLWFOnePro` | Display name in Homebridge logs |
98
98
  | `debug` | no | `false` | Surface ESPHome state-change chatter to the main log instead of `log.debug` |
99
99
  | `autoDiscover` | no | `false` | mDNS-browse for ESPHome devices on the local network and create accessories automatically. Encrypted devices still need a manual `devices[]` entry — the Noise key is not broadcast. |
100
100
  | `discoveryTimeout` | no | `5` | Seconds to wait for mDNS responses before continuing. |
@@ -184,17 +184,37 @@ If the device advertises any swing mode beyond OFF, a HomeKit Swing toggle is ex
184
184
 
185
185
  ## Migration
186
186
 
187
- If you're moving from the upstream `homebridge-esphome-ac`:
187
+ ### From upstream `homebridge-esphome-ac`
188
188
 
189
- ```bash
190
- sudo npm uninstall -g homebridge-esphome-ac
191
- sudo npm install -g homebridge-slwf-01pro
192
- sudo systemctl restart homebridge # or: hb-service restart
193
- ```
189
+ Both the npm package name AND the Homebridge platform identifier are different from upstream — that's deliberate, and it means the two plugins never share cache or namespace. Migration is two short steps:
190
+
191
+ 1. **Replace the package**:
192
+ ```bash
193
+ sudo npm uninstall -g homebridge-esphome-ac
194
+ sudo npm install -g homebridge-slwf-01pro
195
+ ```
196
+
197
+ 2. **Edit `config.json`** — change `"platform": "ESPHomeAC"` to `"platform": "SLWFOnePro"`:
198
+ ```jsonc
199
+ {
200
+ "platforms": [
201
+ {
202
+ "platform": "SLWFOnePro", // ← was "ESPHomeAC"
203
+ "name": "SLWFOnePro", // ← rename to match (or keep your custom name)
204
+ "autoDiscover": true,
205
+ "devices": [ /* ...same as before... */ ]
206
+ }
207
+ ]
208
+ }
209
+ ```
210
+
211
+ 3. **Restart Homebridge**: `sudo systemctl restart homebridge` (or via UI).
212
+
213
+ The plugin will detect any cached accessories left over from upstream and **log a warning** with cleanup instructions on startup. Clean them via Homebridge UI → Settings → Remove Single Cached Accessory, or stop the (child) bridge and delete the relevant `cachedAccessories.<bridgeId>` file. The new accessories from this plugin will re-pair automatically on the next restart with stable UUIDs derived from each device's ESPHome `unique_id` (or from the MAC + `object_id` when `unique_id` isn't set).
194
214
 
195
- **Your `config.json` does not need changes.** The platform identifier (`"platform": "ESPHomeAC"`) is unchanged for compatibility — only the npm package name differs.
215
+ ### From a pre-0.2.0 release of this plugin
196
216
 
197
- If accessories appear duplicated after the migration, clear Homebridge's cached accessories from the UI (Settings Remove Single Cached Accessory) for the orphaned ones from the old plugin. The new plugin will re-pair them automatically on the next restart with stable UUIDs derived from each device's ESPHome `entity.config.uniqueId`.
217
+ If you upgraded from `homebridge-slwf-01pro@0.1.x`, the platform identifier rename is the only change you need to apply (step 2 above). The plugin will detect old `"ESPHomeAC"` cached entries and log a warning the same way.
198
218
 
199
219
  ## Known SLWF-01Pro quirks
200
220
 
@@ -9,8 +9,8 @@
9
9
  "description": "Sample config for the homebridge-SLWF-01Pro fork. Pick auto-discovery OR manual devices, or both.",
10
10
  "platforms": [
11
11
  {
12
- "platform": "ESPHomeAC",
13
- "name": "ESPHomeAC",
12
+ "platform": "SLWFOnePro",
13
+ "name": "SLWFOnePro",
14
14
  "debug": false,
15
15
  "autoDiscover": true,
16
16
  "discoveryTimeout": 5,
@@ -1,5 +1,5 @@
1
1
  {
2
- "pluginAlias": "ESPHomeAC",
2
+ "pluginAlias": "SLWFOnePro",
3
3
  "pluginType": "platform",
4
4
  "singular": true,
5
5
  "headerDisplay": "Homebridge plugin for ESPHome AC controllers (SLWF-01Pro Wi-Fi dongle and other ESPHome `Climate` entities). Supports auto-discovery, humidity / outdoor-temperature / power sensors, beeper / display switches, and DRY / FAN_ONLY mode tiles.",
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const ESPHome = require('./lib/esphome');
2
2
 
3
3
  const PLUGIN_NAME = 'homebridge-slwf-01pro';
4
- const PLATFORM_NAME = 'ESPHomeAC';
4
+ const PLATFORM_NAME = 'SLWFOnePro';
5
5
 
6
6
  class ESPHomeAC {
7
7
  constructor(log, config, api) {
package/lib/esphome.js CHANGED
@@ -1,3 +1,5 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
1
3
  const { Client } = require('@2colors/esphome-native-api');
2
4
  const DeviceAccessory = require('./DeviceAccessory');
3
5
  const { discoverDevices } = require('./discovery');
@@ -6,13 +8,61 @@ const { bundleEntities } = require('./classifyEntity');
6
8
  const RECONNECT_INTERVAL_MS = 5000;
7
9
  const DEFAULT_DISCOVERY_TIMEOUT_S = 5;
8
10
 
11
+ const UPSTREAM_PLUGIN_NAME = 'homebridge-esphome-ac';
12
+ const LEGACY_PLATFORM_NAME = 'ESPHomeAC';
13
+
9
14
  function normalizeHost(value) {
10
15
  if (!value) return '';
11
16
  return value.toString().toLowerCase().replace(/\.local\.?$/, '').replace(/\.$/, '');
12
17
  }
13
18
 
19
+ function detectOrphanedAccessories(platform) {
20
+ try {
21
+ const cacheDir = path.join(platform.api.user.persistPath(), 'accessories');
22
+ if (!fs.existsSync(cacheDir)) return;
23
+
24
+ const files = fs.readdirSync(cacheDir).filter(f => f.startsWith('cachedAccessories.'));
25
+ let upstreamCount = 0;
26
+ let legacyPlatformCount = 0;
27
+
28
+ for (const file of files) {
29
+ let content;
30
+ try {
31
+ content = JSON.parse(fs.readFileSync(path.join(cacheDir, file), 'utf8'));
32
+ } catch (_e) {
33
+ continue;
34
+ }
35
+ if (!Array.isArray(content)) continue;
36
+ for (const acc of content) {
37
+ if (!acc) continue;
38
+ if (acc.plugin === UPSTREAM_PLUGIN_NAME) upstreamCount++;
39
+ else if (acc.plugin === platform.PLUGIN_NAME && acc.platform === LEGACY_PLATFORM_NAME) legacyPlatformCount++;
40
+ }
41
+ }
42
+
43
+ if (upstreamCount > 0) {
44
+ platform.log.warn(
45
+ `Detected ${upstreamCount} cached accessor${upstreamCount === 1 ? 'y' : 'ies'} from upstream "${UPSTREAM_PLUGIN_NAME}". ` +
46
+ `These are orphans (this plugin is "${platform.PLUGIN_NAME}", different name). ` +
47
+ `Clean up via Homebridge UI → Settings → Remove Single Cached Accessory, ` +
48
+ `or stop Homebridge and delete cachedAccessories.* in ${cacheDir}, then restart.`
49
+ );
50
+ }
51
+ if (legacyPlatformCount > 0) {
52
+ platform.log.warn(
53
+ `Detected ${legacyPlatformCount} cached accessor${legacyPlatformCount === 1 ? 'y' : 'ies'} using the legacy "${LEGACY_PLATFORM_NAME}" platform identifier (pre-0.2.0). ` +
54
+ `The platform was renamed to "SLWFOnePro" in v0.2.0; the old entries are orphans. ` +
55
+ `Update your config.json (\`"platform": "SLWFOnePro"\`) and clean up via Homebridge UI → Settings → Remove Single Cached Accessory.`
56
+ );
57
+ }
58
+ } catch (err) {
59
+ platform.log.easyDebug(`Orphan detection failed (non-fatal): ${err.message || err}`);
60
+ }
61
+ }
62
+
14
63
  async function init() {
15
64
  const platform = this;
65
+ detectOrphanedAccessories(platform);
16
66
  platform._clients = [];
17
67
 
18
68
  const manualDevices = (platform.devices || []).map(d => ({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-slwf-01pro",
3
3
  "description": "Homebridge plugin for the SMLIGHT SLWF-01Pro Wi-Fi dongle and other ESPHome Climate entities. Auto-discovery, multi-entity bundling, and full Midea-protocol AC support.",
4
- "version": "0.1.2",
4
+ "version": "0.2.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/nookied/homebridge-SLWF-01Pro.git"