@riddix/hamh 2.1.0-alpha.709 → 2.1.0-alpha.711

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
@@ -56,22 +56,22 @@ of port forwarding etc.
56
56
 
57
57
  **New in v2.0.46:**
58
58
 
59
- - ❄️ Opt-in **companion fan** for climate ACs a per-entity toggle exposes the AC's fan as its own Matter fan endpoint, the setting is persisted, and fan-speed presets are now ordered low→high ([#309](https://github.com/RiDDiX/home-assistant-matter-hub/issues/309))
60
- - 🌦️ **Weather domain support** `weather.*` entities are exposed as a composed Temperature + Humidity + Pressure sensor read from the entity's attributes (pressure converted to hPa, shown on Google Home)
61
- - 🤖 **Vacuum service-area editing** edit area data inline in Entity Mapping and dispatch room cleaning in batches, plus a batch-room-data fix ([#291](https://github.com/RiDDiX/home-assistant-matter-hub/issues/291))
62
- - 🔒 **Door Lock credential hardening** safer access-code handling and fabric-index casting on the lock cluster ([#313](https://github.com/RiDDiX/home-assistant-matter-hub/issues/313))
63
- - ⚡ **Skip unchanged endpoints on HA updates** only endpoints whose entity or a mapped sub-entity actually changed are refreshed, so CPU no longer scales with entity count × event rate ([#351](https://github.com/RiDDiX/home-assistant-matter-hub/issues/351))
64
- - 🔌 **Registry stays resilient when HA drops** an initial reload failure no longer puts the add-on in a restart loop on a flaky HA boot, and a mid-flight "Connection lost" retries once ([#352](https://github.com/RiDDiX/home-assistant-matter-hub/issues/352))
59
+ - ❄️ Opt-in **companion fan** for climate ACs: a per-entity toggle exposes the AC's fan as its own Matter fan endpoint, the setting is persisted, and fan-speed presets are now ordered low→high ([#309](https://github.com/RiDDiX/home-assistant-matter-hub/issues/309))
60
+ - 🌦️ **Weather domain support**: `weather.*` entities are exposed as a composed Temperature + Humidity + Pressure sensor read from the entity's attributes (pressure converted to hPa, shown on Google Home)
61
+ - 🤖 **Vacuum service-area editing**: edit area data inline in Entity Mapping and dispatch room cleaning in batches, plus a batch-room-data fix ([#291](https://github.com/RiDDiX/home-assistant-matter-hub/issues/291))
62
+ - 🔒 **Door Lock credential hardening**: safer access-code handling and fabric-index casting on the lock cluster ([#313](https://github.com/RiDDiX/home-assistant-matter-hub/issues/313))
63
+ - ⚡ **Skip unchanged endpoints on HA updates**: only endpoints whose entity or a mapped sub-entity actually changed are refreshed, so CPU no longer scales with entity count × event rate ([#351](https://github.com/RiDDiX/home-assistant-matter-hub/issues/351))
64
+ - 🔌 **Registry stays resilient when HA drops**: an initial reload failure no longer puts the add-on in a restart loop on a flaky HA boot, and a mid-flight "Connection lost" retries once ([#352](https://github.com/RiDDiX/home-assistant-matter-hub/issues/352))
65
65
  - 🔁 **RVC sessions refreshed safely** so vacuum reactors don't go stale ([#287](https://github.com/RiDDiX/home-assistant-matter-hub/issues/287))
66
66
  - 🪟 **Tilt-only covers** use the tilt channel for lift commands ([#350](https://github.com/RiDDiX/home-assistant-matter-hub/issues/350))
67
67
  - 🔋 **Battery auto-mapping narrowed** to avoid false matches, plus support for enum battery states ([#359](https://github.com/RiDDiX/home-assistant-matter-hub/issues/359))
68
- - 🔘 **`automation` entities are momentary** turning one on triggers it and snaps back to off ([#364](https://github.com/RiDDiX/home-assistant-matter-hub/issues/364))
68
+ - 🔘 **`automation` entities are momentary**: turning one on triggers it and snaps back to off ([#364](https://github.com/RiDDiX/home-assistant-matter-hub/issues/364))
69
69
  - 🌀 **Climate swing-mode handling fix**
70
- - 🚨 **Non-5540 Alexa bridge warning** a bridge on any other port now warns, since Alexa only pairs on port 5540
71
- - 🧵 **matter.js 0.17.0** upgraded from 0.16.11; the local LG-TV NOC-serial patch is dropped because upstream now tolerates 21-octet operational cert serials ([#305](https://github.com/RiDDiX/home-assistant-matter-hub/issues/305))
72
- - 🧰 Build/runtime fixes `bun:sqlite` `constants` export stubbed so the esbuild bundle builds against matter.js 0.17.0, add-on heap flag preserved ([#358](https://github.com/RiDDiX/home-assistant-matter-hub/issues/358))
70
+ - 🚨 **Non-5540 Alexa bridge warning**: a bridge on any other port now warns, since Alexa only pairs on port 5540
71
+ - 🧵 **matter.js 0.17.0**: upgraded from 0.16.11; the local LG-TV NOC-serial patch is dropped because upstream now tolerates 21-octet operational cert serials ([#305](https://github.com/RiDDiX/home-assistant-matter-hub/issues/305))
72
+ - 🧰 Build/runtime fixes: `bun:sqlite` `constants` export stubbed so the esbuild bundle builds against matter.js 0.17.0, add-on heap flag preserved ([#358](https://github.com/RiDDiX/home-assistant-matter-hub/issues/358))
73
73
  - ⬆️ Dependency vulnerabilities resolved
74
- - 📝 Docs `hvac_action` requirement for the Auto running-state display ([#309](https://github.com/RiDDiX/home-assistant-matter-hub/issues/309)), Google Home ModeSelect label gap ([#356](https://github.com/RiDDiX/home-assistant-matter-hub/issues/356)), Alexa cover-routine limitation ([#312](https://github.com/RiDDiX/home-assistant-matter-hub/issues/312)), and the new weather domain
74
+ - 📝 Docs: `hvac_action` requirement for the Auto running-state display ([#309](https://github.com/RiDDiX/home-assistant-matter-hub/issues/309)), Google Home ModeSelect label gap ([#356](https://github.com/RiDDiX/home-assistant-matter-hub/issues/356)), Alexa cover-routine limitation ([#312](https://github.com/RiDDiX/home-assistant-matter-hub/issues/312)), and the new weather domain
75
75
 
76
76
  **Previously in v2.0.45 (hotfix release):**
77
77
 
@@ -79,12 +79,12 @@ of port forwarding etc.
79
79
 
80
80
  **Previously in v2.0.44:**
81
81
 
82
- - 🪟 Cover reliability overhaul Matter state/target/current reports split and correctly ordered, deferred target writes de-duplicated, legacy position attributes dropped from updates, cluster profile aligned with the certified Eve blind, current position held during external motion ([#328](https://github.com/RiDDiX/home-assistant-matter-hub/issues/328))
82
+ - 🪟 Cover reliability overhaul: Matter state/target/current reports split and correctly ordered, deferred target writes de-duplicated, legacy position attributes dropped from updates, cluster profile aligned with the certified Eve blind, current position held during external motion ([#328](https://github.com/RiDDiX/home-assistant-matter-hub/issues/328))
83
83
  - 🎚️ Per-bridge and per-entity cover slider debounce, window widened to 300 ms for smoother slider control ([#331](https://github.com/RiDDiX/home-assistant-matter-hub/issues/331))
84
84
  - 🤖 Vacuum service-area handling: `customServiceAreas` preserved in dynamic `RvcRunMode` supported modes, custom areas dispatched sequentially, `currentArea` cleared on dock return and no longer inherited stale across restarts, `observedCleaning` set on every cleaning event ([#335](https://github.com/RiDDiX/home-assistant-matter-hub/issues/335))
85
85
  - 🔋 Docked vacuum stops reporting charging once the battery is full ([#334](https://github.com/RiDDiX/home-assistant-matter-hub/issues/334))
86
86
  - ❄️ Per-entity `climateKeepModeOnIdle` for off+idle ACs; mode kept through a cool→off transition, freeze applied immediately on off and cleared on `action=off` ([#340](https://github.com/RiDDiX/home-assistant-matter-hub/issues/340))
87
- - 🔁 Matter session rotation opt-in per-bridge setting, aged sessions rotated, RVC clean-mode reactor goes offline correctly, `pushKeepalive` guarded on construction ([#287](https://github.com/RiDDiX/home-assistant-matter-hub/issues/287))
87
+ - 🔁 Matter session rotation: opt-in per-bridge setting, aged sessions rotated, RVC clean-mode reactor goes offline correctly, `pushKeepalive` guarded on construction ([#287](https://github.com/RiDDiX/home-assistant-matter-hub/issues/287))
88
88
  - 🧠 Heap-headroom and force-sync pressure guard to reduce memory pressure ([#347](https://github.com/RiDDiX/home-assistant-matter-hub/issues/347))
89
89
  - 🏷️ Per-entity `customVendorId` with Home Assistant device-registry serial fallback ([#290](https://github.com/RiDDiX/home-assistant-matter-hub/issues/290))
90
90
  - 🔢 `serialNumberSuffix` now loads when editing a bridge and is preserved when the serial is trimmed to 32 characters ([#330](https://github.com/RiDDiX/home-assistant-matter-hub/issues/330))
@@ -97,7 +97,7 @@ of port forwarding etc.
97
97
  - 🧩 JSON editor de-duplicates `@codemirror/state` ([#345](https://github.com/RiDDiX/home-assistant-matter-hub/issues/345))
98
98
  - 🌍 Polish translation update, credited to [@MStankiewiczOfficial](https://github.com/MStankiewiczOfficial) ([#329](https://github.com/RiDDiX/home-assistant-matter-hub/pull/329))
99
99
  - ✅ Added regression test coverage for the session-max-age parser ([#287](https://github.com/RiDDiX/home-assistant-matter-hub/issues/287))
100
- - ⬆️ Dependency hygiene transitive deps flagged by Dependabot patched, `serialize-javascript` bumped to 7.0.5 in docs-site
100
+ - ⬆️ Dependency hygiene: transitive deps flagged by Dependabot patched, `serialize-javascript` bumped to 7.0.5 in docs-site
101
101
 
102
102
  **Previously in v2.0.43:**
103
103
 
@@ -124137,7 +124137,7 @@ var init_bridge_config_schema = __esm({
124137
124137
  },
124138
124138
  coverSliderDebounceMs: {
124139
124139
  title: "Cover Slider Debounce (ms)",
124140
- description: "Override the cover position-update debounce window for this bridge. Some controllers (Apple Home) stream slider updates while the user is still dragging, causing covers to start moving toward an intermediate target. Set to the time the bridge should wait after the last update before sending the final value to Home Assistant. 0 keeps the built-in two-phase debounce (400 ms initial / 150 ms subsequent), which fits most controllers. Try 800\u20131500 ms for slow blinds. A per-entity override on a single cover wins over this flag.",
124140
+ description: "Override the cover position-update debounce window for this bridge. Some controllers (Apple Home) stream slider updates while the user is still dragging, causing covers to start moving toward an intermediate target. Set to the time the bridge should wait after the last update before sending the final value to Home Assistant. 0 keeps the built-in two-phase debounce (400 ms initial / 150 ms subsequent), which fits most controllers. Try 800-1500 ms for slow blinds. A per-entity override on a single cover wins over this flag.",
124141
124141
  type: "number",
124142
124142
  minimum: 0,
124143
124143
  maximum: 5e3,
@@ -125176,7 +125176,8 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
125176
125176
  req.file.buffer
125177
125177
  );
125178
125178
  const existingIds = new Set(bridgeStorage.bridges.map((b) => b.id));
125179
- const bridgesToRestore = options.bridgeIds ? backupData.bridges.filter((b) => options.bridgeIds.includes(b.id)) : backupData.bridges;
125179
+ const bridgeIds = options.bridgeIds;
125180
+ const bridgesToRestore = bridgeIds ? backupData.bridges.filter((b) => bridgeIds.includes(b.id)) : backupData.bridges;
125180
125181
  let bridgesRestored = 0;
125181
125182
  let bridgesSkipped = 0;
125182
125183
  let mappingsRestored = 0;
@@ -125220,6 +125221,7 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
125220
125221
  coverSliderDebounceMs: config11.coverSliderDebounceMs,
125221
125222
  disableClimateOnOff: config11.disableClimateOnOff,
125222
125223
  disableClimateFanControl: config11.disableClimateFanControl,
125224
+ climateAutoMode: config11.climateAutoMode,
125223
125225
  customServiceAreas: config11.customServiceAreas,
125224
125226
  customFanSpeedTags: config11.customFanSpeedTags,
125225
125227
  composedEntities: config11.composedEntities
@@ -125324,7 +125326,8 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
125324
125326
  const options = req.body || {};
125325
125327
  const { backupData, zipDirectory } = await extractBackupData(buffer);
125326
125328
  const existingIds = new Set(bridgeStorage.bridges.map((b) => b.id));
125327
- const bridgesToRestore = options.bridgeIds ? backupData.bridges.filter((b) => options.bridgeIds.includes(b.id)) : backupData.bridges;
125329
+ const bridgeIds = options.bridgeIds;
125330
+ const bridgesToRestore = bridgeIds ? backupData.bridges.filter((b) => bridgeIds.includes(b.id)) : backupData.bridges;
125328
125331
  let bridgesRestored = 0;
125329
125332
  let bridgesSkipped = 0;
125330
125333
  let mappingsRestored = 0;
@@ -125368,6 +125371,7 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
125368
125371
  coverSliderDebounceMs: config11.coverSliderDebounceMs,
125369
125372
  disableClimateOnOff: config11.disableClimateOnOff,
125370
125373
  disableClimateFanControl: config11.disableClimateFanControl,
125374
+ climateAutoMode: config11.climateAutoMode,
125371
125375
  customServiceAreas: config11.customServiceAreas,
125372
125376
  customFanSpeedTags: config11.customFanSpeedTags,
125373
125377
  composedEntities: config11.composedEntities
@@ -126211,6 +126215,7 @@ function entityMappingApi(mappingStorage) {
126211
126215
  disableClimateFanControl: body.disableClimateFanControl,
126212
126216
  climateKeepModeOnIdle: body.climateKeepModeOnIdle,
126213
126217
  climateExposeFan: body.climateExposeFan,
126218
+ climateAutoMode: body.climateAutoMode,
126214
126219
  composedEntities: body.composedEntities
126215
126220
  };
126216
126221
  const config11 = await mappingStorage.setMapping(request);
@@ -126678,7 +126683,8 @@ function configToProfileEntry(config11) {
126678
126683
  disableClimateOnOff: config11.disableClimateOnOff,
126679
126684
  disableClimateFanControl: config11.disableClimateFanControl,
126680
126685
  climateKeepModeOnIdle: config11.climateKeepModeOnIdle,
126681
- climateExposeFan: config11.climateExposeFan
126686
+ climateExposeFan: config11.climateExposeFan,
126687
+ climateAutoMode: config11.climateAutoMode
126682
126688
  };
126683
126689
  }
126684
126690
  function mappingProfileApi(mappingStorage) {
@@ -126804,7 +126810,8 @@ function mappingProfileApi(mappingStorage) {
126804
126810
  disableClimateOnOff: entry.disableClimateOnOff,
126805
126811
  disableClimateFanControl: entry.disableClimateFanControl,
126806
126812
  climateKeepModeOnIdle: entry.climateKeepModeOnIdle,
126807
- climateExposeFan: entry.climateExposeFan
126813
+ climateExposeFan: entry.climateExposeFan,
126814
+ climateAutoMode: entry.climateAutoMode
126808
126815
  });
126809
126816
  applied++;
126810
126817
  } catch (e) {
@@ -130741,9 +130748,10 @@ var EntityMappingStorage = class extends Service {
130741
130748
  disableClimateFanControl: request.disableClimateFanControl || void 0,
130742
130749
  climateKeepModeOnIdle: request.climateKeepModeOnIdle || void 0,
130743
130750
  climateExposeFan: request.climateExposeFan || void 0,
130751
+ climateAutoMode: request.climateAutoMode || void 0,
130744
130752
  composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0
130745
130753
  };
130746
- if (!config11.matterDeviceType && !config11.customName && !config11.customProductName && !config11.customVendorName && !config11.customSerialNumber && config11.customVendorId === void 0 && config11.disabled !== true && !config11.filterLifeEntity && !config11.cleaningModeEntity && !config11.temperatureEntity && !config11.humidityEntity && !config11.batteryEntity && !config11.roomEntities && !config11.disableLockPin && !config11.powerEntity && !config11.energyEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && !config11.currentRoomEntity && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverSliderDebounceMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && (!config11.composedEntities || config11.composedEntities.length === 0)) {
130754
+ if (!config11.matterDeviceType && !config11.customName && !config11.customProductName && !config11.customVendorName && !config11.customSerialNumber && config11.customVendorId === void 0 && config11.disabled !== true && !config11.filterLifeEntity && !config11.cleaningModeEntity && !config11.temperatureEntity && !config11.humidityEntity && !config11.batteryEntity && !config11.roomEntities && !config11.disableLockPin && !config11.powerEntity && !config11.energyEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && !config11.currentRoomEntity && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverSliderDebounceMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0)) {
130747
130755
  bridgeMap.delete(request.entityId);
130748
130756
  } else {
130749
130757
  bridgeMap.set(request.entityId, config11);
@@ -150795,6 +150803,15 @@ function getRunningModeFromHvacAction(entity) {
150795
150803
  }
150796
150804
  return hvacActionToRunningMode[action] ?? Thermostat3.ThermostatRunningMode.Off;
150797
150805
  }
150806
+ function pinnedAutoSystemMode(override) {
150807
+ if (override === "cool") {
150808
+ return Thermostat3.SystemMode.Cool;
150809
+ }
150810
+ if (override === "heat") {
150811
+ return Thermostat3.SystemMode.Heat;
150812
+ }
150813
+ return void 0;
150814
+ }
150798
150815
  var hvacModeToSystemMode = {
150799
150816
  [ClimateHvacMode.heat]: Thermostat3.SystemMode.Heat,
150800
150817
  [ClimateHvacMode.cool]: Thermostat3.SystemMode.Cool,
@@ -150848,6 +150865,16 @@ function computeSystemMode(entity, agent) {
150848
150865
  }
150849
150866
  const homeAssistant = agent.get(HomeAssistantEntityBehavior);
150850
150867
  const entityId = homeAssistant.entityId;
150868
+ const pinnedMode = pinnedAutoSystemMode(
150869
+ homeAssistant.state.mapping?.climateAutoMode
150870
+ );
150871
+ if (pinnedMode != null) {
150872
+ lastHvacDirection.set(
150873
+ entityId,
150874
+ pinnedMode === Thermostat3.SystemMode.Cool ? "cooling" : "heating"
150875
+ );
150876
+ return pinnedMode;
150877
+ }
150851
150878
  const action = attributes5(entity).hvac_action;
150852
150879
  if (action === ClimateHvacAction.cooling) {
150853
150880
  lastHvacDirection.set(entityId, "cooling");
@@ -162955,14 +162982,22 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
162955
162982
  }
162956
162983
  }, 55e3);
162957
162984
  }
162958
- async delete() {
162985
+ clearTimers() {
162959
162986
  if (this.keepaliveTimer) {
162960
162987
  clearInterval(this.keepaliveTimer);
162961
162988
  this.keepaliveTimer = void 0;
162962
162989
  }
162963
162990
  this.flushUpdate.clear();
162991
+ }
162992
+ // dispose calls close(), not delete(), so clean up in both
162993
+ async delete() {
162994
+ this.clearTimers();
162964
162995
  await super.delete();
162965
162996
  }
162997
+ async close() {
162998
+ this.clearTimers();
162999
+ await super.close();
163000
+ }
162966
163001
  /**
162967
163002
  * Re-push the latest operational state through setStateOf.
162968
163003
  * NoError stays detail-free so controllers do not display a false issue.