@riddix/hamh 2.1.0-alpha.843 → 2.1.0-alpha.844

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.51 | Production-ready, recommended for most users |
40
+ | **Stable** | `main` | v2.0.52 | 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,13 @@ 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.51)</strong> - Click to expand</summary>
64
+ <summary><strong>📦 Stable Features (v2.0.52)</strong> - Click to expand</summary>
65
65
 
66
- **New in v2.0.51:**
66
+ **New in v2.0.52 (hotfix release):**
67
+
68
+ - 🔌 The plugins page no longer fails with a 500 when a server mode bridge exists ([#430](https://github.com/RiDDiX/home-assistant-matter-hub/issues/430))
69
+
70
+ **Previously in v2.0.51:**
67
71
 
68
72
  - 🐕 **Opt-in wedge watchdog**: rotates a controller session that keeps acking but stops talking at the interaction layer, the automated "Play Sound" fix for stuck Apple devices ([#287](https://github.com/RiDDiX/home-assistant-matter-hub/issues/287), [#428](https://github.com/RiDDiX/home-assistant-matter-hub/issues/428))
69
73
  - 🧹 **Clean up orphaned records**: bridge menu action with a dry-run preview that removes identity and mapping leftovers of entities deleted from HA (7 day tombstone guards against false positives)
@@ -266,7 +270,7 @@ Re-assign the affected devices to their rooms after they reconnect. See the [doc
266
270
  <details>
267
271
  <summary><strong>🧪 Alpha Features (v2.1.0-alpha.x)</strong> - Click to expand</summary>
268
272
 
269
- **Alpha is currently level with Stable (v2.0.51).** All alpha work up to the latest pre-release has been promoted into v2.0.51. New alpha work continues from the next pre-release tag onward and will appear here as development progresses.
273
+ **Alpha is currently level with Stable (v2.0.52).** All alpha work up to the latest pre-release has been promoted into v2.0.52. New alpha work continues from the next pre-release tag onward and will appear here as development progresses.
270
274
 
271
275
  </details>
272
276
 
@@ -133183,7 +133183,8 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
133183
133183
  fanWindPresets: config11.fanWindPresets,
133184
133184
  fanRestoreSpeedOnPowerOn: config11.fanRestoreSpeedOnPowerOn,
133185
133185
  composedEntities: config11.composedEntities,
133186
- disableMomentaryFlip: config11.disableMomentaryFlip
133186
+ disableMomentaryFlip: config11.disableMomentaryFlip,
133187
+ vacuumAscendingRoomOrder: config11.vacuumAscendingRoomOrder
133187
133188
  });
133188
133189
  mappingsRestored++;
133189
133190
  }
@@ -133346,7 +133347,8 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
133346
133347
  customFanSpeedTags: config11.customFanSpeedTags,
133347
133348
  fanWindPresets: config11.fanWindPresets,
133348
133349
  composedEntities: config11.composedEntities,
133349
- disableMomentaryFlip: config11.disableMomentaryFlip
133350
+ disableMomentaryFlip: config11.disableMomentaryFlip,
133351
+ vacuumAscendingRoomOrder: config11.vacuumAscendingRoomOrder
133350
133352
  });
133351
133353
  mappingsRestored++;
133352
133354
  }
@@ -134195,6 +134197,7 @@ function entityMappingApi(mappingStorage, identityStorage) {
134195
134197
  fanRestoreSpeedOnPowerOn: body.fanRestoreSpeedOnPowerOn,
134196
134198
  currentRoomEntity: body.currentRoomEntity,
134197
134199
  cleanedAreaEntity: body.cleanedAreaEntity,
134200
+ vacuumAscendingRoomOrder: body.vacuumAscendingRoomOrder,
134198
134201
  disableCustomAreaRoomModes: body.disableCustomAreaRoomModes,
134199
134202
  valetudoIdentifier: body.valetudoIdentifier,
134200
134203
  coverSwapOpenClose: body.coverSwapOpenClose,
@@ -134704,7 +134707,8 @@ function configToProfileEntry(config11) {
134704
134707
  climateKeepModeOnIdle: config11.climateKeepModeOnIdle,
134705
134708
  climateExposeFan: config11.climateExposeFan,
134706
134709
  climateAutoMode: config11.climateAutoMode,
134707
- disableMomentaryFlip: config11.disableMomentaryFlip
134710
+ disableMomentaryFlip: config11.disableMomentaryFlip,
134711
+ vacuumAscendingRoomOrder: config11.vacuumAscendingRoomOrder
134708
134712
  };
134709
134713
  }
