@riddix/hamh 2.0.41 → 2.0.43

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.
@@ -146781,7 +146781,7 @@ var init_bridge_config_schema = __esm({
146781
146781
  },
146782
146782
  autoComposedDevices: {
146783
146783
  title: "Auto Composed Devices",
146784
- description: "Master toggle: combine related entities from the same Home Assistant device into a single Matter endpoint. Turns on battery, humidity, pressure, power, and energy auto-mapping at once \u2014 a Shelly Plug shows up as one device with power monitoring instead of several siblings.",
146784
+ description: "Master toggle: combine related entities from the same Home Assistant device into a single Matter endpoint. Turns on battery, humidity, pressure, power, and energy auto-mapping at once, a Shelly Plug shows up as one device with power monitoring instead of several siblings.",
146785
146785
  type: "boolean",
146786
146786
  default: false
146787
146787
  },
@@ -146799,13 +146799,13 @@ var init_bridge_config_schema = __esm({
146799
146799
  },
146800
146800
  preferEntityRegistryName: {
146801
146801
  title: "Prefer Entity Registry Name (HA 2026.4 workaround)",
146802
- description: "Use the entity registry name (or original_name) as nodeLabel instead of the composed friendly_name. Since Home Assistant 2026.4, friendly_name is prefixed with the device name, which breaks voice commands that relied on the short entity name. Resolution order: customName \u2192 registry name \u2192 registry original_name \u2192 friendly_name \u2192 entity_id. Matter has no alias concept \u2014 this only changes which single name is reported.",
146802
+ description: "Use the entity registry name (or original_name) as nodeLabel instead of the composed friendly_name. Since Home Assistant 2026.4, friendly_name is prefixed with the device name, which breaks voice commands that relied on the short entity name. Resolution order: customName \u2192 registry name \u2192 registry original_name \u2192 friendly_name \u2192 entity_id. Matter has no alias concept, this only changes which single name is reported.",
146803
146803
  type: "boolean",
146804
146804
  default: false
146805
146805
  },
146806
146806
  vacuumOnOff: {
146807
146807
  title: "Vacuum: Include OnOff Cluster (Alexa)",
146808
- description: "Add an OnOff cluster to robot vacuum endpoints. Alexa REQUIRES this (PowerController) to show robotic vacuums in the app. Without it, Alexa commissions the device but never displays it. In Server Mode this is enabled automatically \u2014 only check this for bridge mode. WARNING: OnOff is NOT part of the Matter RVC device type specification. Enabling this may break Apple Home (shows 'Updating') and Google Home.",
146808
+ description: "Add an OnOff cluster to robot vacuum endpoints. Alexa REQUIRES this (PowerController) to show robotic vacuums in the app. Without it, Alexa commissions the device but never displays it. In Server Mode this is enabled automatically, only check this for bridge mode. WARNING: OnOff is NOT part of the Matter RVC device type specification. Enabling this may break Apple Home (shows 'Updating') and Google Home.",
146809
146809
  type: "boolean"
146810
146810
  },
146811
146811
  alexaPreserveBrightnessOnTurnOn: {
@@ -147874,6 +147874,7 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
147874
147874
  valetudoIdentifier: config10.valetudoIdentifier,
147875
147875
  coverSwapOpenClose: config10.coverSwapOpenClose,
147876
147876
  disableClimateOnOff: config10.disableClimateOnOff,
147877
+ disableClimateFanControl: config10.disableClimateFanControl,
147877
147878
  customServiceAreas: config10.customServiceAreas,
147878
147879
  customFanSpeedTags: config10.customFanSpeedTags,
147879
147880
  composedEntities: config10.composedEntities
@@ -148020,6 +148021,7 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
148020
148021
  valetudoIdentifier: config10.valetudoIdentifier,
148021
148022
  coverSwapOpenClose: config10.coverSwapOpenClose,
148022
148023
  disableClimateOnOff: config10.disableClimateOnOff,
148024
+ disableClimateFanControl: config10.disableClimateFanControl,
148023
148025
  customServiceAreas: config10.customServiceAreas,
148024
148026
  customFanSpeedTags: config10.customFanSpeedTags,
148025
148027
  composedEntities: config10.composedEntities
@@ -148594,7 +148596,14 @@ function addLogEntry(entry) {
148594
148596
  function logsApi(_logger) {
148595
148597
  const router = express5.Router();
148596
148598
  router.get("/", (req, res) => {
148597
- const { level, search, limit = "100", offset = "0" } = req.query;
148599
+ const {
148600
+ level,
148601
+ search,
148602
+ category,
148603
+ facility,
148604
+ limit = "100",
148605
+ offset = "0"
148606
+ } = req.query;
148598
148607
  const limitNum = Math.min(
148599
148608
  500,
148600
148609
  Math.max(1, parseInt(limit, 10) || 100)
@@ -148605,6 +148614,18 @@ function logsApi(_logger) {
148605
148614
  const levels = level.split(",").map((l) => l.toLowerCase().trim());
148606
148615
  entries = entries.filter((e) => levels.includes(e.level.toLowerCase()));
148607
148616
  }
148617
+ if (category && typeof category === "string") {
148618
+ const cats = category.split(",").map((c) => c.toLowerCase().trim());
148619
+ entries = entries.filter(
148620
+ (e) => e.category != null && cats.includes(e.category.toLowerCase())
148621
+ );
148622
+ }
148623
+ if (facility && typeof facility === "string") {
148624
+ const facLower = facility.toLowerCase();
148625
+ entries = entries.filter(
148626
+ (e) => e.facility?.toLowerCase().includes(facLower)
148627
+ );
148628
+ }
148608
148629
  if (search && typeof search === "string") {
148609
148630
  const searchLower = search.toLowerCase();
148610
148631
  entries = entries.filter(
@@ -148840,6 +148861,7 @@ function entityMappingApi(mappingStorage) {
148840
148861
  valetudoIdentifier: body.valetudoIdentifier,
148841
148862
  coverSwapOpenClose: body.coverSwapOpenClose,
148842
148863
  disableClimateOnOff: body.disableClimateOnOff,
148864
+ disableClimateFanControl: body.disableClimateFanControl,
148843
148865
  composedEntities: body.composedEntities
148844
148866
  };
148845
148867
  const config10 = await mappingStorage.setMapping(request);
@@ -149303,7 +149325,8 @@ function configToProfileEntry(config10) {
149303
149325
  customFanSpeedTags: config10.customFanSpeedTags,
149304
149326
  valetudoIdentifier: config10.valetudoIdentifier,
149305
149327
  coverSwapOpenClose: config10.coverSwapOpenClose,
149306
- disableClimateOnOff: config10.disableClimateOnOff
149328
+ disableClimateOnOff: config10.disableClimateOnOff,
149329
+ disableClimateFanControl: config10.disableClimateFanControl
149307
149330
  };
149308
149331
  }
149309
149332
  function mappingProfileApi(mappingStorage) {
@@ -149425,7 +149448,8 @@ function mappingProfileApi(mappingStorage) {
149425
149448
  customFanSpeedTags: entry.customFanSpeedTags,
149426
149449
  valetudoIdentifier: entry.valetudoIdentifier,
149427
149450
  coverSwapOpenClose: entry.coverSwapOpenClose,
149428
- disableClimateOnOff: entry.disableClimateOnOff
149451
+ disableClimateOnOff: entry.disableClimateOnOff,
149452
+ disableClimateFanControl: entry.disableClimateFanControl
149429
149453
  });
149430
149454
  applied++;
149431
149455
  } catch (e) {
@@ -151603,6 +151627,17 @@ init_esm7();
151603
151627
 
151604
151628
  // src/core/app/logger.ts
151605
151629
  init_esm();
151630
+ var MATTER_TRAFFIC_FACILITIES = /* @__PURE__ */ new Set([
151631
+ "InteractionServer",
151632
+ "MessageExchange",
151633
+ "MessageChannel",
151634
+ "ServerSubscription",
151635
+ "IncomingInteractionServerMessenger",
151636
+ "ExchangeManager"
151637
+ ]);
151638
+ function categoryFor(facility) {
151639
+ return MATTER_TRAFFIC_FACILITIES.has(facility) ? "matter-traffic" : void 0;
151640
+ }
151606
151641
  function logLevelFromString(level) {
151607
151642
  const customNames = {
151608
151643
  SILLY: -1 /* SILLY */
@@ -151648,6 +151683,26 @@ var LoggerService = class {
151648
151683
  MessageExchange: resolvedProtocolLevel
151649
151684
  };
151650
151685
  Logger.format = options.disableColors ? LogFormat.PLAIN : LogFormat.ANSI;
151686
+ const destinationLevel = this.customLogLevelMapping[this._level] ?? this._level;
151687
+ Logger.destinations["hamh-buffer"] = LogDestination({
151688
+ name: "hamh-buffer",
151689
+ level: destinationLevel,
151690
+ facilityLevels: {
151691
+ MessageChannel: resolvedProtocolLevel,
151692
+ MessageExchange: resolvedProtocolLevel
151693
+ },
151694
+ write: (text, message) => {
151695
+ const category = categoryFor(message.facility);
151696
+ if (!category) return;
151697
+ addLogEntry({
151698
+ timestamp: message.now.toISOString(),
151699
+ level: logLevelToString(message.level).toLowerCase(),
151700
+ message: text,
151701
+ facility: message.facility,
151702
+ category
151703
+ });
151704
+ }
151705
+ });
151651
151706
  }
151652
151707
  get(nameOrService) {
151653
151708
  let name;
@@ -152743,7 +152798,7 @@ var HomeAssistantRegistry = class extends Service {
152743
152798
  let refreshing = false;
152744
152799
  this.autoRefresh = setInterval(async () => {
152745
152800
  if (refreshing) {
152746
- logger146.debug("Skipping registry refresh \u2014 previous tick still running");
152801
+ logger146.debug("Skipping registry refresh, previous tick still running");
152747
152802
  return;
152748
152803
  }
152749
152804
  refreshing = true;
@@ -153295,9 +153350,10 @@ var EntityMappingStorage = class extends Service {
153295
153350
  valetudoIdentifier: request.valetudoIdentifier?.trim() || void 0,
153296
153351
  coverSwapOpenClose: request.coverSwapOpenClose || void 0,
153297
153352
  disableClimateOnOff: request.disableClimateOnOff || void 0,
153353
+ disableClimateFanControl: request.disableClimateFanControl || void 0,
153298
153354
  composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0
153299
153355
  };
153300
- if (!config10.matterDeviceType && !config10.customName && !config10.customProductName && !config10.customVendorName && !config10.customSerialNumber && config10.disabled !== true && !config10.filterLifeEntity && !config10.cleaningModeEntity && !config10.temperatureEntity && !config10.humidityEntity && !config10.batteryEntity && !config10.roomEntities && !config10.disableLockPin && !config10.powerEntity && !config10.energyEntity && !config10.pressureEntity && !config10.suctionLevelEntity && !config10.mopIntensityEntity && (!config10.customServiceAreas || config10.customServiceAreas.length === 0) && (!config10.customFanSpeedTags || Object.keys(config10.customFanSpeedTags).length === 0) && !config10.currentRoomEntity && !config10.valetudoIdentifier && !config10.coverSwapOpenClose && !config10.disableClimateOnOff && (!config10.composedEntities || config10.composedEntities.length === 0)) {
153356
+ if (!config10.matterDeviceType && !config10.customName && !config10.customProductName && !config10.customVendorName && !config10.customSerialNumber && config10.disabled !== true && !config10.filterLifeEntity && !config10.cleaningModeEntity && !config10.temperatureEntity && !config10.humidityEntity && !config10.batteryEntity && !config10.roomEntities && !config10.disableLockPin && !config10.powerEntity && !config10.energyEntity && !config10.pressureEntity && !config10.suctionLevelEntity && !config10.mopIntensityEntity && (!config10.customServiceAreas || config10.customServiceAreas.length === 0) && (!config10.customFanSpeedTags || Object.keys(config10.customFanSpeedTags).length === 0) && !config10.currentRoomEntity && !config10.valetudoIdentifier && !config10.coverSwapOpenClose && !config10.disableClimateOnOff && !config10.disableClimateFanControl && (!config10.composedEntities || config10.composedEntities.length === 0)) {
153301
153357
  bridgeMap.delete(request.entityId);
153302
153358
  } else {
153303
153359
  bridgeMap.set(request.entityId, config10);
@@ -165331,7 +165387,7 @@ var ServerModeServerNode = class extends ServerNode {
165331
165387
  /**
165332
165388
  * Update root-level BasicInformation with entity-specific data.
165333
165389
  * In server mode, controllers (Apple Home, Alexa) read the root node's
165334
- * BasicInformation not the device endpoint's BridgedDeviceBasicInformation.
165390
+ * BasicInformation, not the device endpoint's BridgedDeviceBasicInformation.
165335
165391
  * Without this, server-mode devices show bridge defaults (e.g. "riddix" / "MatterHub").
165336
165392
  */
165337
165393
  async updateDeviceIdentity(entityId, device, mapping, friendlyName) {
@@ -167516,7 +167572,9 @@ function createBridgeServerConfig(data) {
167516
167572
  hardwareVersion: data.basicInformation.hardwareVersion,
167517
167573
  softwareVersion: data.basicInformation.softwareVersion,
167518
167574
  hardwareVersionString: data.basicInformation.hardwareVersionString,
167519
- softwareVersionString: data.basicInformation.softwareVersionString ?? String(data.basicInformation.softwareVersion),
167575
+ // Keep the root string aligned with the numeric softwareVersion. Aqara
167576
+ // stalls bridge registration when the two diverge (#316).
167577
+ softwareVersionString: String(data.basicInformation.softwareVersion),
167520
167578
  ...data.countryCode ? { location: data.countryCode } : {}
167521
167579
  },
167522
167580
  subscriptions: {
@@ -167840,7 +167898,7 @@ ${e?.toString()}`);
167840
167898
  );
167841
167899
  if (totalSubs === 0 && sessions.length > 0) {
167842
167900
  this.log.warn(
167843
- `All subscriptions lost \u2014 ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
167901
+ `All subscriptions lost, ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
167844
167902
  );
167845
167903
  if (!this.deadSessionTimer) {
167846
167904
  this.deadSessionTimer = setTimeout(() => {
@@ -167888,7 +167946,7 @@ ${e?.toString()}`);
167888
167946
  for (const s of [...sessionManager.sessions]) {
167889
167947
  if (s !== newSession && !s.isClosing && s.peerNodeId === newSession.peerNodeId && s.fabric?.fabricIndex === newSession.fabric?.fabricIndex && s.subscriptions.size === 0) {
167890
167948
  this.log.info(
167891
- `Closing stale session ${s.id} (peer ${s.peerNodeId}, 0 subs) \u2014 replaced by session ${newSession.id}`
167949
+ `Closing stale session ${s.id} (peer ${s.peerNodeId}, 0 subs), replaced by session ${newSession.id}`
167892
167950
  );
167893
167951
  s.initiateForceClose().catch(() => {
167894
167952
  });
@@ -168343,7 +168401,7 @@ var BasicInformationServer2 = class extends BridgedDeviceBasicInformationServer
168343
168401
  await super.initialize();
168344
168402
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
168345
168403
  this.update(homeAssistant.entity);
168346
- this.reactTo(homeAssistant.onChange, this.update);
168404
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
168347
168405
  }
168348
168406
  update(entity) {
168349
168407
  if (!entity.state || !entity.state.attributes) {
@@ -168409,7 +168467,7 @@ var ElectricalEnergyMeasurementServerBase = class extends FeaturedBase {
168409
168467
  );
168410
168468
  }
168411
168469
  this.update();
168412
- this.reactTo(homeAssistant.onChange, this.update);
168470
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
168413
168471
  }
168414
168472
  update() {
168415
168473
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
@@ -168469,7 +168527,7 @@ var ElectricalPowerMeasurementServerBase = class extends ElectricalPowerMeasurem
168469
168527
  );
168470
168528
  }
168471
168529
  this.update();
168472
- this.reactTo(homeAssistant.onChange, this.update);
168530
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
168473
168531
  }
168474
168532
  update() {
168475
168533
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
@@ -168522,7 +168580,7 @@ var HumidityMeasurementServerBase = class extends RelativeHumidityMeasurementSer
168522
168580
  await super.initialize();
168523
168581
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
168524
168582
  this.update(homeAssistant.entity);
168525
- this.reactTo(homeAssistant.onChange, this.update);
168583
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
168526
168584
  }
168527
168585
  update(entity) {
168528
168586
  if (!entity.state || !entity.state.attributes) {
@@ -168586,7 +168644,7 @@ var PowerSourceServerBase = class extends FeaturedBase2 {
168586
168644
  );
168587
168645
  }
168588
168646
  this.update(homeAssistant.entity);
168589
- this.reactTo(homeAssistant.onChange, this.update);
168647
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
168590
168648
  }
168591
168649
  update(entity) {
168592
168650
  if (!entity.state || !entity.state.attributes) {
@@ -168672,7 +168730,7 @@ var TemperatureMeasurementServerBase = class extends TemperatureMeasurementServe
168672
168730
  await super.initialize();
168673
168731
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
168674
168732
  this.update(homeAssistant.entity);
168675
- this.reactTo(homeAssistant.onChange, this.update);
168733
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
168676
168734
  }
168677
168735
  update(entity) {
168678
168736
  if (!entity.state || !entity.state.attributes) {
@@ -168714,7 +168772,7 @@ var HepaFilterMonitoringServerBase = class extends FeaturedBase3 {
168714
168772
  await super.initialize();
168715
168773
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
168716
168774
  this.update(homeAssistant.entity);
168717
- this.reactTo(homeAssistant.onChange, this.update);
168775
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
168718
168776
  }
168719
168777
  update(entity) {
168720
168778
  if (!entity.state || !entity.state.attributes) {
@@ -169192,7 +169250,7 @@ var FeaturedBase5 = FanControlServer.with(
169192
169250
  "Rocking",
169193
169251
  "Wind"
169194
169252
  ).set({
169195
- // rockSupport / windSupport are Fixed quality attributes they MUST be set
169253
+ // rockSupport / windSupport are Fixed quality attributes, they MUST be set
169196
169254
  // via .set() at behavior creation time, NOT in initialize().
169197
169255
  // Without these, controllers reject attempts to enable rocking/wind.
169198
169256
  rockSupport: { rockUpDown: true },
@@ -169968,7 +170026,7 @@ var PressureMeasurementServerBase = class extends PressureMeasurementServer {
169968
170026
  await super.initialize();
169969
170027
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
169970
170028
  this.update(homeAssistant.entity);
169971
- this.reactTo(homeAssistant.onChange, this.update);
170029
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
169972
170030
  }
169973
170031
  update(entity) {
169974
170032
  if (!entity.state || !entity.state.attributes) {
@@ -170528,7 +170586,7 @@ var BooleanStateServerBase = class extends BooleanStateServer {
170528
170586
  await super.initialize();
170529
170587
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
170530
170588
  this.update(homeAssistant.entity);
170531
- this.reactTo(homeAssistant.onChange, this.update);
170589
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
170532
170590
  }
170533
170591
  update(entity) {
170534
170592
  if (!entity.state || !entity.state.attributes) {
@@ -170606,7 +170664,7 @@ var PirOccupancySensingServer = class extends PirOccupancySensingServerBase {
170606
170664
  await super.initialize();
170607
170665
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
170608
170666
  this.update(homeAssistant.entity);
170609
- this.reactTo(homeAssistant.onChange, this.update);
170667
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
170610
170668
  }
170611
170669
  update(entity) {
170612
170670
  if (!entity.state || !entity.state.attributes) {
@@ -170674,7 +170732,7 @@ var OccupancySensingServer2 = class extends OccupancySensingServerBase {
170674
170732
  await super.initialize();
170675
170733
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
170676
170734
  this.update(homeAssistant.entity);
170677
- this.reactTo(homeAssistant.onChange, this.update);
170735
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
170678
170736
  }
170679
170737
  update(entity) {
170680
170738
  if (!entity.state || !entity.state.attributes) {
@@ -170789,7 +170847,7 @@ var SmokeAlarmServerImpl = class extends SmokeAlarmServerWithFeature {
170789
170847
  await super.initialize();
170790
170848
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
170791
170849
  this.update(homeAssistant.entity);
170792
- this.reactTo(homeAssistant.onChange, this.update);
170850
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
170793
170851
  }
170794
170852
  update(entity) {
170795
170853
  const isOn = this.agent.get(HomeAssistantEntityBehavior).isAvailable && entity.state.state === "on";
@@ -170803,7 +170861,7 @@ var CoAlarmServerImpl = class extends CoAlarmServerWithFeature {
170803
170861
  await super.initialize();
170804
170862
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
170805
170863
  this.update(homeAssistant.entity);
170806
- this.reactTo(homeAssistant.onChange, this.update);
170864
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
170807
170865
  }
170808
170866
  update(entity) {
170809
170867
  const isOn = this.agent.get(HomeAssistantEntityBehavior).isAvailable && entity.state.state === "on";
@@ -171084,6 +171142,23 @@ var ClimateOnOffServer = OnOffServer2({
171084
171142
 
171085
171143
  // src/matter/endpoints/legacy/climate/behaviors/climate-thermostat-server.ts
171086
171144
  init_dist();
171145
+
171146
+ // src/utils/converters/snap-to-step.ts
171147
+ function snapToStep(target, current, step) {
171148
+ if (step == null || !Number.isFinite(step) || step <= 0) return target;
171149
+ const ratio = target / step;
171150
+ const lower = Math.floor(ratio) * step;
171151
+ const upper = Math.ceil(ratio) * step;
171152
+ if (lower === upper) return target;
171153
+ const distLower = target - lower;
171154
+ const distUpper = upper - target;
171155
+ if (distLower < distUpper) return lower;
171156
+ if (distUpper < distLower) return upper;
171157
+ if (current == null || !Number.isFinite(current)) return upper;
171158
+ return target > current ? upper : lower;
171159
+ }
171160
+
171161
+ // src/matter/endpoints/legacy/climate/behaviors/climate-thermostat-server.ts
171087
171162
  init_home_assistant_entity_behavior();
171088
171163
 
171089
171164
  // src/matter/behaviors/thermostat-server.ts
@@ -171279,7 +171354,7 @@ var ThermostatServerBase = class extends FullFeaturedBase {
171279
171354
  // Heat/Cool/Off but SKIPS Auto (see #handleSystemModeChange in Matter.js).
171280
171355
  // Without this, switching Heat→Auto leaves runningMode stale at Heat.
171281
171356
  // 889010b set for ALL modes (conflicted with reactor), 0678d35 set for NONE
171282
- // (stale in Auto). da04b2e's Auto-only approach is correct the issues
171357
+ // (stale in Auto). da04b2e's Auto-only approach is correct, the issues
171283
171358
  // reported after it were caused by localTemperature fallback, not runningMode.
171284
171359
  ...this.features.heating && this.features.cooling && systemMode === Thermostat3.SystemMode.Auto ? { thermostatRunningMode: runningMode } : {}
171285
171360
  });
@@ -171564,7 +171639,7 @@ var CoolingOnlyThermostatServerBase = class extends CoolingOnlyFeaturedBase {
171564
171639
  static State = class extends CoolingOnlyFeaturedBase.State {
171565
171640
  config;
171566
171641
  };
171567
- // Each variant MUST define its own initialize() see HeatingOnly comment above.
171642
+ // Each variant MUST define its own initialize(), see HeatingOnly comment above.
171568
171643
  async initialize() {
171569
171644
  thermostatPreInitialize(this);
171570
171645
  await super.initialize();
@@ -171586,7 +171661,7 @@ var HeatingAndCoolingThermostatServerBase = class extends HeatingAndCoolingFeatu
171586
171661
  static State = class extends HeatingAndCoolingFeaturedBase.State {
171587
171662
  config;
171588
171663
  };
171589
- // Each variant MUST define its own initialize() see HeatingOnly comment above.
171664
+ // Each variant MUST define its own initialize(), see HeatingOnly comment above.
171590
171665
  async initialize() {
171591
171666
  thermostatPreInitialize(this);
171592
171667
  await super.initialize();
@@ -171667,6 +171742,18 @@ var getTemp = (agent, entity, attributeName) => {
171667
171742
  return Temperature.withUnit(+temperature3, unit);
171668
171743
  }
171669
171744
  };
171745
+ var getStep = (entity) => {
171746
+ const raw = attributes4(entity).target_temp_step;
171747
+ if (raw == null) return void 0;
171748
+ const num = typeof raw === "string" ? parseFloat(raw) : raw;
171749
+ return Number.isFinite(num) && num > 0 ? num : void 0;
171750
+ };
171751
+ var getRefTemp = (entity, attr) => {
171752
+ const raw = attributes4(entity)[attr];
171753
+ if (raw == null) return void 0;
171754
+ const num = typeof raw === "string" ? parseFloat(raw) : raw;
171755
+ return Number.isFinite(num) ? num : void 0;
171756
+ };
171670
171757
  var systemModeToHvacMode = {
171671
171758
  [Thermostat3.SystemMode.Auto]: ClimateHvacMode.heat_cool,
171672
171759
  [Thermostat3.SystemMode.Precooling]: ClimateHvacMode.cool,
@@ -171745,7 +171832,7 @@ var config4 = {
171745
171832
  const direction = getHeatCoolOnlyDirection(entity, agent);
171746
171833
  return direction === "cooling" ? Thermostat3.SystemMode.Cool : Thermostat3.SystemMode.Heat;
171747
171834
  }
171748
- const hasMatterAuto = modes.includes(ClimateHvacMode.heat_cool) || modes.includes(ClimateHvacMode.auto);
171835
+ const hasMatterAuto = modes.includes(ClimateHvacMode.heat_cool) && (modes.includes(ClimateHvacMode.heat) || modes.includes(ClimateHvacMode.cool));
171749
171836
  if (hasMatterAuto) {
171750
171837
  return systemMode;
171751
171838
  }
@@ -171759,11 +171846,34 @@ var config4 = {
171759
171846
  if (hasCooling && !hasHeating) {
171760
171847
  return Thermostat3.SystemMode.Cool;
171761
171848
  }
171849
+ const homeAssistant = agent.get(HomeAssistantEntityBehavior);
171850
+ const entityId = homeAssistant.entityId;
171762
171851
  const action = attributes4(entity).hvac_action;
171763
171852
  if (action === ClimateHvacAction.cooling) {
171853
+ lastHvacDirection.set(entityId, "cooling");
171764
171854
  return Thermostat3.SystemMode.Cool;
171765
171855
  }
171766
- return Thermostat3.SystemMode.Heat;
171856
+ if (action === ClimateHvacAction.heating) {
171857
+ lastHvacDirection.set(entityId, "heating");
171858
+ return Thermostat3.SystemMode.Heat;
171859
+ }
171860
+ const remembered = lastHvacDirection.get(entityId);
171861
+ if (remembered) {
171862
+ return remembered === "cooling" ? Thermostat3.SystemMode.Cool : Thermostat3.SystemMode.Heat;
171863
+ }
171864
+ const current = attributes4(entity).current_temperature;
171865
+ const target = attributes4(entity).temperature;
171866
+ if (typeof current === "number" && typeof target === "number") {
171867
+ if (current > target) {
171868
+ lastHvacDirection.set(entityId, "cooling");
171869
+ return Thermostat3.SystemMode.Cool;
171870
+ }
171871
+ if (current < target) {
171872
+ lastHvacDirection.set(entityId, "heating");
171873
+ return Thermostat3.SystemMode.Heat;
171874
+ }
171875
+ }
171876
+ return Thermostat3.SystemMode.Cool;
171767
171877
  }
171768
171878
  return systemMode;
171769
171879
  },
@@ -171825,19 +171935,37 @@ var config4 = {
171825
171935
  data: { hvac_mode: targetMode }
171826
171936
  };
171827
171937
  },
171828
- setTargetTemperature: (value, agent) => ({
171829
- action: "climate.set_temperature",
171830
- data: {
171831
- temperature: value.toUnit(getUnit(agent))
171832
- }
171833
- }),
171834
- setTargetTemperatureRange: ({ low, high }, agent) => ({
171835
- action: "climate.set_temperature",
171836
- data: {
171837
- target_temp_low: low.toUnit(getUnit(agent)),
171838
- target_temp_high: high.toUnit(getUnit(agent))
171839
- }
171840
- })
171938
+ setTargetTemperature: (value, agent) => {
171939
+ const homeAssistant = agent.get(HomeAssistantEntityBehavior);
171940
+ const entity = homeAssistant.entity.state;
171941
+ const unit = getUnit(agent);
171942
+ const target = value.toUnit(unit);
171943
+ const step = getStep(entity);
171944
+ const current = getRefTemp(entity, "temperature") ?? getRefTemp(entity, "target_temperature");
171945
+ return {
171946
+ action: "climate.set_temperature",
171947
+ data: {
171948
+ temperature: snapToStep(target, current, step)
171949
+ }
171950
+ };
171951
+ },
171952
+ setTargetTemperatureRange: ({ low, high }, agent) => {
171953
+ const homeAssistant = agent.get(HomeAssistantEntityBehavior);
171954
+ const entity = homeAssistant.entity.state;
171955
+ const unit = getUnit(agent);
171956
+ const step = getStep(entity);
171957
+ const lowTarget = low.toUnit(unit);
171958
+ const highTarget = high.toUnit(unit);
171959
+ const lowCurrent = getRefTemp(entity, "target_temp_low") ?? getRefTemp(entity, "temperature");
171960
+ const highCurrent = getRefTemp(entity, "target_temp_high") ?? getRefTemp(entity, "temperature");
171961
+ return {
171962
+ action: "climate.set_temperature",
171963
+ data: {
171964
+ target_temp_low: snapToStep(lowTarget, lowCurrent, step),
171965
+ target_temp_high: snapToStep(highTarget, highCurrent, step)
171966
+ }
171967
+ };
171968
+ }
171841
171969
  };
171842
171970
  function ClimateThermostatServer(initialState = {}, features2) {
171843
171971
  return ThermostatServer2(config4, initialState, features2);
@@ -171917,10 +172045,7 @@ function ClimateDevice(homeAssistantEntity) {
171917
172045
  }
171918
172046
  const supportsHumidity = attributes7.current_humidity != null || testBit(supportedFeatures, ClimateDeviceFeature.TARGET_HUMIDITY);
171919
172047
  const supportsOnOff = testBit(supportedFeatures, ClimateDeviceFeature.TURN_ON) && testBit(supportedFeatures, ClimateDeviceFeature.TURN_OFF) && homeAssistantEntity.mapping?.disableClimateOnOff !== true;
171920
- const supportsFanMode = testBit(
171921
- supportedFeatures,
171922
- ClimateDeviceFeature.FAN_MODE
171923
- );
172048
+ const supportsFanMode = testBit(supportedFeatures, ClimateDeviceFeature.FAN_MODE) && homeAssistantEntity.mapping?.disableClimateFanControl !== true;
171924
172049
  const initialState = {
171925
172050
  // Pass actual current_temperature for initial state.
171926
172051
  // If unavailable (null/undefined), update() will fall back to the
@@ -171934,7 +172059,7 @@ function ClimateDevice(homeAssistantEntity) {
171934
172059
  minCoolSetpointLimit: toMatterTemp(attributes7.min_temp) ?? 0,
171935
172060
  maxCoolSetpointLimit: toMatterTemp(attributes7.max_temp) ?? 5e3
171936
172061
  };
171937
- const autoMode = supportsHeating && supportsCooling && (attributes7.hvac_modes.includes(ClimateHvacMode.heat_cool) || attributes7.hvac_modes.includes(ClimateHvacMode.auto)) && (attributes7.hvac_modes.includes(ClimateHvacMode.heat) || attributes7.hvac_modes.includes(ClimateHvacMode.cool));
172062
+ const autoMode = supportsHeating && supportsCooling && attributes7.hvac_modes.includes(ClimateHvacMode.heat_cool) && (attributes7.hvac_modes.includes(ClimateHvacMode.heat) || attributes7.hvac_modes.includes(ClimateHvacMode.cool));
171938
172063
  return ClimateDeviceType(
171939
172064
  supportsOnOff,
171940
172065
  supportsHumidity,
@@ -172059,6 +172184,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
172059
172184
  this.state.targetPositionTiltPercent100ths = null;
172060
172185
  }
172061
172186
  }
172187
+ this.state.type = this.features.lift && this.features.tilt ? WindowCovering3.WindowCoveringType.TiltBlindLift : this.features.tilt ? WindowCovering3.WindowCoveringType.TiltBlindTiltOnly : WindowCovering3.WindowCoveringType.Rollershade;
172062
172188
  await super.initialize();
172063
172189
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
172064
172190
  this.update(homeAssistant.entity);
@@ -172177,7 +172303,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
172177
172303
  } else if (type === MovementType.Tilt) {
172178
172304
  if (targetPercent100ths == null && this.lastLiftMovementDirection === direction && Date.now() - this.lastLiftMovementMs < 50) {
172179
172305
  logger179.info(
172180
- `Skipping tilt ${MovementDirection[direction]} \u2014 lift already moving in same direction`
172306
+ `Skipping tilt ${MovementDirection[direction]}, lift already moving in same direction`
172181
172307
  );
172182
172308
  return;
172183
172309
  }
@@ -172351,6 +172477,13 @@ var DEVICE_CLASS_TO_MATTER_TYPE = {
172351
172477
  shade: {
172352
172478
  type: WindowCovering3.WindowCoveringType.Rollershade,
172353
172479
  endProductType: WindowCovering3.EndProductType.RollerShade
172480
+ },
172481
+ // Velux-style motorized roof/casement windows. There's no Matter
172482
+ // WindowCoveringType for "window", so we map to lift-only Rollershade
172483
+ // and use Unknown end-product to avoid implying a specific physical form.
172484
+ window: {
172485
+ type: WindowCovering3.WindowCoveringType.Rollershade,
172486
+ endProductType: WindowCovering3.EndProductType.Unknown
172354
172487
  }
172355
172488
  };
172356
172489
  var deviceClassMapping = (entity) => {
@@ -172359,12 +172492,21 @@ var deviceClassMapping = (entity) => {
172359
172492
  const mapping = DEVICE_CLASS_TO_MATTER_TYPE[raw.toLowerCase()];
172360
172493
  if (!mapping) return void 0;
172361
172494
  const supportedFeatures = attributes5(entity).supported_features ?? 0;
172495
+ const hasLift = (supportedFeatures & CoverSupportedFeatures.support_open) !== 0;
172362
172496
  const hasTilt = (supportedFeatures & CoverSupportedFeatures.support_open_tilt) !== 0;
172363
- if (mapping.type === WindowCovering3.WindowCoveringType.TiltBlindTiltOnly && !hasTilt) {
172364
- return {
172365
- type: WindowCovering3.WindowCoveringType.Rollershade,
172366
- endProductType: mapping.endProductType
172367
- };
172497
+ if (mapping.type === WindowCovering3.WindowCoveringType.TiltBlindTiltOnly) {
172498
+ if (!hasTilt) {
172499
+ return {
172500
+ type: WindowCovering3.WindowCoveringType.Rollershade,
172501
+ endProductType: mapping.endProductType
172502
+ };
172503
+ }
172504
+ if (hasLift) {
172505
+ return {
172506
+ type: WindowCovering3.WindowCoveringType.TiltBlindLift,
172507
+ endProductType: mapping.endProductType
172508
+ };
172509
+ }
172368
172510
  }
172369
172511
  return mapping;
172370
172512
  };
@@ -174596,7 +174738,7 @@ var SpeakerLevelControlServerBase = class extends FeaturedBase8 {
174596
174738
  *
174597
174739
  * The base class registers a reactor on onOff$Changed that sets
174598
174740
  * currentLevel = onLevel. This is designed for lights (restore brightness
174599
- * on power-on) but is wrong for speakers it overwrites the correct
174741
+ * on power-on) but is wrong for speakers, it overwrites the correct
174600
174742
  * volume (e.g. 191 for 75%) with a stale onLevel value, causing Google
174601
174743
  * Home to display the wrong percentage (Issue #79).
174602
174744
  */
@@ -174943,7 +175085,7 @@ var AirQualitySensorServerImpl = class extends AirQualityServerWithFeatures {
174943
175085
  await super.initialize();
174944
175086
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
174945
175087
  this.update(homeAssistant.entity);
174946
- this.reactTo(homeAssistant.onChange, this.update);
175088
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
174947
175089
  }
174948
175090
  update(entity) {
174949
175091
  if (!entity.state || !entity.state.attributes) {
@@ -175054,7 +175196,7 @@ var CarbonMonoxideConcentrationMeasurementServer2 = class extends CarbonMonoxide
175054
175196
  await super.initialize();
175055
175197
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175056
175198
  this.update(homeAssistant.entity);
175057
- this.reactTo(homeAssistant.onChange, this.update);
175199
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175058
175200
  }
175059
175201
  update(entity) {
175060
175202
  if (!entity.state || !entity.state.attributes) {
@@ -175085,7 +175227,7 @@ var CoAirQualityServer = class extends CoAirQualityServerBase {
175085
175227
  await super.initialize();
175086
175228
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175087
175229
  this.update(homeAssistant.entity);
175088
- this.reactTo(homeAssistant.onChange, this.update);
175230
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175089
175231
  }
175090
175232
  update(entity) {
175091
175233
  const state = entity.state.state;
@@ -175125,7 +175267,7 @@ var StandalonePowerServer = class extends ElectricalPowerMeasurementServer {
175125
175267
  await super.initialize();
175126
175268
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175127
175269
  this.update(homeAssistant.entity);
175128
- this.reactTo(homeAssistant.onChange, this.update);
175270
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175129
175271
  }
175130
175272
  update(entity) {
175131
175273
  if (!entity.state || !entity.state.attributes) {
@@ -175183,7 +175325,7 @@ var StandaloneEnergyServer = class extends EnergyFeaturedBase {
175183
175325
  await super.initialize();
175184
175326
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175185
175327
  this.update(homeAssistant.entity);
175186
- this.reactTo(homeAssistant.onChange, this.update);
175328
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175187
175329
  }
175188
175330
  update(entity) {
175189
175331
  if (!entity.state || !entity.state.attributes) {
@@ -175239,7 +175381,7 @@ var FlowMeasurementServerBase = class extends FlowMeasurementServer {
175239
175381
  await super.initialize();
175240
175382
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175241
175383
  this.update(homeAssistant.entity);
175242
- this.reactTo(homeAssistant.onChange, this.update);
175384
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175243
175385
  }
175244
175386
  update(entity) {
175245
175387
  if (!entity.state || !entity.state.attributes) {
@@ -175331,7 +175473,7 @@ var FormaldehydeConcentrationMeasurementServer2 = class extends FormaldehydeConc
175331
175473
  await super.initialize();
175332
175474
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175333
175475
  this.update(homeAssistant.entity);
175334
- this.reactTo(homeAssistant.onChange, this.update);
175476
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175335
175477
  }
175336
175478
  update(entity) {
175337
175479
  if (!entity.state || !entity.state.attributes) {
@@ -175362,7 +175504,7 @@ var FormaldehydeAirQualityServer = class extends FormaldehydeAirQualityServerBas
175362
175504
  await super.initialize();
175363
175505
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175364
175506
  this.update(homeAssistant.entity);
175365
- this.reactTo(homeAssistant.onChange, this.update);
175507
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175366
175508
  }
175367
175509
  update(entity) {
175368
175510
  const state = entity.state.state;
@@ -175421,7 +175563,7 @@ var IlluminanceMeasurementServerBase = class extends IlluminanceMeasurementServe
175421
175563
  await super.initialize();
175422
175564
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175423
175565
  this.update(homeAssistant.entity);
175424
- this.reactTo(homeAssistant.onChange, this.update);
175566
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175425
175567
  }
175426
175568
  update(entity) {
175427
175569
  if (!entity.state || !entity.state.attributes) {
@@ -175505,7 +175647,7 @@ var NitrogenDioxideConcentrationMeasurementServer2 = class extends NitrogenDioxi
175505
175647
  await super.initialize();
175506
175648
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175507
175649
  this.update(homeAssistant.entity);
175508
- this.reactTo(homeAssistant.onChange, this.update);
175650
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175509
175651
  }
175510
175652
  update(entity) {
175511
175653
  if (!entity.state || !entity.state.attributes) {
@@ -175535,7 +175677,7 @@ var No2AirQualityServer = class extends No2AirQualityServerBase {
175535
175677
  await super.initialize();
175536
175678
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175537
175679
  this.update(homeAssistant.entity);
175538
- this.reactTo(homeAssistant.onChange, this.update);
175680
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175539
175681
  }
175540
175682
  update(entity) {
175541
175683
  const state = entity.state.state;
@@ -175598,7 +175740,7 @@ var OzoneConcentrationMeasurementServer2 = class extends OzoneConcentrationMeasu
175598
175740
  await super.initialize();
175599
175741
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175600
175742
  this.update(homeAssistant.entity);
175601
- this.reactTo(homeAssistant.onChange, this.update);
175743
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175602
175744
  }
175603
175745
  update(entity) {
175604
175746
  if (!entity.state || !entity.state.attributes) {
@@ -175628,7 +175770,7 @@ var OzoneAirQualityServer = class extends OzoneAirQualityServerBase {
175628
175770
  await super.initialize();
175629
175771
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175630
175772
  this.update(homeAssistant.entity);
175631
- this.reactTo(homeAssistant.onChange, this.update);
175773
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175632
175774
  }
175633
175775
  update(entity) {
175634
175776
  const state = entity.state.state;
@@ -175691,7 +175833,7 @@ var Pm1ConcentrationMeasurementServer2 = class extends Pm1ConcentrationMeasureme
175691
175833
  await super.initialize();
175692
175834
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175693
175835
  this.update(homeAssistant.entity);
175694
- this.reactTo(homeAssistant.onChange, this.update);
175836
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175695
175837
  }
175696
175838
  update(entity) {
175697
175839
  if (!entity.state || !entity.state.attributes) {
@@ -175721,7 +175863,7 @@ var Pm1AirQualityServer = class extends Pm1AirQualityServerBase {
175721
175863
  await super.initialize();
175722
175864
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175723
175865
  this.update(homeAssistant.entity);
175724
- this.reactTo(homeAssistant.onChange, this.update);
175866
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175725
175867
  }
175726
175868
  update(entity) {
175727
175869
  const state = entity.state.state;
@@ -175804,7 +175946,7 @@ var RadonConcentrationMeasurementServer2 = class extends RadonConcentrationMeasu
175804
175946
  await super.initialize();
175805
175947
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175806
175948
  this.update(homeAssistant.entity);
175807
- this.reactTo(homeAssistant.onChange, this.update);
175949
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175808
175950
  }
175809
175951
  update(entity) {
175810
175952
  if (!entity.state || !entity.state.attributes) {
@@ -175834,7 +175976,7 @@ var RadonAirQualityServer = class extends RadonAirQualityServerBase {
175834
175976
  await super.initialize();
175835
175977
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175836
175978
  this.update(homeAssistant.entity);
175837
- this.reactTo(homeAssistant.onChange, this.update);
175979
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175838
175980
  }
175839
175981
  update(entity) {
175840
175982
  const state = entity.state.state;
@@ -175952,7 +176094,7 @@ var TvocConcentrationMeasurementServer = class extends TvocConcentrationMeasurem
175952
176094
  await super.initialize();
175953
176095
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
175954
176096
  this.update(homeAssistant.entity);
175955
- this.reactTo(homeAssistant.onChange, this.update);
176097
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
175956
176098
  }
175957
176099
  update(entity) {
175958
176100
  if (!entity.state || !entity.state.attributes) {
@@ -176002,7 +176144,7 @@ var TvocAirQualityServer = class extends TvocAirQualityServerBase {
176002
176144
  await super.initialize();
176003
176145
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
176004
176146
  this.update(homeAssistant.entity);
176005
- this.reactTo(homeAssistant.onChange, this.update);
176147
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
176006
176148
  }
176007
176149
  update(entity) {
176008
176150
  if (!entity.state || !entity.state.attributes) {
@@ -176069,7 +176211,7 @@ var CarbonDioxideConcentrationMeasurementServer2 = class extends CarbonDioxideCo
176069
176211
  await super.initialize();
176070
176212
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
176071
176213
  this.update(homeAssistant.entity);
176072
- this.reactTo(homeAssistant.onChange, this.update);
176214
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
176073
176215
  }
176074
176216
  update(entity) {
176075
176217
  if (!entity.state || !entity.state.attributes) {
@@ -176102,7 +176244,7 @@ var Co2AirQualityServer = class extends Co2AirQualityServerBase {
176102
176244
  await super.initialize();
176103
176245
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
176104
176246
  this.update(homeAssistant.entity);
176105
- this.reactTo(homeAssistant.onChange, this.update);
176247
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
176106
176248
  }
176107
176249
  update(entity) {
176108
176250
  const state = entity.state.state;
@@ -176165,7 +176307,7 @@ var Pm10ConcentrationMeasurementServer2 = class extends Pm10ConcentrationMeasure
176165
176307
  await super.initialize();
176166
176308
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
176167
176309
  this.update(homeAssistant.entity);
176168
- this.reactTo(homeAssistant.onChange, this.update);
176310
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
176169
176311
  }
176170
176312
  update(entity) {
176171
176313
  if (!entity.state || !entity.state.attributes) {
@@ -176197,7 +176339,7 @@ var Pm10AirQualityServer = class extends Pm10AirQualityServerBase {
176197
176339
  await super.initialize();
176198
176340
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
176199
176341
  this.update(homeAssistant.entity);
176200
- this.reactTo(homeAssistant.onChange, this.update);
176342
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
176201
176343
  }
176202
176344
  update(entity) {
176203
176345
  const state = entity.state.state;
@@ -176269,7 +176411,7 @@ var Pm25ConcentrationMeasurementServer2 = class extends Pm25ConcentrationMeasure
176269
176411
  );
176270
176412
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
176271
176413
  this.update(homeAssistant.entity);
176272
- this.reactTo(homeAssistant.onChange, this.update);
176414
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
176273
176415
  }
176274
176416
  update(entity) {
176275
176417
  if (!entity.state || !entity.state.attributes) {
@@ -176304,7 +176446,7 @@ var Pm25AirQualityServer = class extends Pm25AirQualityServerBase {
176304
176446
  logger189.debug("Pm25AirQualityServer: after super.initialize()");
176305
176447
  const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
176306
176448
  this.update(homeAssistant.entity);
176307
- this.reactTo(homeAssistant.onChange, this.update);
176449
+ this.reactTo(homeAssistant.onChange, this.update, { offline: true });
176308
176450
  }
176309
176451
  update(entity) {
176310
176452
  const state = entity.state.state;
@@ -176601,7 +176743,7 @@ function SensorDevice(homeAssistantEntity) {
176601
176743
  if (deviceClass) {
176602
176744
  diagnosticEventBus.emit(
176603
176745
  "entity_warning",
176604
- `Sensor "${homeAssistantEntity.entity.entity_id}" has unsupported device_class "${deviceClass}" \u2014 skipped`,
176746
+ `Sensor "${homeAssistantEntity.entity.entity_id}" has unsupported device_class "${deviceClass}", skipped`,
176605
176747
  {
176606
176748
  entityId: homeAssistantEntity.entity.entity_id,
176607
176749
  details: { device_class: deviceClass }
@@ -176688,6 +176830,7 @@ init_dist();
176688
176830
  init_esm();
176689
176831
  init_home_assistant_entity_behavior();
176690
176832
  var logger190 = Logger.get("VacuumIdentifyServer");
176833
+ var IDENTIFY_BUTTON_SUFFIXES = ["_identify", "_locate", "_find_me"];
176691
176834
  var VacuumIdentifyServer = class extends IdentifyServer2 {
176692
176835
  triggerEffect(effect) {
176693
176836
  this.#locate("triggerEffect");
@@ -176702,16 +176845,40 @@ var VacuumIdentifyServer = class extends IdentifyServer2 {
176702
176845
  #locate(source) {
176703
176846
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
176704
176847
  const features2 = homeAssistant.entity.state.attributes.supported_features ?? 0;
176705
- const hasLocate = testBit(features2, VacuumDeviceFeature.LOCATE);
176706
- if (!hasLocate) {
176707
- logger190.warn(
176708
- `${source} for ${homeAssistant.entityId} \u2014 LOCATE not in supported_features (${features2}), calling vacuum.locate anyway`
176709
- );
176710
- } else {
176848
+ if (testBit(features2, VacuumDeviceFeature.LOCATE)) {
176711
176849
  logger190.info(`${source} \u2192 vacuum.locate for ${homeAssistant.entityId}`);
176850
+ homeAssistant.callAction({ action: "vacuum.locate" });
176851
+ return;
176712
176852
  }
176853
+ const sibling = this.#findIdentifyButton(homeAssistant);
176854
+ if (sibling) {
176855
+ logger190.info(
176856
+ `${source} \u2192 button.press ${sibling} for ${homeAssistant.entityId}`
176857
+ );
176858
+ homeAssistant.callAction({ action: "button.press", target: sibling });
176859
+ return;
176860
+ }
176861
+ logger190.warn(
176862
+ `${source} for ${homeAssistant.entityId}, LOCATE not in supported_features (${features2}), trying vacuum.locate anyway`
176863
+ );
176713
176864
  homeAssistant.callAction({ action: "vacuum.locate" });
176714
176865
  }
176866
+ #findIdentifyButton(homeAssistant) {
176867
+ const deviceId = homeAssistant.entity.registry?.device_id;
176868
+ if (!deviceId) return void 0;
176869
+ const registry2 = this.env.get(HomeAssistantRegistry);
176870
+ for (const entity of Object.values(registry2.entities)) {
176871
+ if (entity.device_id !== deviceId) continue;
176872
+ if (!entity.entity_id.startsWith("button.")) continue;
176873
+ const uniqueId = entity.unique_id ?? "";
176874
+ if (IDENTIFY_BUTTON_SUFFIXES.some(
176875
+ (s) => entity.entity_id.endsWith(s) || uniqueId.endsWith(s)
176876
+ )) {
176877
+ return entity.entity_id;
176878
+ }
176879
+ }
176880
+ return void 0;
176881
+ }
176715
176882
  };
176716
176883
 
176717
176884
  // src/matter/behaviors/rvc-run-mode-server.ts
@@ -176822,7 +176989,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176822
176989
  if (!currentRoomEntityId) {
176823
176990
  this.logShortCircuitOnce(
176824
176991
  "no-mapping",
176825
- "currentRoom sensor: no currentRoomEntity in mapping \u2014 auto-detect did not run or sensor not on same HA device"
176992
+ "currentRoom sensor: no currentRoomEntity in mapping, auto-detect did not run or sensor not on same HA device"
176826
176993
  );
176827
176994
  return;
176828
176995
  }
@@ -176835,26 +177002,22 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176835
177002
  );
176836
177003
  return;
176837
177004
  }
176838
- if (s.activeAreas.length === 0) {
176839
- this.logShortCircuitOnce(
176840
- "no-active-areas",
176841
- `currentRoom sensor: activeAreas empty while cleaning \u2014 sensor=${currentRoomEntityId} state="${roomState.state}"`
176842
- );
176843
- return;
176844
- }
176845
177005
  const serviceArea = this.agent.get(ServiceAreaBehavior);
177006
+ const externalSession = s.activeAreas.length === 0;
177007
+ const supportedAreaIds = serviceArea.state.supportedAreas.map(
177008
+ (a) => a.areaId
177009
+ );
177010
+ const isAllowedArea = (id) => externalSession ? supportedAreaIds.includes(id) : s.activeAreas.includes(id);
176846
177011
  const sensorAttrs = roomState.attributes;
176847
177012
  const segmentId = sensorAttrs.segment_id ?? sensorAttrs.room_id;
176848
177013
  const roomName = roomState.state;
176849
177014
  let matchedAreaId = null;
176850
- if (segmentId != null) {
176851
- if (s.activeAreas.includes(segmentId)) {
176852
- matchedAreaId = segmentId;
176853
- }
177015
+ if (segmentId != null && isAllowedArea(segmentId)) {
177016
+ matchedAreaId = segmentId;
176854
177017
  }
176855
177018
  if (matchedAreaId === null && segmentId != null) {
176856
177019
  for (const area of serviceArea.state.supportedAreas) {
176857
- if (s.activeAreas.includes(area.areaId) && area.areaId % 1e4 === segmentId) {
177020
+ if (isAllowedArea(area.areaId) && area.areaId % 1e4 === segmentId) {
176858
177021
  matchedAreaId = area.areaId;
176859
177022
  break;
176860
177023
  }
@@ -176864,7 +177027,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
176864
177027
  const area = serviceArea.state.supportedAreas.find(
176865
177028
  (a) => a.areaInfo.locationInfo?.locationName?.toLowerCase() === roomName.toLowerCase()
176866
177029
  );
176867
- if (area && s.activeAreas.includes(area.areaId)) {
177030
+ if (area && isAllowedArea(area.areaId)) {
176868
177031
  matchedAreaId = area.areaId;
176869
177032
  }
176870
177033
  }
@@ -177608,9 +177771,8 @@ function buildSupportedModes2(attributes7, includeUnnamedRooms = false, customAr
177608
177771
  }
177609
177772
  return modes;
177610
177773
  }
177611
- function handleCustomServiceAreas(selectedAreas, customAreas, homeAssistant, serviceArea) {
177774
+ function handleCustomServiceAreas(selectedAreas, customAreas, homeAssistant) {
177612
177775
  const matched = selectedAreas.map((areaId) => customAreas[areaId - 1]).filter(Boolean);
177613
- serviceArea.state.selectedAreas = [];
177614
177776
  if (matched.length === 0) {
177615
177777
  logger194.warn(
177616
177778
  `Custom service areas: no match for selected IDs ${selectedAreas.join(", ")}`
@@ -177680,14 +177842,12 @@ var vacuumRvcRunModeConfig = {
177680
177842
  return handleCustomServiceAreas(
177681
177843
  selectedAreas,
177682
177844
  customAreas,
177683
- homeAssistant,
177684
- serviceArea
177845
+ homeAssistant
177685
177846
  );
177686
177847
  }
177687
177848
  const cleanAreaRooms = homeAssistant.state.mapping?.cleanAreaRooms;
177688
177849
  if (cleanAreaRooms && cleanAreaRooms.length > 0) {
177689
177850
  const haAreaIds = resolveCleanAreaIds(selectedAreas, cleanAreaRooms);
177690
- serviceArea.state.selectedAreas = [];
177691
177851
  if (haAreaIds.length > 0) {
177692
177852
  logger194.info(
177693
177853
  `CLEAN_AREA: cleaning HA areas: ${haAreaIds.join(", ")}`
@@ -177713,7 +177873,6 @@ var vacuumRvcRunModeConfig = {
177713
177873
  logger194.info(
177714
177874
  `Roborock: Pressing button entities for selected rooms: ${buttonEntityIds.join(", ")}`
177715
177875
  );
177716
- serviceArea.state.selectedAreas = [];
177717
177876
  for (let i = 1; i < buttonEntityIds.length; i++) {
177718
177877
  homeAssistant.callAction({
177719
177878
  action: "button.press",
@@ -177728,7 +177887,6 @@ var vacuumRvcRunModeConfig = {
177728
177887
  }
177729
177888
  const vacuumEntityId = homeAssistant.entityId;
177730
177889
  if (vacuumEntityId.startsWith("vacuum.valetudo_")) {
177731
- serviceArea.state.selectedAreas = [];
177732
177890
  return buildValetudoSegmentAction(
177733
177891
  vacuumEntityId,
177734
177892
  selectedAreas,
@@ -177751,7 +177909,6 @@ var vacuumRvcRunModeConfig = {
177751
177909
  logger194.info(
177752
177910
  `Starting cleaning with selected areas: ${roomIds.join(", ")}`
177753
177911
  );
177754
- serviceArea.state.selectedAreas = [];
177755
177912
  if (isDreameVacuum(attributes7)) {
177756
177913
  if (targetMapName) {
177757
177914
  const vacName = vacuumEntityId.replace("vacuum.", "");
@@ -178209,33 +178366,24 @@ function buildSupportedModes3(fanSpeedList, mopIntensityList, cleaningModeOption
178209
178366
  }
178210
178367
  return modes;
178211
178368
  }
178212
- var CLEANING_MODE_ALIASES = {
178213
- [0 /* Sweeping */]: [
178214
- "Sweeping",
178215
- "Vacuum",
178216
- "Vacuuming",
178217
- "Sweep",
178218
- "vacuum",
178219
- "sweeping"
178220
- ],
178221
- [1 /* Mopping */]: ["Mopping", "Mop", "mopping", "mop", "wet_mop"],
178222
- [2 /* SweepingAndMopping */]: [
178223
- "Sweeping and mopping",
178224
- "Vacuum and mop",
178225
- "Vacuum & Mop",
178226
- "Vacuum & mop",
178227
- "vacuum_and_mop",
178228
- "sweeping_and_mopping"
178229
- ],
178230
- [3 /* MoppingAfterSweeping */]: [
178231
- "Mopping after sweeping",
178232
- "mopping_after_sweeping",
178233
- "Vacuum then mop",
178234
- "Mop after vacuum",
178235
- "vacuum_then_mop",
178236
- "mop_after_vacuum"
178237
- ]
178369
+ var CLEAN_TOKENS = {
178370
+ vacuum: /\b(vacuum|vacuuming|sweep|sweeping|suction)\b/i,
178371
+ mop: /\b(mop|mopping|wipe|wet|wash|scrub)\b/i,
178372
+ sequential: /\b(then|after|before|followed|following|first|secondly|sequentially)\b/i
178238
178373
  };
178374
+ function normalizeCleanLabel(s) {
178375
+ return s.toLowerCase().replace(/[_\-+&/. ]+/g, " ").replace(/\band\b/g, " ").trim();
178376
+ }
178377
+ function classifyCleanOption(option) {
178378
+ const s = normalizeCleanLabel(option);
178379
+ const hasVac = CLEAN_TOKENS.vacuum.test(s);
178380
+ const hasMop = CLEAN_TOKENS.mop.test(s);
178381
+ const hasSeq = CLEAN_TOKENS.sequential.test(s);
178382
+ if (hasVac && hasMop && hasSeq) return 3 /* MoppingAfterSweeping */;
178383
+ if (hasVac && hasMop) return 2 /* SweepingAndMopping */;
178384
+ if (hasMop) return 1 /* Mopping */;
178385
+ return 0 /* Sweeping */;
178386
+ }
178239
178387
  var CLEAN_TYPE_LABELS = {
178240
178388
  [0 /* Sweeping */]: "Sweeping",
178241
178389
  [1 /* Mopping */]: "Mopping",
@@ -178368,17 +178516,7 @@ function matchMopIntensityOption(name, availableOptions) {
178368
178516
  }
178369
178517
  function parseCleanType(modeString) {
178370
178518
  if (!modeString) return 0 /* Sweeping */;
178371
- const s = modeString.toLowerCase();
178372
- if (s.includes("mopping after") || s.includes("after sweeping") || s.includes("then_mop") || s.includes("then mop")) {
178373
- return 3 /* MoppingAfterSweeping */;
178374
- }
178375
- if (s.includes("and") || s.includes("sweeping and mopping")) {
178376
- return 2 /* SweepingAndMopping */;
178377
- }
178378
- if (s === "mopping" || s.includes("mop")) {
178379
- return 1 /* Mopping */;
178380
- }
178381
- return 0 /* Sweeping */;
178519
+ return classifyCleanOption(modeString);
178382
178520
  }
178383
178521
  function cleanTypeToModeId(ct) {
178384
178522
  switch (ct) {
@@ -178419,30 +178557,20 @@ var CLEAN_TYPE_FALLBACK = {
178419
178557
  [3 /* MoppingAfterSweeping */]: 2 /* SweepingAndMopping */
178420
178558
  };
178421
178559
  function findMatchingCleanOption(ct, availableOptions) {
178422
- const aliases = CLEANING_MODE_ALIASES[ct];
178423
- if (!availableOptions || availableOptions.length === 0) return aliases[0];
178560
+ if (!availableOptions || availableOptions.length === 0) {
178561
+ return CLEAN_TYPE_LABELS[ct];
178562
+ }
178424
178563
  const typesToTry = [ct];
178425
178564
  const fallback = CLEAN_TYPE_FALLBACK[ct];
178426
178565
  if (fallback !== void 0) typesToTry.push(fallback);
178427
178566
  for (const type of typesToTry) {
178428
- const typeAliases = CLEANING_MODE_ALIASES[type];
178429
- for (const alias of typeAliases) {
178430
- const match = availableOptions.find(
178431
- (o) => o.toLowerCase() === alias.toLowerCase()
178432
- );
178433
- if (match) return match;
178434
- }
178435
- for (const alias of typeAliases) {
178436
- const match = availableOptions.find(
178437
- (o) => o.toLowerCase().includes(alias.toLowerCase())
178438
- );
178439
- if (match) return match;
178440
- }
178567
+ const match = availableOptions.find((o) => classifyCleanOption(o) === type);
178568
+ if (match) return match;
178441
178569
  }
178442
178570
  logger196.warn(
178443
178571
  `No match for ${CLEAN_TYPE_LABELS[ct]} in [${availableOptions.join(", ")}]`
178444
178572
  );
178445
- return aliases[0];
178573
+ return availableOptions[0];
178446
178574
  }
178447
178575
  function buildCleaningModeAction(targetCleanType, agent) {
178448
178576
  const selectEntityId = getCleaningModeSelectEntity(agent);
@@ -178577,7 +178705,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
178577
178705
  const vacuumEntityId = homeAssistant.entityId;
178578
178706
  const mapping = homeAssistant.state.mapping;
178579
178707
  logger196.info(
178580
- `setCleanMode(${mode}) for ${vacuumEntityId} \u2014 suctionEntity=${mapping?.suctionLevelEntity ?? "none"}, mopEntity=${mapping?.mopIntensityEntity ?? "none"}, fanSpeedList=${JSON.stringify(fanSpeedList ?? [])}, mopIntensityList=${JSON.stringify(mopIntensityList ?? [])}, customTags=${JSON.stringify(customFanSpeedTags ?? {})}`
178708
+ `setCleanMode(${mode}) for ${vacuumEntityId}, suctionEntity=${mapping?.suctionLevelEntity ?? "none"}, mopEntity=${mapping?.mopIntensityEntity ?? "none"}, fanSpeedList=${JSON.stringify(fanSpeedList ?? [])}, mopIntensityList=${JSON.stringify(mopIntensityList ?? [])}, customTags=${JSON.stringify(customFanSpeedTags ?? {})}`
178581
178709
  );
178582
178710
  if (mopIntensityList && mopIntensityList.length > 0 && isMopIntensityMode(mode)) {
178583
178711
  const mopIndex = mode - MOP_INTENSITY_MODE_BASE;
@@ -180544,7 +180672,7 @@ var BridgeEndpointManager = class extends Service {
180544
180672
  this.mappingFingerprints.delete(endpoint.entityId);
180545
180673
  } else if (this.registry.isAutoComposedDevicesEnabled() && this.registry.isComposedSubEntityUsed(endpoint.entityId)) {
180546
180674
  this.log.info(
180547
- `Deleting standalone endpoint ${endpoint.entityId} \u2014 consumed by composed device`
180675
+ `Deleting standalone endpoint ${endpoint.entityId}, consumed by composed device`
180548
180676
  );
180549
180677
  try {
180550
180678
  await endpoint.delete();
@@ -180582,14 +180710,14 @@ var BridgeEndpointManager = class extends Service {
180582
180710
  if (!memoryLimitReached && isHeapUnderPressure()) {
180583
180711
  memoryLimitReached = true;
180584
180712
  this.log.error(
180585
- "Memory pressure detected \u2014 skipping remaining entities to prevent OOM crash. Reduce the number of entities in this bridge or increase the Node.js heap size (NODE_OPTIONS=--max-old-space-size=1024)."
180713
+ "Memory pressure detected, skipping remaining entities to prevent OOM crash. Reduce the number of entities in this bridge or increase the Node.js heap size (NODE_OPTIONS=--max-old-space-size=1024)."
180586
180714
  );
180587
180715
  }
180588
180716
  if (memoryLimitReached) {
180589
180717
  if (!existingEndpoints.some((e) => e.entityId === entityId)) {
180590
180718
  this._failedEntities.push({
180591
180719
  entityId,
180592
- reason: "Skipped due to memory pressure \u2014 reduce entities or increase heap size"
180720
+ reason: "Skipped due to memory pressure, reduce entities or increase heap size"
180593
180721
  });
180594
180722
  }
180595
180723
  continue;
@@ -180601,7 +180729,7 @@ var BridgeEndpointManager = class extends Service {
180601
180729
  }
180602
180730
  if (this.registry.isAutoComposedDevicesEnabled() && this.registry.isComposedSubEntityUsed(entityId)) {
180603
180731
  this.log.debug(
180604
- `Skipping ${entityId} \u2014 already part of a composed device`
180732
+ `Skipping ${entityId}, already part of a composed device`
180605
180733
  );
180606
180734
  continue;
180607
180735
  }
@@ -180701,7 +180829,7 @@ var BridgeEndpointManager = class extends Service {
180701
180829
  }
180702
180830
  /**
180703
180831
  * Log detailed behavior error information for debugging "Behaviors have errors".
180704
- * Matter.js EndpointBehaviorsError extends AggregateError the `errors` array
180832
+ * Matter.js EndpointBehaviorsError extends AggregateError, the `errors` array
180705
180833
  * contains individual behavior crash errors (one per failed behavior).
180706
180834
  */
180707
180835
  logDetailedError(entityId, error) {
@@ -180850,7 +180978,7 @@ var BridgeRegistry = class _BridgeRegistry {
180850
180978
  * Check if auto composed devices mode is enabled.
180851
180979
  * When enabled, temperature sensors with auto-mapped humidity/pressure/battery
180852
180980
  * build real Matter Composed Devices (BridgedNodeEndpoint with sub-endpoints)
180853
- * rather than stacking extra clusters onto a flat TemperatureSensor
180981
+ * rather than stacking extra clusters onto a flat TemperatureSensor.
180854
180982
  * Apple Home, Google Home, and Alexa render each sub-endpoint using its
180855
180983
  * own device type.
180856
180984
  */
@@ -180996,8 +181124,8 @@ var BridgeRegistry = class _BridgeRegistry {
180996
181124
  } else if (id.endsWith("_mode")) {
180997
181125
  const options = state.attributes?.options;
180998
181126
  if (options?.some(
180999
- (o) => /^(vacuum|mop|sweep|vacuum_and_mop|vacuum_then_mop|mopping|sweeping|sweeping_and_mopping|mopping_after_sweeping)$/i.test(
181000
- o
181127
+ (o) => /^(vacuum|mop|sweep|sweep_mop|sweep_before_mopping|sweep_then_mop|vacuum_and_mop|vacuum_then_mop|mopping|sweeping|sweeping_and_mopping|mopping_after_sweeping)$/i.test(
181128
+ o.replace(/\s+/g, "_")
181001
181129
  )
181002
181130
  )) {
181003
181131
  cleaningModeEntity = entity.entity_id;
@@ -181155,14 +181283,14 @@ var BridgeRegistry = class _BridgeRegistry {
181155
181283
  const segments = areaMapping[haAreaId];
181156
181284
  if (!segments || segments.length === 0) {
181157
181285
  _BridgeRegistry.cleanAreaLogger.debug(
181158
- `${entityId}: Skipping HA area ${haAreaId} \u2014 no segments mapped`
181286
+ `${entityId}: Skipping HA area ${haAreaId}, no segments mapped`
181159
181287
  );
181160
181288
  continue;
181161
181289
  }
181162
181290
  if (validSegmentIds && !segments.some((sid) => validSegmentIds.has(sid))) {
181163
181291
  const areaName2 = this.registry.areas.get(haAreaId) ?? haAreaId;
181164
181292
  _BridgeRegistry.cleanAreaLogger.info(
181165
- `${entityId}: Skipping stale HA area "${areaName2}" (${haAreaId}) \u2014 segments [${segments.join(", ")}] no longer exist on vacuum`
181293
+ `${entityId}: Skipping stale HA area "${areaName2}" (${haAreaId}), segments [${segments.join(", ")}] no longer exist on vacuum`
181166
181294
  );
181167
181295
  continue;
181168
181296
  }
@@ -181638,7 +181766,7 @@ ${e?.toString()}`);
181638
181766
  );
181639
181767
  if (totalSubs === 0 && sessions.length > 0) {
181640
181768
  this.log.warn(
181641
- `All subscriptions lost \u2014 ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
181769
+ `All subscriptions lost, ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
181642
181770
  );
181643
181771
  if (!this.deadSessionTimer) {
181644
181772
  this.deadSessionTimer = setTimeout(() => {
@@ -181677,7 +181805,7 @@ ${e?.toString()}`);
181677
181805
  for (const s of [...sessionManager.sessions]) {
181678
181806
  if (s !== newSession && !s.isClosing && s.peerNodeId === newSession.peerNodeId && s.fabric?.fabricIndex === newSession.fabric?.fabricIndex && s.subscriptions.size === 0) {
181679
181807
  this.log.info(
181680
- `Closing stale session ${s.id} (peer ${s.peerNodeId}, 0 subs) \u2014 replaced by session ${newSession.id}`
181808
+ `Closing stale session ${s.id} (peer ${s.peerNodeId}, 0 subs), replaced by session ${newSession.id}`
181681
181809
  );
181682
181810
  s.initiateForceClose().catch(() => {
181683
181811
  });
@@ -182098,7 +182226,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
182098
182226
  }
182099
182227
  }
182100
182228
  } else {
182101
- logger205.warn(`${entityId}: No device_id \u2014 cannot auto-assign battery`);
182229
+ logger205.warn(`${entityId}: No device_id, cannot auto-assign battery`);
182102
182230
  }
182103
182231
  const payload = {
182104
182232
  entity_id: entityId,
@@ -182154,7 +182282,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
182154
182282
  * Previous approaches that pushed state through
182155
182283
  * HomeAssistantEntityBehavior failed because the reactor writes
182156
182284
  * (RvcOperationalStateServer.update()) run inside the postCommit
182157
- * phase of the HAEntityBehavior transaction those writes are
182285
+ * phase of the HAEntityBehavior transaction, those writes are
182158
182286
  * buffered but never committed, so no attrsChanged event reaches
182159
182287
  * the ServerSubscription.
182160
182288
  *
@@ -182400,11 +182528,11 @@ var ServerModeEndpointManager = class extends Service {
182400
182528
  }
182401
182529
  if (isHeapUnderPressure()) {
182402
182530
  this.log.error(
182403
- "Memory pressure detected \u2014 cannot create device endpoint. Reduce entities on other bridges or increase the Node.js heap size (NODE_OPTIONS=--max-old-space-size=1024)."
182531
+ "Memory pressure detected, cannot create device endpoint. Reduce entities on other bridges or increase the Node.js heap size (NODE_OPTIONS=--max-old-space-size=1024)."
182404
182532
  );
182405
182533
  this._failedEntities.push({
182406
182534
  entityId,
182407
- reason: "Skipped due to memory pressure \u2014 reduce entities or increase heap size"
182535
+ reason: "Skipped due to memory pressure, reduce entities or increase heap size"
182408
182536
  });
182409
182537
  return;
182410
182538
  }
@@ -182794,7 +182922,7 @@ function patchLevelControlTlv() {
182794
182922
  );
182795
182923
  } else {
182796
182924
  logger206.warn(
182797
- "Failed to patch LevelControl TLV schemas \u2014 field definitions not found. Google Home brightness adjustment may not work."
182925
+ "Failed to patch LevelControl TLV schemas, field definitions not found. Google Home brightness adjustment may not work."
182798
182926
  );
182799
182927
  }
182800
182928
  }