@riddix/hamh 2.1.0-alpha.574 → 2.1.0-alpha.576

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.30 | Production-ready, recommended for most users |
40
+ | **Stable** | `main` | v2.0.36 | Production-ready, recommended for most users |
41
41
  | **Alpha** | `alpha` | v2.1.0-alpha.x | Pre-release with new features, for early adopters |
42
42
  | **Testing** | `testing` | v4.1.0-testing.x | ⚠️ **Highly unstable!** Experimental features, may break |
43
43
 
@@ -52,30 +52,39 @@ of port forwarding etc.
52
52
  ## 🎉 What's New
53
53
 
54
54
  <details>
55
- <summary><strong>📦 Stable Features (v2.0.30)</strong> - Click to expand</summary>
55
+ <summary><strong>📦 Stable Features (v2.0.36)</strong> - Click to expand</summary>
56
56
 
57
- **New in v2.0.30:**
57
+ **New in v2.0.36:**
58
58
 
59
59
  | Feature | Description |
60
60
  |---------|-------------|
61
- | **� Mapped Entity Propagation Fix** | Propagate mapped entity changes (battery, humidity, etc.) to Matter endpoints — fixes stale sensor readings |
62
- | **🖥️ API Error Surfacing** | Surface API errors instead of silently swallowing them ([#232](https://github.com/RiDDiX/home-assistant-matter-hub/issues/232)) |
63
-
64
- **Previously in v2.0.29:**
61
+ | **🏗️ User-Defined Composed Devices** | Create custom composed devices via composedEntities mapping ([#220](https://github.com/RiDDiX/home-assistant-matter-hub/issues/220)) |
62
+ | **🔌 Plugin Domain Mappings** | Domain mapping support in plugin API with cloud-mock example |
63
+ | **🔋 Valve & Pump Battery** | Battery support for valve and pump endpoints |
64
+ | **🌐 German + Russian Translations** | Complete German translation and new Russian language |
65
+ | **📡 Session Recovery** | Graceful session close, dead session cleanup, mDNS re-announcement ([#266](https://github.com/RiDDiX/home-assistant-matter-hub/issues/266)) |
66
+ | **🔗 Quick Link to Failed Devices** | Dashboard quick link to failed devices ([#270](https://github.com/RiDDiX/home-assistant-matter-hub/issues/270)) |
67
+ | **🌡️ Thermostat Fix** | Skip climate.turn_on when already on ([#269](https://github.com/RiDDiX/home-assistant-matter-hub/issues/269)) |
68
+ | **🪟 Cover Fix** | Correct stale targetPosition during external movement ([#268](https://github.com/RiDDiX/home-assistant-matter-hub/issues/268)) |
69
+ | **🌬️ Air Purifier Fix** | Sub-endpoints for composed air purifier, manual temp/humidity mapping ([#265](https://github.com/RiDDiX/home-assistant-matter-hub/issues/265)) |
70
+ | **🔥 Cooling-Only Thermostat Fix** | Prevent HeatingOnly on cooling-only thermostat ([#264](https://github.com/RiDDiX/home-assistant-matter-hub/issues/264)) |
71
+ | **↔️ Per-Entity Cover Swap** | Individual coverSwapOpenClose per cover ([#263](https://github.com/RiDDiX/home-assistant-matter-hub/issues/263)) |
72
+
73
+ **Previously in v2.0.35:**
65
74
 
66
75
  | Feature | Description |
67
76
  |---------|-------------|
68
- | **� Light currentLevel Fix** | Retain light currentLevel when off to prevent Apple Home 100% brightness on turn-on ([#225](https://github.com/RiDDiX/home-assistant-matter-hub/issues/225)) |
69
- | **�️ Bridge Config Save Fix** | Decouple save button from RJSF schema validation errors ([#232](https://github.com/RiDDiX/home-assistant-matter-hub/issues/232)) |
70
- | **🌀 Fan Device Feature Fix** | Correct FanDeviceFeature TURN_ON/TURN_OFF enum values to match Home Assistant |
71
- | **🌡️ Humidity Auto-Mapping Fix** | Correct autoHumidityMapping schema default to match runtime behavior |
77
+ | **🏠 HA 2026.3 Clean Area Support** | Native support for the new `vacuum.clean_area` action |
78
+ | **🤖 Valetudo Identifier Mapping** | Custom `valetudoIdentifier` for MQTT topic case mismatches |
79
+ | **🔌 Plugin System Hardening** | Validation, API version check, tgz upload/local install |
80
+ | **📖 Docusaurus Docs** | New documentation site with improved search and navigation |
72
81
 
73
82
  </details>
74
83
 
75
84
  <details>
76
85
  <summary><strong>🧪 Alpha Features (v2.1.0-alpha.x)</strong> - Click to expand</summary>
77
86
 
78
- **Alpha is currently in sync with Stable (v2.0.30).** All alpha features have been promoted to stable. New alpha features will appear here as development continues.
87
+ **Alpha is currently in sync with Stable (v2.0.36).** All alpha features have been promoted to stable. New alpha features will appear here as development continues.
79
88
 
80
89
  </details>
81
90
 
@@ -101,6 +110,24 @@ of port forwarding etc.
101
110
  <details>
102
111
  <summary><strong>📜 Previous Stable Versions</strong> - Click to expand</summary>
103
112
 
113
+ ### v2.0.35
114
+ HA 2026.3 Clean Area Support, Valetudo Identifier Mapping, Plugin System Hardening, Registry Fingerprint Fix, Roomba Battery Fix, Contact Sensor Fix, Script Momentary Fix, Docusaurus Docs
115
+
116
+ ### v2.0.34
117
+ Automatic Backup, Vacuum Battery Auto-Map, Deprecated Feature Flags Fix
118
+
119
+ ### v2.0.33
120
+ Endpoint Number Preservation, Binary Sensor Battery Auto-Map
121
+
122
+ ### v2.0.32
123
+ Multi-Language Support, Plugin System, New Device Types (PIR, Rain, Electrical, AQ Sensors), Cluster Diagnostics, Dashboard Enhancements, Mapping Profile Export/Import, Fan & Air Purifier Fixes, Stale Session Cleanup, KNX Cover Fix
124
+
125
+ ### v2.0.31
126
+ Controller Profiles & Area Setup, Fan Speed/Preset Fix, Optimistic State Fix, Cover Target Fix, Humidity Auto-Mapping Default
127
+
128
+ ### v2.0.30
129
+ Mapped Entity Propagation Fix, API Error Surfacing
130
+
104
131
  ### v2.0.29
105
132
  Light currentLevel Fix, Bridge Config Save Fix, Fan Device Feature Fix, Humidity Auto-Mapping Fix
106
133
 
@@ -441,7 +468,7 @@ Thank you to everyone who helps improve this project by reporting issues!
441
468
  | 💎 StefanS | 💎 Manny B. | 💎 Bonjon |
442
469
  | 💎 TobiR | 💎 Franz Huber | 💎 Michele Larese de Prata |
443
470
  | 💎 [@CNCB](https://github.com/CNCB) | 💎 [@pelican1997](https://github.com/pelican1997) | 💎 [@PeJanNL](https://github.com/PeJanNL) |
444
- | 💎 [@bra1nbuster](https://github.com/bra1nbuster) | | |
471
+ | 💎 [@bra1nbuster](https://github.com/bra1nbuster) | 💎 [@knuti1960](https://github.com/knuti1960) | |
445
472
 
446
473
  🙏 *...and anonymous supporters who prefer not to be named.*
447
474
 
@@ -175948,21 +175948,21 @@ var ROOM_MODE_BASE = 100;
175948
175948
  function isRoomMode(mode) {
175949
175949
  return mode >= ROOM_MODE_BASE;
175950
175950
  }
175951
+ var cleaningSessions = /* @__PURE__ */ new WeakMap();
175952
+ function getSession(agent) {
175953
+ let session = cleaningSessions.get(agent);
175954
+ if (!session) {
175955
+ session = {
175956
+ completedAreas: /* @__PURE__ */ new Set(),
175957
+ lastCurrentArea: null,
175958
+ activeAreas: [],
175959
+ loggedShortCircuits: /* @__PURE__ */ new Set()
175960
+ };
175961
+ cleaningSessions.set(agent, session);
175962
+ }
175963
+ return session;
175964
+ }
175951
175965
  var RvcRunModeServerBase = class extends RvcRunModeServer {
175952
- /** Areas that the vacuum has already finished cleaning in this session */
175953
- completedAreas = /* @__PURE__ */ new Set();
175954
- /** Last known currentArea — used to detect room transitions */
175955
- lastCurrentArea = null;
175956
- /** Snapshot of selectedAreas taken when cleaning starts.
175957
- * The start handler clears serviceArea.state.selectedAreas after
175958
- * dispatching the HA action to prevent re-dispatch, but progress
175959
- * tracking needs the original list for the entire cleaning session. */
175960
- activeAreas = [];
175961
- /** Diagnostic short-circuit reasons already logged this session.
175962
- * updateCurrentRoomFromSensor() is called on every HA state event;
175963
- * without this guard a failing path would flood the log. Cleared
175964
- * when the vacuum returns to Idle. */
175965
- loggedShortCircuits = /* @__PURE__ */ new Set();
175966
175966
  async initialize() {
175967
175967
  await super.initialize();
175968
175968
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
@@ -175973,6 +175973,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
175973
175973
  if (!entity.state || !entity.state.attributes) {
175974
175974
  return;
175975
175975
  }
175976
+ const s = getSession(this.agent);
175976
175977
  const previousMode = this.state.currentMode;
175977
175978
  const newMode = this.state.config.getCurrentMode(entity.state, this.agent);
175978
175979
  applyPatchState(
@@ -175989,12 +175990,12 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
175989
175990
  if (previousMode !== newMode) {
175990
175991
  if (newMode === 0 /* Idle */) {
175991
175992
  this.trySetCurrentArea(null);
175992
- this.completedAreas.clear();
175993
- this.lastCurrentArea = null;
175994
- this.loggedShortCircuits.clear();
175993
+ s.completedAreas.clear();
175994
+ s.lastCurrentArea = null;
175995
+ s.loggedShortCircuits.clear();
175995
175996
  } else if (newMode === 1 /* Cleaning */) {
175996
- if (this.activeAreas.length > 0 && this.lastCurrentArea === null) {
175997
- this.trySetCurrentArea(this.activeAreas[0]);
175997
+ if (s.activeAreas.length > 0 && s.lastCurrentArea === null) {
175998
+ this.trySetCurrentArea(s.activeAreas[0]);
175998
175999
  }
175999
176000
  }
176000
176001
  }
@@ -176008,8 +176009,9 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176008
176009
  * surfacing the silent paths that would otherwise be invisible.
176009
176010
  */
176010
176011
  logShortCircuitOnce(reason, message) {
176011
- if (this.loggedShortCircuits.has(reason)) return;
176012
- this.loggedShortCircuits.add(reason);
176012
+ const s = getSession(this.agent);
176013
+ if (s.loggedShortCircuits.has(reason)) return;
176014
+ s.loggedShortCircuits.add(reason);
176013
176015
  logger189.info(message);
176014
176016
  }
176015
176017
  /**
@@ -176018,6 +176020,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176018
176020
  */
176019
176021
  updateCurrentRoomFromSensor() {
176020
176022
  try {
176023
+ const s = getSession(this.agent);
176021
176024
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
176022
176025
  const currentRoomEntityId = homeAssistant.state.mapping?.currentRoomEntity;
176023
176026
  if (!currentRoomEntityId) {
@@ -176036,7 +176039,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176036
176039
  );
176037
176040
  return;
176038
176041
  }
176039
- if (this.activeAreas.length === 0) {
176042
+ if (s.activeAreas.length === 0) {
176040
176043
  this.logShortCircuitOnce(
176041
176044
  "no-active-areas",
176042
176045
  `currentRoom sensor: activeAreas empty while cleaning \u2014 sensor=${currentRoomEntityId} state="${roomState.state}"`
@@ -176049,13 +176052,13 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176049
176052
  const roomName = roomState.state;
176050
176053
  let matchedAreaId = null;
176051
176054
  if (segmentId != null) {
176052
- if (this.activeAreas.includes(segmentId)) {
176055
+ if (s.activeAreas.includes(segmentId)) {
176053
176056
  matchedAreaId = segmentId;
176054
176057
  }
176055
176058
  }
176056
176059
  if (matchedAreaId === null && segmentId != null) {
176057
176060
  for (const area of serviceArea.state.supportedAreas) {
176058
- if (this.activeAreas.includes(area.areaId) && area.areaId % 1e4 === segmentId) {
176061
+ if (s.activeAreas.includes(area.areaId) && area.areaId % 1e4 === segmentId) {
176059
176062
  matchedAreaId = area.areaId;
176060
176063
  break;
176061
176064
  }
@@ -176065,23 +176068,23 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176065
176068
  const area = serviceArea.state.supportedAreas.find(
176066
176069
  (a) => a.areaInfo.locationInfo?.locationName?.toLowerCase() === roomName.toLowerCase()
176067
176070
  );
176068
- if (area && this.activeAreas.includes(area.areaId)) {
176071
+ if (area && s.activeAreas.includes(area.areaId)) {
176069
176072
  matchedAreaId = area.areaId;
176070
176073
  }
176071
176074
  }
176072
176075
  if (matchedAreaId === null) {
176073
176076
  logger189.info(
176074
- `currentRoom sensor: no match for "${roomName}" (segmentId=${segmentId}), activeAreas=[${this.activeAreas.join(", ")}], supportedAreas=[${serviceArea.state.supportedAreas.map((a) => `${a.areaId}:${a.areaInfo.locationInfo?.locationName}`).join(", ")}]`
176077
+ `currentRoom sensor: no match for "${roomName}" (segmentId=${segmentId}), activeAreas=[${s.activeAreas.join(", ")}], supportedAreas=[${serviceArea.state.supportedAreas.map((a) => `${a.areaId}:${a.areaInfo.locationInfo?.locationName}`).join(", ")}]`
176075
176078
  );
176076
176079
  return;
176077
176080
  }
176078
- if (matchedAreaId === this.lastCurrentArea) return;
176079
- if (this.lastCurrentArea !== null) {
176080
- this.completedAreas.add(this.lastCurrentArea);
176081
+ if (matchedAreaId === s.lastCurrentArea) return;
176082
+ if (s.lastCurrentArea !== null) {
176083
+ s.completedAreas.add(s.lastCurrentArea);
176081
176084
  }
176082
- this.lastCurrentArea = matchedAreaId;
176085
+ s.lastCurrentArea = matchedAreaId;
176083
176086
  logger189.info(
176084
- `currentRoom sensor: transition to area ${matchedAreaId} ("${roomName}"), completed: [${[...this.completedAreas].join(", ")}]`
176087
+ `currentRoom sensor: transition to area ${matchedAreaId} ("${roomName}"), completed: [${[...s.completedAreas].join(", ")}]`
176085
176088
  );
176086
176089
  this.trySetCurrentArea(matchedAreaId);
176087
176090
  } catch (e) {
@@ -176118,17 +176121,18 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176118
176121
  * matter.js property getters during transaction pre-commit.
176119
176122
  */
176120
176123
  updateProgress(serviceArea, areaId) {
176121
- if (this.activeAreas.length === 0) return;
176124
+ const s = getSession(this.agent);
176125
+ if (s.activeAreas.length === 0) return;
176122
176126
  const state = serviceArea.state;
176123
176127
  if (areaId === null) {
176124
- state.progress = this.activeAreas.map((id) => ({
176128
+ state.progress = s.activeAreas.map((id) => ({
176125
176129
  areaId: id,
176126
176130
  status: ServiceArea3.OperationalStatus.Completed
176127
176131
  }));
176128
176132
  } else {
176129
- state.progress = this.activeAreas.map((id) => ({
176133
+ state.progress = s.activeAreas.map((id) => ({
176130
176134
  areaId: id,
176131
- status: id === areaId ? ServiceArea3.OperationalStatus.Operating : this.completedAreas.has(id) ? ServiceArea3.OperationalStatus.Completed : ServiceArea3.OperationalStatus.Pending
176135
+ status: id === areaId ? ServiceArea3.OperationalStatus.Operating : s.completedAreas.has(id) ? ServiceArea3.OperationalStatus.Completed : ServiceArea3.OperationalStatus.Pending
176132
176136
  }));
176133
176137
  }
176134
176138
  }
@@ -176150,6 +176154,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176150
176154
  }
176151
176155
  }
176152
176156
  changeToMode(request) {
176157
+ const s = getSession(this.agent);
176153
176158
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
176154
176159
  const { newMode } = request;
176155
176160
  if (newMode !== this.state.currentMode && !this.state.supportedModes.some((m) => m.mode === newMode)) {
@@ -176162,8 +176167,8 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176162
176167
  try {
176163
176168
  const serviceArea = this.agent.get(ServiceAreaBehavior);
176164
176169
  if (serviceArea.state.selectedAreas?.length > 0) {
176165
- this.activeAreas = [...serviceArea.state.selectedAreas];
176166
- this.trySetCurrentArea(this.activeAreas[0]);
176170
+ s.activeAreas = [...serviceArea.state.selectedAreas];
176171
+ this.trySetCurrentArea(s.activeAreas[0]);
176167
176172
  homeAssistant.callAction(this.state.config.start(void 0, this.agent));
176168
176173
  this.state.currentMode = newMode;
176169
176174
  return {
@@ -176175,7 +176180,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176175
176180
  }
176176
176181
  if (this.state.config.cleanRoom) {
176177
176182
  const areaId = this.findAreaIdForMode(newMode);
176178
- this.activeAreas = areaId !== null ? [areaId] : [];
176183
+ s.activeAreas = areaId !== null ? [areaId] : [];
176179
176184
  this.trySetCurrentArea(areaId);
176180
176185
  homeAssistant.callAction(
176181
176186
  this.state.config.cleanRoom(newMode, this.agent)
@@ -176192,8 +176197,8 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176192
176197
  try {
176193
176198
  const serviceArea = this.agent.get(ServiceAreaBehavior);
176194
176199
  if (serviceArea.state.selectedAreas?.length > 0) {
176195
- this.activeAreas = [...serviceArea.state.selectedAreas];
176196
- this.trySetCurrentArea(this.activeAreas[0]);
176200
+ s.activeAreas = [...serviceArea.state.selectedAreas];
176201
+ this.trySetCurrentArea(s.activeAreas[0]);
176197
176202
  }
176198
176203
  } catch {
176199
176204
  }
@@ -176202,9 +176207,9 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176202
176207
  }
176203
176208
  case 0 /* Idle */:
176204
176209
  this.trySetCurrentArea(null);
176205
- this.completedAreas.clear();
176206
- this.lastCurrentArea = null;
176207
- this.activeAreas = [];
176210
+ s.completedAreas.clear();
176211
+ s.lastCurrentArea = null;
176212
+ s.activeAreas = [];
176208
176213
  homeAssistant.callAction(
176209
176214
  this.state.config.returnToBase(void 0, this.agent)
176210
176215
  );