134710
134714
  function mappingProfileApi(mappingStorage) {
@@ -134845,7 +134849,8 @@ function mappingProfileApi(mappingStorage) {
134845
134849
  climateKeepModeOnIdle: entry.climateKeepModeOnIdle,
134846
134850
  climateExposeFan: entry.climateExposeFan,
134847
134851
  climateAutoMode: entry.climateAutoMode,
134848
- disableMomentaryFlip: entry.disableMomentaryFlip
134852
+ disableMomentaryFlip: entry.disableMomentaryFlip,
134853
+ vacuumAscendingRoomOrder: entry.vacuumAscendingRoomOrder
134849
134854
  });
134850
134855
  applied++;
134851
134856
  } catch (e) {
@@ -139564,6 +139569,7 @@ var EntityMappingStorage = class extends Service {
139564
139569
  fanRestoreSpeedOnPowerOn: request.fanRestoreSpeedOnPowerOn || void 0,
139565
139570
  currentRoomEntity: request.currentRoomEntity?.trim() || void 0,
139566
139571
  cleanedAreaEntity: request.cleanedAreaEntity?.trim() || void 0,
139572
+ vacuumAscendingRoomOrder: request.vacuumAscendingRoomOrder || void 0,
139567
139573
  disableCustomAreaRoomModes: request.disableCustomAreaRoomModes || void 0,
139568
139574
  valetudoIdentifier: request.valetudoIdentifier?.trim() || void 0,
139569
139575
  coverSwapOpenClose: request.coverSwapOpenClose || void 0,
@@ -139581,7 +139587,7 @@ var EntityMappingStorage = class extends Service {
139581
139587
  composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0,
139582
139588
  disableMomentaryFlip: request.disableMomentaryFlip || void 0
139583
139589
  };
139584
- 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.disableBatteryMapping && !config11.chargingStateEntity && !config11.roomEntities && !config11.disableLockPin && !config11.lockUsercodeService && config11.lockUsercodeSlot === void 0 && config11.lockPinMinLength === void 0 && config11.lockPinMaxLength === void 0 && !config11.powerEntity && !config11.energyEntity && !config11.voltageEntity && !config11.currentEntity && !config11.batteryPowerEntity && !config11.batteryEnergyEntity && !config11.chargingSwitchEntity && !config11.currentLimitEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && (!config11.fanWindPresets || (config11.fanWindPresets.natural?.length ?? 0) === 0 && (config11.fanWindPresets.sleep?.length ?? 0) === 0) && !config11.fanRestoreSpeedOnPowerOn && !config11.currentRoomEntity && !config11.cleanedAreaEntity && !config11.disableCustomAreaRoomModes && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverExposeAsDimmableLight && !config11.selectExposeAsSwitch && !config11.selectSwitchOnOption && !config11.selectSwitchOffOption && !config11.coverSliderDebounceMs && !config11.updateThrottleMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0) && !config11.disableMomentaryFlip) {
139590
+ 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.disableBatteryMapping && !config11.chargingStateEntity && !config11.roomEntities && !config11.disableLockPin && !config11.lockUsercodeService && config11.lockUsercodeSlot === void 0 && config11.lockPinMinLength === void 0 && config11.lockPinMaxLength === void 0 && !config11.powerEntity && !config11.energyEntity && !config11.voltageEntity && !config11.currentEntity && !config11.batteryPowerEntity && !config11.batteryEnergyEntity && !config11.chargingSwitchEntity && !config11.currentLimitEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && (!config11.fanWindPresets || (config11.fanWindPresets.natural?.length ?? 0) === 0 && (config11.fanWindPresets.sleep?.length ?? 0) === 0) && !config11.fanRestoreSpeedOnPowerOn && !config11.currentRoomEntity && !config11.cleanedAreaEntity && !config11.vacuumAscendingRoomOrder && !config11.disableCustomAreaRoomModes && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverExposeAsDimmableLight && !config11.selectExposeAsSwitch && !config11.selectSwitchOnOption && !config11.selectSwitchOffOption && !config11.coverSliderDebounceMs && !config11.updateThrottleMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0) && !config11.disableMomentaryFlip) {
139585
139591
  bridgeMap.delete(request.entityId);
139586
139592
  } else {
139587
139593
  bridgeMap.set(request.entityId, config11);
@@ -165085,6 +165091,23 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
165085
165091
  }
