@riddix/hamh 2.1.0-alpha.521 → 2.1.0-alpha.522

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.
@@ -1743,8 +1743,8 @@ var init_Cancelable = __esm({
1743
1743
  };
1744
1744
  return result;
1745
1745
  }
1746
- static set logger(logger203) {
1747
- this.#logger = logger203;
1746
+ static set logger(logger204) {
1747
+ this.#logger = logger204;
1748
1748
  }
1749
1749
  static get logger() {
1750
1750
  return this.#logger;
@@ -3422,13 +3422,13 @@ var init_Logger = __esm({
3422
3422
  *
3423
3423
  * @deprecated use {@link destinations}
3424
3424
  */
3425
- static addLogger(identifier, logger203, options) {
3425
+ static addLogger(identifier, logger204, options) {
3426
3426
  if (identifier in this.destinations) {
3427
3427
  throw new ImplementationError(`Logger "${identifier}" already exists`);
3428
3428
  }
3429
3429
  const dest = LogDestination({ name: identifier });
3430
3430
  const legacy = adaptDestinationToLegacy(dest);
3431
- legacy.log = logger203;
3431
+ legacy.log = logger204;
3432
3432
  if (options?.defaultLogLevel !== void 0) {
3433
3433
  legacy.defaultLogLevel = options.defaultLogLevel;
3434
3434
  }
@@ -5538,8 +5538,8 @@ function Construction(subject, initializer) {
5538
5538
  }
5539
5539
  }
5540
5540
  function unhandledError(...args) {
5541
- const logger203 = Logger.get(subject.constructor.name);
5542
- logger203.error(...args);
5541
+ const logger204 = Logger.get(subject.constructor.name);
5542
+ logger204.error(...args);
5543
5543
  }
5544
5544
  function createErrorHandler(name) {
5545
5545
  return (e) => {
@@ -135998,11 +135998,11 @@ var init_Api = __esm({
135998
135998
  }
135999
135999
  Api2.resourceFor = resourceFor;
136000
136000
  function log(level, facility, id, ...message) {
136001
- let logger203 = loggers.get(facility);
136002
- if (!logger203) {
136003
- loggers.set(facility, logger203 = Logger.get(facility));
136001
+ let logger204 = loggers.get(facility);
136002
+ if (!logger204) {
136003
+ loggers.set(facility, logger204 = Logger.get(facility));
136004
136004
  }
136005
- logger203[level](Diagnostic.via(id || "(anon)"), message);
136005
+ logger204[level](Diagnostic.via(id || "(anon)"), message);
136006
136006
  }
136007
136007
  Api2.log = log;
136008
136008
  function logRequest(facility, id, method, target) {
@@ -147221,10 +147221,10 @@ var init_home_assistant_actions = __esm({
147221
147221
  circuitBreakerResetMs: 3e4
147222
147222
  };
147223
147223
  HomeAssistantActions = class extends Service {
147224
- constructor(logger203, client, config10) {
147224
+ constructor(logger204, client, config10) {
147225
147225
  super("HomeAssistantActions");
147226
147226
  this.client = client;
147227
- this.log = logger203.get(this);
147227
+ this.log = logger204.get(this);
147228
147228
  this.config = { ...defaultConfig, ...config10 };
147229
147229
  this.circuitBreaker = new CircuitBreaker(
147230
147230
  this.config.circuitBreakerThreshold,
@@ -147596,10 +147596,10 @@ var DiagnosticService = class {
147596
147596
  };
147597
147597
 
147598
147598
  // src/api/access-log.ts
147599
- function accessLogger(logger203) {
147599
+ function accessLogger(logger204) {
147600
147600
  return (req, res, next) => {
147601
147601
  res.on("finish", () => {
147602
- logger203.debug(
147602
+ logger204.debug(
147603
147603
  `${req.method} ${decodeURI(req.originalUrl)} ${res.statusCode} ${res.statusMessage} from ${req.socket.remoteAddress}`
147604
147604
  );
147605
147605
  });
@@ -151095,7 +151095,7 @@ var WebSocketApi = class {
151095
151095
 
151096
151096
  // src/api/web-api.ts
151097
151097
  var WebApi = class extends Service {
151098
- constructor(logger203, bridgeService, haClient, haRegistry, bridgeStorage, mappingStorage, lockCredentialStorage, settingsStorage, backupService, props) {
151098
+ constructor(logger204, bridgeService, haClient, haRegistry, bridgeStorage, mappingStorage, lockCredentialStorage, settingsStorage, backupService, props) {
151099
151099
  super("WebApi");
151100
151100
  this.bridgeService = bridgeService;
151101
151101
  this.haClient = haClient;
@@ -151106,8 +151106,8 @@ var WebApi = class extends Service {
151106
151106
  this.settingsStorage = settingsStorage;
151107
151107
  this.backupService = backupService;
151108
151108
  this.props = props;
151109
- this.logger = logger203;
151110
- this.log = logger203.get(this);
151109
+ this.logger = logger204;
151110
+ this.log = logger204.get(this);
151111
151111
  this.accessLogger = accessLogger(this.log.createChild("Access Log"));
151112
151112
  this.startTime = Date.now();
151113
151113
  this.wsApi = new WebSocketApi(
@@ -151545,12 +151545,12 @@ var CustomStorage = class extends StorageBackendDisk {
151545
151545
 
151546
151546
  // src/core/app/storage.ts
151547
151547
  function storage(environment, options) {
151548
- const logger203 = environment.get(LoggerService).get("CustomStorage");
151548
+ const logger204 = environment.get(LoggerService).get("CustomStorage");
151549
151549
  const location2 = resolveStorageLocation(options.location);
151550
151550
  fs8.mkdirSync(location2, { recursive: true });
151551
151551
  const storageService = environment.get(StorageService);
151552
151552
  storageService.location = location2;
151553
- storageService.factory = (ns) => new CustomStorage(logger203, path8.resolve(location2, ns));
151553
+ storageService.factory = (ns) => new CustomStorage(logger204, path8.resolve(location2, ns));
151554
151554
  }
151555
151555
  function resolveStorageLocation(storageLocation) {
151556
151556
  const homedir = os3.homedir();
@@ -152100,10 +152100,10 @@ import {
152100
152100
  getConfig
152101
152101
  } from "home-assistant-js-websocket";
152102
152102
  var HomeAssistantClient = class extends Service {
152103
- constructor(logger203, options) {
152103
+ constructor(logger204, options) {
152104
152104
  super("HomeAssistantClient");
152105
152105
  this.options = options;
152106
- this.log = logger203.get(this);
152106
+ this.log = logger204.get(this);
152107
152107
  }
152108
152108
  static Options = /* @__PURE__ */ Symbol.for("HomeAssistantClientProps");
152109
152109
  _connection;
@@ -152696,9 +152696,10 @@ var EntityMappingStorage = class extends Service {
152696
152696
  ) ?? void 0,
152697
152697
  customFanSpeedTags: request.customFanSpeedTags && Object.keys(request.customFanSpeedTags).length > 0 ? request.customFanSpeedTags : void 0,
152698
152698
  valetudoIdentifier: request.valetudoIdentifier?.trim() || void 0,
152699
- coverSwapOpenClose: request.coverSwapOpenClose || void 0
152699
+ coverSwapOpenClose: request.coverSwapOpenClose || void 0,
152700
+ composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0
152700
152701
  };
152701
- if (!config10.matterDeviceType && !config10.customName && 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.valetudoIdentifier && !config10.coverSwapOpenClose) {
152702
+ if (!config10.matterDeviceType && !config10.customName && 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.valetudoIdentifier && !config10.coverSwapOpenClose && (!config10.composedEntities || config10.composedEntities.length === 0)) {
152702
152703
  bridgeMap.delete(request.entityId);
152703
152704
  } else {
152704
152705
  bridgeMap.set(request.entityId, config10);
@@ -166868,10 +166869,10 @@ function ensureCommissioningConfig(server) {
166868
166869
  var AUTO_FORCE_SYNC_INTERVAL_MS = 9e4;
166869
166870
  var DEAD_SESSION_TIMEOUT_MS = 6e4;
166870
166871
  var Bridge = class {
166871
- constructor(env, logger203, dataProvider, endpointManager) {
166872
+ constructor(env, logger204, dataProvider, endpointManager) {
166872
166873
  this.dataProvider = dataProvider;
166873
166874
  this.endpointManager = endpointManager;
166874
- this.log = logger203.get(`Bridge / ${dataProvider.id}`);
166875
+ this.log = logger204.get(`Bridge / ${dataProvider.id}`);
166875
166876
  this.server = new BridgeServerNode(
166876
166877
  env,
166877
166878
  this.dataProvider,
@@ -167316,7 +167317,7 @@ var AggregatorEndpoint2 = class extends Endpoint {
167316
167317
  init_dist();
167317
167318
  init_esm();
167318
167319
  init_home_assistant_entity_behavior();
167319
- import debounce4 from "debounce";
167320
+ import debounce5 from "debounce";
167320
167321
 
167321
167322
  // src/matter/endpoints/entity-endpoint.ts
167322
167323
  init_esm7();
@@ -167359,6 +167360,11 @@ function getMappedEntityIds(mapping) {
167359
167360
  if (mapping.filterLifeEntity) ids.push(mapping.filterLifeEntity);
167360
167361
  if (mapping.powerEntity) ids.push(mapping.powerEntity);
167361
167362
  if (mapping.energyEntity) ids.push(mapping.energyEntity);
167363
+ if (mapping.composedEntities) {
167364
+ for (const sub of mapping.composedEntities) {
167365
+ if (sub.entityId) ids.push(sub.entityId);
167366
+ }
167367
+ }
167362
167368
  return ids;
167363
167369
  }
167364
167370
 
@@ -169196,6 +169202,12 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
169196
169202
  }
169197
169203
  };
169198
169204
 
169205
+ // src/matter/endpoints/composed/user-composed-endpoint.ts
169206
+ init_esm();
169207
+ init_esm7();
169208
+ import debounce4 from "debounce";
169209
+ init_home_assistant_entity_behavior();
169210
+
169199
169211
  // src/matter/endpoints/legacy/air-purifier/index.ts
169200
169212
  init_dist();
169201
169213
  init_home_assistant_entity_behavior();
@@ -177908,8 +177920,190 @@ var matterDeviceTypeFactories = {
177908
177920
  })
177909
177921
  };
177910
177922
 
177923
+ // src/matter/endpoints/composed/user-composed-endpoint.ts
177924
+ var logger198 = Logger.get("UserComposedEndpoint");
177925
+ function createEndpointId4(entityId, customName) {
177926
+ const baseName = customName || entityId;
177927
+ return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
177928
+ }
177929
+ function buildEntityPayload3(registry2, entityId) {
177930
+ const state = registry2.initialState(entityId);
177931
+ if (!state) return void 0;
177932
+ const entity = registry2.entity(entityId);
177933
+ const deviceRegistry = registry2.deviceOf(entityId);
177934
+ return {
177935
+ entity_id: entityId,
177936
+ state,
177937
+ registry: entity,
177938
+ deviceRegistry
177939
+ };
177940
+ }
177941
+ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
177942
+ entityId;
177943
+ mappedEntityIds;
177944
+ subEndpoints = /* @__PURE__ */ new Map();
177945
+ lastStates = /* @__PURE__ */ new Map();
177946
+ debouncedUpdates = /* @__PURE__ */ new Map();
177947
+ static async create(config10) {
177948
+ const { registry: registry2, primaryEntityId, composedEntities } = config10;
177949
+ const primaryPayload = buildEntityPayload3(registry2, primaryEntityId);
177950
+ if (!primaryPayload) return void 0;
177951
+ let parentType = BridgedNodeEndpoint.with(
177952
+ BasicInformationServer2,
177953
+ IdentifyServer2,
177954
+ HomeAssistantEntityBehavior
177955
+ );
177956
+ if (config10.areaName) {
177957
+ const truncatedName = config10.areaName.length > 16 ? config10.areaName.substring(0, 16) : config10.areaName;
177958
+ parentType = parentType.with(
177959
+ FixedLabelServer.set({
177960
+ labelList: [{ label: "room", value: truncatedName }]
177961
+ })
177962
+ );
177963
+ }
177964
+ const endpointId = createEndpointId4(primaryEntityId, config10.customName);
177965
+ const parts = [];
177966
+ const subEndpointMap = /* @__PURE__ */ new Map();
177967
+ const mappedIds = [];
177968
+ const primaryType = createLegacyEndpointType(
177969
+ primaryPayload,
177970
+ config10.mapping,
177971
+ void 0,
177972
+ { vacuumOnOff: registry2.isVacuumOnOffEnabled() }
177973
+ );
177974
+ if (!primaryType) {
177975
+ logger198.warn(
177976
+ `Cannot create endpoint type for primary entity ${primaryEntityId}`
177977
+ );
177978
+ return void 0;
177979
+ }
177980
+ const primarySub = new Endpoint(primaryType, {
177981
+ id: `${endpointId}_primary`
177982
+ });
177983
+ parts.push(primarySub);
177984
+ subEndpointMap.set(primaryEntityId, primarySub);
177985
+ for (let i = 0; i < composedEntities.length; i++) {
177986
+ const sub = composedEntities[i];
177987
+ if (!sub.entityId) continue;
177988
+ const subPayload = buildEntityPayload3(registry2, sub.entityId);
177989
+ if (!subPayload) {
177990
+ logger198.warn(
177991
+ `Cannot find entity state for composed sub-entity ${sub.entityId}`
177992
+ );
177993
+ continue;
177994
+ }
177995
+ const subMapping = {
177996
+ entityId: sub.entityId,
177997
+ matterDeviceType: sub.matterDeviceType
177998
+ };
177999
+ const subType = createLegacyEndpointType(subPayload, subMapping);
178000
+ if (!subType) {
178001
+ logger198.warn(
178002
+ `Cannot create endpoint type for composed sub-entity ${sub.entityId}`
178003
+ );
178004
+ continue;
178005
+ }
178006
+ const subEndpoint = new Endpoint(subType, {
178007
+ id: `${endpointId}_sub_${i}`
178008
+ });
178009
+ parts.push(subEndpoint);
178010
+ subEndpointMap.set(sub.entityId, subEndpoint);
178011
+ mappedIds.push(sub.entityId);
178012
+ }
178013
+ if (parts.length < 2) {
178014
+ logger198.warn(
178015
+ `User composed device ${primaryEntityId}: only ${parts.length} sub-endpoint(s), need at least 2 (primary + one sub-entity). Falling back to standalone.`
178016
+ );
178017
+ return void 0;
178018
+ }
178019
+ const parentTypeWithState = parentType.set({
178020
+ homeAssistantEntity: {
178021
+ entity: primaryPayload,
178022
+ customName: config10.customName,
178023
+ mapping: config10.mapping
178024
+ }
178025
+ });
178026
+ const endpoint = new _UserComposedEndpoint(
178027
+ parentTypeWithState,
178028
+ primaryEntityId,
178029
+ endpointId,
178030
+ parts,
178031
+ mappedIds
178032
+ );
178033
+ endpoint.subEndpoints = subEndpointMap;
178034
+ const labels = parts.map(
178035
+ (_, i) => i === 0 ? primaryEntityId.split(".")[0] : composedEntities[i - 1]?.entityId?.split(".")[0] ?? "?"
178036
+ ).join("+");
178037
+ logger198.info(
178038
+ `Created user composed device ${primaryEntityId}: ${parts.length} sub-endpoint(s) [${labels}]`
178039
+ );
178040
+ return endpoint;
178041
+ }
178042
+ constructor(type, entityId, id, parts, mappedEntityIds) {
178043
+ super(type, { id, parts });
178044
+ this.entityId = entityId;
178045
+ this.mappedEntityIds = mappedEntityIds;
178046
+ }
178047
+ async updateStates(states) {
178048
+ this.scheduleUpdate(this, this.entityId, states);
178049
+ for (const [entityId, sub] of this.subEndpoints) {
178050
+ this.scheduleUpdate(sub, entityId, states);
178051
+ }
178052
+ }
178053
+ scheduleUpdate(endpoint, entityId, states) {
178054
+ const state = states[entityId];
178055
+ if (!state) return;
178056
+ const key = endpoint === this ? `_parent_:${entityId}` : entityId;
178057
+ const stateJson = JSON.stringify({
178058
+ s: state.state,
178059
+ a: state.attributes
178060
+ });
178061
+ if (this.lastStates.get(key) === stateJson) return;
178062
+ this.lastStates.set(key, stateJson);
178063
+ let debouncedFn = this.debouncedUpdates.get(key);
178064
+ if (!debouncedFn) {
178065
+ debouncedFn = debounce4(
178066
+ (ep, s) => this.flushUpdate(ep, s),
178067
+ 50
178068
+ );
178069
+ this.debouncedUpdates.set(key, debouncedFn);
178070
+ }
178071
+ debouncedFn(endpoint, state);
178072
+ }
178073
+ async flushUpdate(endpoint, state) {
178074
+ try {
178075
+ await endpoint.construction.ready;
178076
+ } catch {
178077
+ return;
178078
+ }
178079
+ try {
178080
+ const current = endpoint.stateOf(HomeAssistantEntityBehavior).entity;
178081
+ await endpoint.setStateOf(HomeAssistantEntityBehavior, {
178082
+ entity: { ...current, state }
178083
+ });
178084
+ } catch (error) {
178085
+ if (error instanceof TransactionDestroyedError || error instanceof DestroyedDependencyError) {
178086
+ return;
178087
+ }
178088
+ const errorMessage = error instanceof Error ? error.message : String(error);
178089
+ if (errorMessage.includes(
178090
+ "Endpoint storage inaccessible because endpoint is not a node and is not owned by another endpoint"
178091
+ )) {
178092
+ return;
178093
+ }
178094
+ throw error;
178095
+ }
178096
+ }
178097
+ async delete() {
178098
+ for (const fn of this.debouncedUpdates.values()) {
178099
+ fn.clear();
178100
+ }
178101
+ await super.delete();
178102
+ }
178103
+ };
178104
+
177911
178105
  // src/matter/endpoints/legacy/legacy-endpoint.ts
177912
- var logger198 = Logger.get("LegacyEndpoint");
178106
+ var logger199 = Logger.get("LegacyEndpoint");
177913
178107
  var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
177914
178108
  static async create(registry2, entityId, mapping) {
177915
178109
  const deviceRegistry = registry2.deviceOf(entityId);
@@ -177919,25 +178113,25 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
177919
178113
  return;
177920
178114
  }
177921
178115
  if (registry2.isAutoBatteryMappingEnabled() && registry2.isBatteryEntityUsed(entityId)) {
177922
- logger198.debug(
178116
+ logger199.debug(
177923
178117
  `Skipping ${entityId} - already auto-assigned as battery to another device`
177924
178118
  );
177925
178119
  return;
177926
178120
  }
177927
178121
  if (registry2.isAutoHumidityMappingEnabled() && registry2.isHumidityEntityUsed(entityId)) {
177928
- logger198.debug(
178122
+ logger199.debug(
177929
178123
  `Skipping ${entityId} - already auto-assigned as humidity to a temperature sensor`
177930
178124
  );
177931
178125
  return;
177932
178126
  }
177933
178127
  if (registry2.isAutoPressureMappingEnabled() && registry2.isPressureEntityUsed(entityId)) {
177934
- logger198.debug(
178128
+ logger199.debug(
177935
178129
  `Skipping ${entityId} - already auto-assigned as pressure to a temperature sensor`
177936
178130
  );
177937
178131
  return;
177938
178132
  }
177939
178133
  if (registry2.isAutoComposedDevicesEnabled() && registry2.isComposedSubEntityUsed(entityId)) {
177940
- logger198.debug(
178134
+ logger199.debug(
177941
178135
  `Skipping ${entityId} - already consumed by a composed device`
177942
178136
  );
177943
178137
  return;
@@ -177957,7 +178151,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
177957
178151
  humidityEntity: humidityEntityId
177958
178152
  };
177959
178153
  registry2.markHumidityEntityUsed(humidityEntityId);
177960
- logger198.debug(
178154
+ logger199.debug(
177961
178155
  `Auto-assigned humidity ${humidityEntityId} to ${entityId}`
177962
178156
  );
177963
178157
  }
@@ -177976,7 +178170,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
177976
178170
  pressureEntity: pressureEntityId
177977
178171
  };
177978
178172
  registry2.markPressureEntityUsed(pressureEntityId);
177979
- logger198.debug(
178173
+ logger199.debug(
177980
178174
  `Auto-assigned pressure ${pressureEntityId} to ${entityId}`
177981
178175
  );
177982
178176
  }
@@ -177994,7 +178188,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
177994
178188
  batteryEntity: batteryEntityId
177995
178189
  };
177996
178190
  registry2.markBatteryEntityUsed(batteryEntityId);
177997
- logger198.debug(
178191
+ logger199.debug(
177998
178192
  `Auto-assigned battery ${batteryEntityId} to ${entityId}`
177999
178193
  );
178000
178194
  }
@@ -178012,7 +178206,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178012
178206
  powerEntity: powerEntityId
178013
178207
  };
178014
178208
  registry2.markPowerEntityUsed(powerEntityId);
178015
- logger198.debug(`Auto-assigned power ${powerEntityId} to ${entityId}`);
178209
+ logger199.debug(`Auto-assigned power ${powerEntityId} to ${entityId}`);
178016
178210
  }
178017
178211
  }
178018
178212
  }
@@ -178029,7 +178223,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178029
178223
  energyEntity: energyEntityId
178030
178224
  };
178031
178225
  registry2.markEnergyEntityUsed(energyEntityId);
178032
- logger198.debug(
178226
+ logger199.debug(
178033
178227
  `Auto-assigned energy ${energyEntityId} to ${entityId}`
178034
178228
  );
178035
178229
  }
@@ -178045,7 +178239,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178045
178239
  entityId: effectiveMapping?.entityId ?? entityId,
178046
178240
  cleaningModeEntity: vacuumEntities.cleaningModeEntity
178047
178241
  };
178048
- logger198.debug(
178242
+ logger199.debug(
178049
178243
  `Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity} to ${entityId}`
178050
178244
  );
178051
178245
  }
@@ -178055,7 +178249,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178055
178249
  entityId: effectiveMapping?.entityId ?? entityId,
178056
178250
  suctionLevelEntity: vacuumEntities.suctionLevelEntity
178057
178251
  };
178058
- logger198.debug(
178252
+ logger199.debug(
178059
178253
  `Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity} to ${entityId}`
178060
178254
  );
178061
178255
  }
@@ -178065,7 +178259,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178065
178259
  entityId: effectiveMapping?.entityId ?? entityId,
178066
178260
  mopIntensityEntity: vacuumEntities.mopIntensityEntity
178067
178261
  };
178068
- logger198.debug(
178262
+ logger199.debug(
178069
178263
  `Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity} to ${entityId}`
178070
178264
  );
178071
178265
  }
@@ -178080,7 +178274,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178080
178274
  entityId: effectiveMapping?.entityId ?? entityId,
178081
178275
  cleanAreaRooms
178082
178276
  };
178083
- logger198.debug(
178277
+ logger199.debug(
178084
178278
  `Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA for ${entityId}`
178085
178279
  );
178086
178280
  }
@@ -178101,7 +178295,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178101
178295
  rooms: roomsObj
178102
178296
  }
178103
178297
  };
178104
- logger198.debug(
178298
+ logger199.debug(
178105
178299
  `Auto-detected ${valetudoRooms.length} Valetudo segments for ${entityId}`
178106
178300
  );
178107
178301
  } else {
@@ -178118,7 +178312,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178118
178312
  rooms: roomsObj
178119
178313
  }
178120
178314
  };
178121
- logger198.debug(
178315
+ logger199.debug(
178122
178316
  `Auto-detected ${roborockRooms.length} Roborock rooms for ${entityId}`
178123
178317
  );
178124
178318
  }
@@ -178126,6 +178320,23 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178126
178320
  }
178127
178321
  }
178128
178322
  }
178323
+ if (registry2.isAutoComposedDevicesEnabled() && effectiveMapping?.composedEntities && effectiveMapping.composedEntities.length > 0) {
178324
+ const composedAreaName = registry2.getAreaName(entityId);
178325
+ const composed = await UserComposedEndpoint.create({
178326
+ registry: registry2,
178327
+ primaryEntityId: entityId,
178328
+ mapping: effectiveMapping,
178329
+ composedEntities: effectiveMapping.composedEntities,
178330
+ customName: effectiveMapping?.customName,
178331
+ areaName: composedAreaName
178332
+ });
178333
+ if (composed) {
178334
+ return composed;
178335
+ }
178336
+ logger199.warn(
178337
+ `User composed device creation failed for ${entityId}, falling back to standalone`
178338
+ );
178339
+ }
178129
178340
  if (registry2.isAutoComposedDevicesEnabled()) {
178130
178341
  const attrs = state.attributes;
178131
178342
  if (entityId.startsWith("sensor.") && attrs.device_class === SensorDeviceClass.temperature && (effectiveMapping?.humidityEntity || effectiveMapping?.pressureEntity)) {
@@ -178200,7 +178411,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178200
178411
  }
178201
178412
  constructor(type, entityId, customName, mappedEntityIds) {
178202
178413
  super(type, entityId, customName, mappedEntityIds);
178203
- this.flushUpdate = debounce4(this.flushPendingUpdate.bind(this), 50);
178414
+ this.flushUpdate = debounce5(this.flushPendingUpdate.bind(this), 50);
178204
178415
  }
178205
178416
  lastState;
178206
178417
  pendingMappedChange = false;
@@ -178217,11 +178428,11 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
178217
178428
  }
178218
178429
  if (mappedChanged) {
178219
178430
  this.pendingMappedChange = true;
178220
- logger198.debug(
178431
+ logger199.debug(
178221
178432
  `Mapped entity change detected for ${this.entityId}, forcing update`
178222
178433
  );
178223
178434
  }
178224
- logger198.debug(
178435
+ logger199.debug(
178225
178436
  `State update received for ${this.entityId}: state=${state.state}`
178226
178437
  );
178227
178438
  this.lastState = state;
@@ -178265,7 +178476,7 @@ import {
178265
178476
  getCollection
178266
178477
  } from "home-assistant-js-websocket";
178267
178478
  import { atLeastHaVersion } from "home-assistant-js-websocket/dist/util.js";
178268
- var logger199 = Logger.get("SubscribeEntities");
178479
+ var logger200 = Logger.get("SubscribeEntities");
178269
178480
  function processEvent(store, updates) {
178270
178481
  const state = { ...store.state };
178271
178482
  if (updates.a) {
@@ -178291,7 +178502,7 @@ function processEvent(store, updates) {
178291
178502
  for (const entityId in updates.c) {
178292
178503
  let entityState = state[entityId];
178293
178504
  if (!entityState) {
178294
- logger199.warn("Received state update for unknown entity", entityId);
178505
+ logger200.warn("Received state update for unknown entity", entityId);
178295
178506
  continue;
178296
178507
  }
178297
178508
  entityState = { ...entityState };
@@ -178361,7 +178572,7 @@ var subscribeEntities = (conn, onChange, entityIds) => entitiesColl(conn, entity
178361
178572
 
178362
178573
  // src/services/bridges/entity-isolation-service.ts
178363
178574
  init_esm();
178364
- var logger200 = Logger.get("EntityIsolation");
178575
+ var logger201 = Logger.get("EntityIsolation");
178365
178576
  var EntityIsolationServiceImpl = class {
178366
178577
  isolatedEntities = /* @__PURE__ */ new Map();
178367
178578
  isolationCallbacks = /* @__PURE__ */ new Map();
@@ -178426,13 +178637,13 @@ var EntityIsolationServiceImpl = class {
178426
178637
  }
178427
178638
  const parsed = this.parseEndpointPath(msg);
178428
178639
  if (!parsed) {
178429
- logger200.warn("Could not parse entity from error:", msg);
178640
+ logger201.warn("Could not parse entity from error:", msg);
178430
178641
  return false;
178431
178642
  }
178432
178643
  const { bridgeId, entityName } = parsed;
178433
178644
  const callback = this.isolationCallbacks.get(bridgeId);
178434
178645
  if (!callback) {
178435
- logger200.warn(
178646
+ logger201.warn(
178436
178647
  `No isolation callback registered for bridge ${bridgeId}, entity: ${entityName}`
178437
178648
  );
178438
178649
  return false;
@@ -178443,14 +178654,14 @@ var EntityIsolationServiceImpl = class {
178443
178654
  }
178444
178655
  const reason = `${classification}. Entity isolated to protect bridge stability.`;
178445
178656
  this.isolatedEntities.set(key, { entityId: entityName, reason });
178446
- logger200.warn(
178657
+ logger201.warn(
178447
178658
  `Isolating entity "${entityName}" from bridge ${bridgeId} due to: ${reason}`
178448
178659
  );
178449
178660
  try {
178450
178661
  await callback(entityName);
178451
178662
  return true;
178452
178663
  } catch (e) {
178453
- logger200.error(`Failed to isolate entity ${entityName}:`, e);
178664
+ logger201.error(`Failed to isolate entity ${entityName}:`, e);
178454
178665
  return false;
178455
178666
  }
178456
178667
  }
@@ -178749,8 +178960,15 @@ var BridgeEndpointManager = class extends Service {
178749
178960
  this.entityIds = this.registry.entityIds;
178750
178961
  if (this.registry.isAutoComposedDevicesEnabled()) {
178751
178962
  for (const eid of this.entityIds) {
178752
- if (!eid.startsWith("fan.")) continue;
178753
178963
  const m = this.getEntityMapping(eid);
178964
+ if (m?.composedEntities) {
178965
+ for (const sub of m.composedEntities) {
178966
+ if (sub.entityId) {
178967
+ this.registry.markComposedSubEntityUsed(sub.entityId);
178968
+ }
178969
+ }
178970
+ }
178971
+ if (!eid.startsWith("fan.")) continue;
178754
178972
  const matterType = m?.matterDeviceType ?? "fan";
178755
178973
  if (matterType !== "air_purifier") continue;
178756
178974
  const ent = this.registry.entity(eid);
@@ -179604,11 +179822,11 @@ init_dist();
179604
179822
  var AUTO_FORCE_SYNC_INTERVAL_MS2 = 9e4;
179605
179823
  var DEAD_SESSION_TIMEOUT_MS2 = 6e4;
179606
179824
  var ServerModeBridge = class {
179607
- constructor(logger203, dataProvider, endpointManager, server) {
179825
+ constructor(logger204, dataProvider, endpointManager, server) {
179608
179826
  this.dataProvider = dataProvider;
179609
179827
  this.endpointManager = endpointManager;
179610
179828
  this.server = server;
179611
- this.log = logger203.get(`ServerModeBridge / ${dataProvider.id}`);
179829
+ this.log = logger204.get(`ServerModeBridge / ${dataProvider.id}`);
179612
179830
  }
179613
179831
  log;
179614
179832
  status = {
@@ -180033,7 +180251,7 @@ init_service();
180033
180251
  // src/matter/endpoints/server-mode-vacuum-endpoint.ts
180034
180252
  init_esm();
180035
180253
  init_home_assistant_entity_behavior();
180036
- import debounce5 from "debounce";
180254
+ import debounce6 from "debounce";
180037
180255
 
180038
180256
  // src/matter/endpoints/legacy/vacuum/server-mode-vacuum-device.ts
180039
180257
  init_home_assistant_entity_behavior();
@@ -180097,7 +180315,7 @@ function ServerModeVacuumDevice(homeAssistantEntity, includeOnOff = false, clean
180097
180315
  }
180098
180316
 
180099
180317
  // src/matter/endpoints/server-mode-vacuum-endpoint.ts
180100
- var logger201 = Logger.get("ServerModeVacuumEndpoint");
180318
+ var logger202 = Logger.get("ServerModeVacuumEndpoint");
180101
180319
  var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEndpoint {
180102
180320
  static async create(registry2, entityId, mapping) {
180103
180321
  const deviceRegistry = registry2.deviceOf(entityId);
@@ -180107,7 +180325,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180107
180325
  return void 0;
180108
180326
  }
180109
180327
  let effectiveMapping = mapping;
180110
- logger201.info(
180328
+ logger202.info(
180111
180329
  `${entityId}: device_id=${entity.device_id}, manualBattery=${mapping?.batteryEntity ?? "none"}`
180112
180330
  );
180113
180331
  if (entity.device_id) {
@@ -180122,15 +180340,15 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180122
180340
  batteryEntity: batteryEntityId
180123
180341
  };
180124
180342
  registry2.markBatteryEntityUsed(batteryEntityId);
180125
- logger201.info(`${entityId}: Auto-assigned battery ${batteryEntityId}`);
180343
+ logger202.info(`${entityId}: Auto-assigned battery ${batteryEntityId}`);
180126
180344
  } else {
180127
180345
  const attrs = state.attributes;
180128
180346
  if (attrs.battery_level != null || attrs.battery != null) {
180129
- logger201.info(
180347
+ logger202.info(
180130
180348
  `${entityId}: No battery entity found, using battery attribute from vacuum state`
180131
180349
  );
180132
180350
  } else {
180133
- logger201.warn(
180351
+ logger202.warn(
180134
180352
  `${entityId}: No battery entity found for device ${entity.device_id}`
180135
180353
  );
180136
180354
  }
@@ -180145,7 +180363,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180145
180363
  entityId: effectiveMapping?.entityId ?? entityId,
180146
180364
  cleaningModeEntity: vacuumEntities.cleaningModeEntity
180147
180365
  };
180148
- logger201.info(
180366
+ logger202.info(
180149
180367
  `${entityId}: Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity}`
180150
180368
  );
180151
180369
  }
@@ -180155,7 +180373,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180155
180373
  entityId: effectiveMapping?.entityId ?? entityId,
180156
180374
  suctionLevelEntity: vacuumEntities.suctionLevelEntity
180157
180375
  };
180158
- logger201.info(
180376
+ logger202.info(
180159
180377
  `${entityId}: Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity}`
180160
180378
  );
180161
180379
  }
@@ -180165,7 +180383,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180165
180383
  entityId: effectiveMapping?.entityId ?? entityId,
180166
180384
  mopIntensityEntity: vacuumEntities.mopIntensityEntity
180167
180385
  };
180168
- logger201.info(
180386
+ logger202.info(
180169
180387
  `${entityId}: Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity}`
180170
180388
  );
180171
180389
  }
@@ -180180,7 +180398,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180180
180398
  entityId: effectiveMapping?.entityId ?? entityId,
180181
180399
  cleanAreaRooms
180182
180400
  };
180183
- logger201.info(
180401
+ logger202.info(
180184
180402
  `${entityId}: Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA`
180185
180403
  );
180186
180404
  }
@@ -180201,7 +180419,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180201
180419
  rooms: roomsObj
180202
180420
  }
180203
180421
  };
180204
- logger201.info(
180422
+ logger202.info(
180205
180423
  `${entityId}: Auto-detected ${valetudoRooms.length} Valetudo segments`
180206
180424
  );
180207
180425
  } else {
@@ -180218,14 +180436,14 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180218
180436
  rooms: roomsObj
180219
180437
  }
180220
180438
  };
180221
- logger201.info(
180439
+ logger202.info(
180222
180440
  `${entityId}: Auto-detected ${roborockRooms.length} Roborock rooms`
180223
180441
  );
180224
180442
  }
180225
180443
  }
180226
180444
  }
180227
180445
  } else {
180228
- logger201.warn(`${entityId}: No device_id \u2014 cannot auto-assign battery`);
180446
+ logger202.warn(`${entityId}: No device_id \u2014 cannot auto-assign battery`);
180229
180447
  }
180230
180448
  const payload = {
180231
180449
  entity_id: entityId,
@@ -180275,7 +180493,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180275
180493
  flushUpdate;
180276
180494
  constructor(type, entityId, customName, mappedEntityIds) {
180277
180495
  super(type, entityId, customName, mappedEntityIds);
180278
- this.flushUpdate = debounce5(this.flushPendingUpdate.bind(this), 50);
180496
+ this.flushUpdate = debounce6(this.flushPendingUpdate.bind(this), 50);
180279
180497
  }
180280
180498
  async delete() {
180281
180499
  this.flushUpdate.clear();
@@ -180289,11 +180507,11 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
180289
180507
  }
180290
180508
  if (mappedChanged) {
180291
180509
  this.pendingMappedChange = true;
180292
- logger201.debug(
180510
+ logger202.debug(
180293
180511
  `Mapped entity change detected for ${this.entityId}, forcing update`
180294
180512
  );
180295
180513
  }
180296
- logger201.debug(
180514
+ logger202.debug(
180297
180515
  `State update received for ${this.entityId}: state=${state.state}`
180298
180516
  );
180299
180517
  this.lastState = state;
@@ -180707,10 +180925,10 @@ var BridgeEnvironmentFactory = class extends BridgeFactory {
180707
180925
  // src/core/ioc/app-environment.ts
180708
180926
  var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
180709
180927
  constructor(rootEnv, options) {
180710
- const logger203 = rootEnv.get(LoggerService);
180928
+ const logger204 = rootEnv.get(LoggerService);
180711
180929
  super({
180712
180930
  id: "App",
180713
- log: logger203.get("AppContainer"),
180931
+ log: logger204.get("AppContainer"),
180714
180932
  parent: rootEnv
180715
180933
  });
180716
180934
  this.options = options;
@@ -180723,8 +180941,8 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
180723
180941
  }
180724
180942
  construction;
180725
180943
  async init() {
180726
- const logger203 = this.get(LoggerService);
180727
- this.set(LoggerService, logger203);
180944
+ const logger204 = this.get(LoggerService);
180945
+ this.set(LoggerService, logger204);
180728
180946
  this.set(AppStorage, new AppStorage(await this.load(StorageService)));
180729
180947
  this.set(BridgeStorage, new BridgeStorage(await this.load(AppStorage)));
180730
180948
  this.set(
@@ -180741,7 +180959,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
180741
180959
  );
180742
180960
  this.set(
180743
180961
  HomeAssistantClient,
180744
- new HomeAssistantClient(logger203, this.options.homeAssistant)
180962
+ new HomeAssistantClient(logger204, this.options.homeAssistant)
180745
180963
  );
180746
180964
  this.set(
180747
180965
  HomeAssistantConfig,
@@ -180749,7 +180967,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
180749
180967
  );
180750
180968
  this.set(
180751
180969
  HomeAssistantActions,
180752
- new HomeAssistantActions(logger203, await this.load(HomeAssistantClient))
180970
+ new HomeAssistantActions(logger204, await this.load(HomeAssistantClient))
180753
180971
  );
180754
180972
  this.set(
180755
180973
  HomeAssistantRegistry,
@@ -180785,7 +181003,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
180785
181003
  this.set(
180786
181004
  WebApi,
180787
181005
  new WebApi(
180788
- logger203,
181006
+ logger204,
180789
181007
  await this.load(BridgeService),
180790
181008
  await this.load(HomeAssistantClient),
180791
181009
  await this.load(HomeAssistantRegistry),
@@ -180811,7 +181029,7 @@ init_nodejs();
180811
181029
  init_level_control();
180812
181030
 
180813
181031
  // src/matter/patches/patch-level-control-tlv.ts
180814
- var logger202 = Logger.get("PatchLevelControlTlv");
181032
+ var logger203 = Logger.get("PatchLevelControlTlv");
180815
181033
  function patchLevelControlTlv() {
180816
181034
  let patched = 0;
180817
181035
  const moveToLevelFields = LevelControl3.TlvMoveToLevelRequest.fieldDefinitions;
@@ -180825,11 +181043,11 @@ function patchLevelControlTlv() {
180825
181043
  patched++;
180826
181044
  }
180827
181045
  if (patched > 0) {
180828
- logger202.info(
181046
+ logger203.info(
180829
181047
  `Patched ${patched} LevelControl TLV schema(s): transitionTime is now optional (Google Home compatibility)`
180830
181048
  );
180831
181049
  } else {
180832
- logger202.warn(
181050
+ logger203.warn(
180833
181051
  "Failed to patch LevelControl TLV schemas \u2014 field definitions not found. Google Home brightness adjustment may not work."
180834
181052
  );
180835
181053
  }