@riddix/hamh 2.1.0-alpha.806 → 2.1.0-alpha.808
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/README.md
CHANGED
|
@@ -37,7 +37,7 @@ of port forwarding etc.
|
|
|
37
37
|
|
|
38
38
|
| Channel | Branch | Current Version | Description |
|
|
39
39
|
|---------|--------|-----------------|-------------|
|
|
40
|
-
| **Stable** | `main` | v2.0.
|
|
40
|
+
| **Stable** | `main` | v2.0.49 | Production-ready, recommended for most users |
|
|
41
41
|
| **Alpha** | `alpha` | v2.1.0-alpha.x (next) | Currently level with Stable; next pre-release lands here first |
|
|
42
42
|
| **Testing** | `testing` | v4.1.0-testing.x | ⚠️ **Highly unstable!** Experimental features, may break |
|
|
43
43
|
|
|
@@ -61,9 +61,24 @@ Re-assign the affected devices to their rooms after they reconnect. See the [doc
|
|
|
61
61
|
## 🎉 What's New
|
|
62
62
|
|
|
63
63
|
<details>
|
|
64
|
-
<summary><strong>📦 Stable Features (v2.0.
|
|
64
|
+
<summary><strong>📦 Stable Features (v2.0.49)</strong> - Click to expand</summary>
|
|
65
65
|
|
|
66
|
-
**New in v2.0.
|
|
66
|
+
**New in v2.0.49:**
|
|
67
|
+
|
|
68
|
+
- 🌀 **Fan speed restore**: speed is remembered across transactions and restarts, localized wind presets map through, Auto is gated on a real auto preset, and an opt-in restores speed on power-on ([#387](https://github.com/RiDDiX/home-assistant-matter-hub/issues/387))
|
|
69
|
+
- 📡 **Session recovery hardening**: subscription jitter dropped, superseded sessions of a reconnecting peer swept, stale sessions closed only after a real quiet period, plus opt-in fast recovery ([#386](https://github.com/RiDDiX/home-assistant-matter-hub/issues/386), [#400](https://github.com/RiDDiX/home-assistant-matter-hub/issues/400), [#398](https://github.com/RiDDiX/home-assistant-matter-hub/issues/398), [#287](https://github.com/RiDDiX/home-assistant-matter-hub/issues/287))
|
|
70
|
+
- 🩺 **Per-fabric controller health card** on the bridge page
|
|
71
|
+
- 🔢 **Endpoint number kept on mapping change** so Alexa no longer re-adds the device ([#404](https://github.com/RiDDiX/home-assistant-matter-hub/issues/404)), plus a **unique-id suffix** to shed stale controller records ([#385](https://github.com/RiDDiX/home-assistant-matter-hub/issues/385))
|
|
72
|
+
- 🔘 **`select` as an On/Off Switch** ([#356](https://github.com/RiDDiX/home-assistant-matter-hub/issues/356)), plus an **experimental mounted On/Off** control type ([#380](https://github.com/RiDDiX/home-assistant-matter-hub/issues/380))
|
|
73
|
+
- 🪟 **Tilt for `set_tilt_position`-only covers** ([#405](https://github.com/RiDDiX/home-assistant-matter-hub/issues/405)), and **tilt-only cover-as-light** uses the tilt channel ([#350](https://github.com/RiDDiX/home-assistant-matter-hub/issues/350))
|
|
74
|
+
- 🚨 **Warns on a non-5540 Alexa bridge** ([#401](https://github.com/RiDDiX/home-assistant-matter-hub/issues/401)) and on an **OTBR Thread mDNS interface** ([#388](https://github.com/RiDDiX/home-assistant-matter-hub/issues/388))
|
|
75
|
+
- 📷 **Camera plugin config scoped per bridge** ([#373](https://github.com/RiDDiX/home-assistant-matter-hub/issues/373))
|
|
76
|
+
- 🔌 **Clashing bridge port reassigned on load** ([#378](https://github.com/RiDDiX/home-assistant-matter-hub/issues/378))
|
|
77
|
+
- 🧩 **Composed sub-entities compose even outside the bridge filter** ([#408](https://github.com/RiDDiX/home-assistant-matter-hub/issues/408)), and **composed sensors list all device types** ([#214](https://github.com/RiDDiX/home-assistant-matter-hub/issues/214))
|
|
78
|
+
- 🔒 **Unbolt maps to `lock.unlock`** not open ([#397](https://github.com/RiDDiX/home-assistant-matter-hub/issues/397)), **level-to-brightness uses one scale** ([#402](https://github.com/RiDDiX/home-assistant-matter-hub/issues/402)), **button drops the Lighting feature** ([#182](https://github.com/RiDDiX/home-assistant-matter-hub/issues/182)), and **stale cooling/auto state is cleared** ([#384](https://github.com/RiDDiX/home-assistant-matter-hub/issues/384))
|
|
79
|
+
- 🌍 **Russian translations** added ([#409](https://github.com/RiDDiX/home-assistant-matter-hub/issues/409)) and **zh-TW completed**
|
|
80
|
+
|
|
81
|
+
**Previously in v2.0.48:**
|
|
67
82
|
|
|
68
83
|
- 🌡️ Cooling-only thermostats no longer drop and re-pair after a switch to cool; a leftover Heat setpoint limit was crashing init ([#381](https://github.com/RiDDiX/home-assistant-matter-hub/issues/381))
|
|
69
84
|
- 📝 The Settings update box now shows the full release notes instead of cutting them off
|
|
@@ -220,7 +235,7 @@ Re-assign the affected devices to their rooms after they reconnect. See the [doc
|
|
|
220
235
|
<details>
|
|
221
236
|
<summary><strong>🧪 Alpha Features (v2.1.0-alpha.x)</strong> - Click to expand</summary>
|
|
222
237
|
|
|
223
|
-
**Alpha is currently level with Stable (v2.0.
|
|
238
|
+
**Alpha is currently level with Stable (v2.0.49).** All alpha work up to the latest pre-release has been promoted into v2.0.49. New alpha work continues from the next pre-release tag onward and will appear here as development progresses.
|
|
224
239
|
|
|
225
240
|
</details>
|
|
226
241
|
|
|
@@ -498,7 +513,7 @@ Matter relies heavily on **mDNS (multicast DNS)** for device discovery and reach
|
|
|
498
513
|
- **Keep the path simple**: Avoid placing access points or managed switches between your Matter bridge (Home Assistant) and your Home Hub (HomePod/Apple TV)
|
|
499
514
|
- **Use wired connections** where possible for Home Hubs and the Home Assistant host
|
|
500
515
|
- **Same subnet**: All Matter devices, controllers, and the bridge must be on the same Layer 2 network / subnet
|
|
501
|
-
- **IPv6**: Matter requires IPv6, do not disable it. For VLAN setups, configure **ULA addresses** (`fd00::/8`), not just link-local (`fe80::`). See [Troubleshooting](https://home-assistant-matter-hub
|
|
516
|
+
- **IPv6**: Matter requires IPv6, do not disable it. For VLAN setups, configure **ULA addresses** (`fd00::/8`), not just link-local (`fe80::`). See [Troubleshooting](https://riddix.github.io/home-assistant-matter-hub/guides/connectivity-issues#ipv6) and [Discussion #39](https://github.com/RiDDiX/home-assistant-matter-hub/discussions/39)
|
|
502
517
|
|
|
503
518
|
</details>
|
|
504
519
|
|
package/dist/backend/cli.js
CHANGED
|
@@ -162514,6 +162514,9 @@ function createLegacyEndpointType(entity, mapping, areaName, options) {
|
|
|
162514
162514
|
const overrideFactory = matterDeviceTypeFactories[mapping.matterDeviceType];
|
|
162515
162515
|
if (overrideFactory) {
|
|
162516
162516
|
type = overrideFactory({ entity, customName, mapping });
|
|
162517
|
+
if (type && mapping.batteryEntity && !hasPowerSource(type)) {
|
|
162518
|
+
type = addPowerSource(type);
|
|
162519
|
+
}
|
|
162517
162520
|
}
|
|
162518
162521
|
}
|
|
162519
162522
|
if (!type) {
|
|
@@ -162564,6 +162567,16 @@ function addFixedLabel(type, areaName) {
|
|
|
162564
162567
|
behaviors: { ...type.behaviors, fixedLabel }
|
|
162565
162568
|
};
|
|
162566
162569
|
}
|
|
162570
|
+
function hasPowerSource(type) {
|
|
162571
|
+
return "powerSource" in type.behaviors;
|
|
162572
|
+
}
|
|
162573
|
+
function addPowerSource(type) {
|
|
162574
|
+
const mutable = type;
|
|
162575
|
+
if (typeof mutable.with === "function") {
|
|
162576
|
+
return mutable.with(DefaultPowerSourceServer);
|
|
162577
|
+
}
|
|
162578
|
+
return type;
|
|
162579
|
+
}
|
|
162567
162580
|
var deviceCtrs = {
|
|
162568
162581
|
light: LightDevice,
|
|
162569
162582
|
switch: SwitchDevice,
|
|
@@ -162680,6 +162693,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
162680
162693
|
mappedEntityIds;
|
|
162681
162694
|
subEndpoints = /* @__PURE__ */ new Map();
|
|
162682
162695
|
lastStates = /* @__PURE__ */ new Map();
|
|
162696
|
+
lastMappedStates = /* @__PURE__ */ new Map();
|
|
162683
162697
|
debouncedUpdates = /* @__PURE__ */ new Map();
|
|
162684
162698
|
static async create(config11) {
|
|
162685
162699
|
const { registry: registry2, primaryEntityId, composedEntities } = config11;
|
|
@@ -162698,14 +162712,32 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
162698
162712
|
})
|
|
162699
162713
|
);
|
|
162700
162714
|
}
|
|
162715
|
+
if (config11.mapping?.batteryEntity) {
|
|
162716
|
+
parentType = parentType.with(DefaultPowerSourceServer);
|
|
162717
|
+
}
|
|
162701
162718
|
const endpointId = createEndpointId5(primaryEntityId, config11.customName);
|
|
162702
162719
|
const parts = [];
|
|
162703
162720
|
const subEndpointMap = /* @__PURE__ */ new Map();
|
|
162704
162721
|
const mappedIds = [];
|
|
162722
|
+
if (config11.mapping?.batteryEntity) {
|
|
162723
|
+
mappedIds.push(config11.mapping.batteryEntity);
|
|
162724
|
+
}
|
|
162725
|
+
let primaryMapping = config11.mapping;
|
|
162726
|
+
let primarySubPayload = primaryPayload;
|
|
162727
|
+
if (config11.mapping?.batteryEntity) {
|
|
162728
|
+
primaryMapping = { ...config11.mapping, batteryEntity: void 0 };
|
|
162729
|
+
const attributes9 = { ...primaryPayload.state.attributes };
|
|
162730
|
+
delete attributes9.battery;
|
|
162731
|
+
delete attributes9.battery_level;
|
|
162732
|
+
primarySubPayload = {
|
|
162733
|
+
...primaryPayload,
|
|
162734
|
+
state: { ...primaryPayload.state, attributes: attributes9 }
|
|
162735
|
+
};
|
|
162736
|
+
}
|
|
162705
162737
|
const primaryType = createLegacyEndpointType(
|
|
162706
|
-
|
|
162707
|
-
|
|
162708
|
-
|
|
162738
|
+
primarySubPayload,
|
|
162739
|
+
primaryMapping,
|
|
162740
|
+
config11.areaName,
|
|
162709
162741
|
{ vacuumOnOff: registry2.isVacuumOnOffEnabled() }
|
|
162710
162742
|
);
|
|
162711
162743
|
if (!primaryType) {
|
|
@@ -162733,7 +162765,11 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
162733
162765
|
entityId: sub.entityId,
|
|
162734
162766
|
matterDeviceType: sub.matterDeviceType
|
|
162735
162767
|
};
|
|
162736
|
-
const subType = createLegacyEndpointType(
|
|
162768
|
+
const subType = createLegacyEndpointType(
|
|
162769
|
+
subPayload,
|
|
162770
|
+
subMapping,
|
|
162771
|
+
config11.areaName
|
|
162772
|
+
);
|
|
162737
162773
|
if (!subType) {
|
|
162738
162774
|
logger229.warn(
|
|
162739
162775
|
`Cannot create endpoint type for composed sub-entity ${sub.entityId}`
|
|
@@ -162782,12 +162818,29 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
162782
162818
|
this.mappedEntityIds = mappedEntityIds;
|
|
162783
162819
|
}
|
|
162784
162820
|
async updateStates(states) {
|
|
162785
|
-
this.
|
|
162821
|
+
const mappedChanged = this.hasMappedNonSubEntityChanged(states);
|
|
162822
|
+
this.scheduleUpdate(this, this.entityId, states, mappedChanged);
|
|
162786
162823
|
for (const [entityId, sub] of this.subEndpoints) {
|
|
162787
162824
|
this.scheduleUpdate(sub, entityId, states);
|
|
162788
162825
|
}
|
|
162789
162826
|
}
|
|
162790
|
-
|
|
162827
|
+
// A mapped entity without its own sub-endpoint (the battery) drives the parent
|
|
162828
|
+
// PowerSource, so track its state and report when it moves. Subs flush
|
|
162829
|
+
// themselves, so skip them here.
|
|
162830
|
+
hasMappedNonSubEntityChanged(states) {
|
|
162831
|
+
let changed = false;
|
|
162832
|
+
for (const mappedId of this.mappedEntityIds) {
|
|
162833
|
+
if (this.subEndpoints.has(mappedId)) continue;
|
|
162834
|
+
const mappedState = states[mappedId];
|
|
162835
|
+
if (!mappedState) continue;
|
|
162836
|
+
if (mappedState.state !== this.lastMappedStates.get(mappedId)) {
|
|
162837
|
+
this.lastMappedStates.set(mappedId, mappedState.state);
|
|
162838
|
+
changed = true;
|
|
162839
|
+
}
|
|
162840
|
+
}
|
|
162841
|
+
return changed;
|
|
162842
|
+
}
|
|
162843
|
+
scheduleUpdate(endpoint, entityId, states, force = false) {
|
|
162791
162844
|
const state = states[entityId];
|
|
162792
162845
|
if (!state) return;
|
|
162793
162846
|
const key = endpoint === this ? `_parent_:${entityId}` : entityId;
|
|
@@ -162795,8 +162848,9 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
162795
162848
|
s: state.state,
|
|
162796
162849
|
a: state.attributes
|
|
162797
162850
|
});
|
|
162798
|
-
if (this.lastStates.get(key) === stateJson) return;
|
|
162851
|
+
if (!force && this.lastStates.get(key) === stateJson) return;
|
|
162799
162852
|
this.lastStates.set(key, stateJson);
|
|
162853
|
+
const effectiveState = force ? { ...state, last_updated: (/* @__PURE__ */ new Date()).toISOString() } : state;
|
|
162800
162854
|
let debouncedFn = this.debouncedUpdates.get(key);
|
|
162801
162855
|
if (!debouncedFn) {
|
|
162802
162856
|
debouncedFn = debounce5(
|
|
@@ -162805,7 +162859,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
162805
162859
|
);
|
|
162806
162860
|
this.debouncedUpdates.set(key, debouncedFn);
|
|
162807
162861
|
}
|
|
162808
|
-
debouncedFn(endpoint,
|
|
162862
|
+
debouncedFn(endpoint, effectiveState);
|
|
162809
162863
|
}
|
|
162810
162864
|
async flushUpdate(endpoint, state) {
|
|
162811
162865
|
try {
|