165086
165092
  }
165087
165093
  }
165094
+ /**
165095
+ * Snapshot the controller selection in the order the vacuum will actually
165096
+ * clean it. Roborock-class devices clean a batch of segments in ascending
165097
+ * id order and ignore the order they were dispatched in, so tracking has
165098
+ * to follow that instead of the tap order (#368).
165099
+ */
165100
+ orderSelectedAreas(selectedAreas) {
165101
+ const areas = [...selectedAreas];
165102
+ try {
165103
+ const mapping = this.agent.get(HomeAssistantEntityBehavior).state.mapping;
165104
+ if (mapping?.vacuumAscendingRoomOrder) {
165105
+ areas.sort((a, b) => a - b);
165106
+ }
165107
+ } catch {
165108
+ }
165109
+ return areas;
165110
+ }
165088
165111
  /** Read the cumulative cleaned-area sensor (m2), or null if not configured. */
165089
165112
  readCleanedAreaSqm() {
165090
165113
  try {
@@ -165274,7 +165297,10 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
165274
165297
  try {
165275
165298
  const serviceArea = this.agent.get(ServiceAreaBehavior);
165276
165299
  if (serviceArea.state.selectedAreas?.length > 0) {
165277
- s.activeAreas = [...serviceArea.state.selectedAreas];
165300
+ s.activeAreas = this.orderSelectedAreas(
165301
+ serviceArea.state.selectedAreas
165302
+ );
165303
+ serviceArea.state.selectedAreas = [...s.activeAreas];
165278
165304
  s.completedAreas.clear();
165279
165305
  s.lastCurrentArea = null;
165280
165306
  s.loggedShortCircuits.clear();
@@ -165313,7 +165339,10 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
165313
165339
  try {
165314
165340
  const serviceArea = this.agent.get(ServiceAreaBehavior);
165315
165341
  if (serviceArea.state.selectedAreas?.length > 0) {
165316
- s.activeAreas = [...serviceArea.state.selectedAreas];
165342
+ s.activeAreas = this.orderSelectedAreas(
165343
+ serviceArea.state.selectedAreas
165344
+ );
165345
+ serviceArea.state.selectedAreas = [...s.activeAreas];
165317
165346
  s.completedAreas.clear();
165318
165347
  s.lastCurrentArea = null;
165319
165348
  s.loggedShortCircuits.clear();
@@ -169992,7 +170021,16 @@ init_esm();
169992
170021
 
169993
170022
  // src/matter/behaviors/service-area-server.ts
169994
170023
  init_esm();
170024
+ init_home_assistant_entity_behavior();
169995
170025
  var logger234 = Logger.get("ServiceAreaServer");
170026
+ function orderSelection(areas, agent) {
170027
+ try {
170028
+ const ascending = agent?.get(HomeAssistantEntityBehavior).state.mapping?.vacuumAscendingRoomOrder === true;
170029
+ return ascending ? [...areas].sort((a, b) => a - b) : areas;
170030
+ } catch {
170031
+ return areas;
170032
+ }
170033
+ }
169996
170034
  var ServiceAreaWithProgress = ServiceAreaBehavior.with(
169997
170035
  ServiceArea3.Feature.ProgressReporting
169998
170036
  );
@@ -170002,7 +170040,7 @@ var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
170002
170040
  logger234.info(
170003
170041
  `ServiceArea selectAreas called with: ${JSON.stringify(newAreas)}`
170004
170042
  );
170005
- const uniqueAreas = [...new Set(newAreas)];
170043
+ const uniqueAreas = orderSelection([...new Set(newAreas)], this.agent);
170006
170044
  const supportedAreaIds = this.state.supportedAreas.map((a) => a.areaId);
170007
170045
  const invalidAreas = uniqueAreas.filter(
170008
170046
  (id) => !supportedAreaIds.includes(id)
@@ -170061,7 +170099,7 @@ var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress
170061
170099
  logger234.info(
170062
170100
  `ServiceArea selectAreas called with: ${JSON.stringify(newAreas)}`
170063
170101
  );
170064
- const uniqueAreas = [...new Set(newAreas)];
170102
+ const uniqueAreas = orderSelection([...new Set(newAreas)], this.agent);
170065
170103
  const supportedAreaIds = this.state.supportedAreas.map((a) => a.areaId);
170066
170104
  const invalidAreas = uniqueAreas.filter(
170067
170105
  (id) => !supportedAreaIds.includes(id)