@riddix/hamh 2.1.0-alpha.605 → 2.1.0-alpha.607

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.
@@ -146794,6 +146794,12 @@ var init_bridge_config_schema = __esm({
146794
146794
  type: "boolean",
146795
146795
  default: false
146796
146796
  },
146797
+ preferEntityRegistryName: {
146798
+ title: "Prefer Entity Registry Name (HA 2026.4 workaround)",
146799
+ 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.",
146800
+ type: "boolean",
146801
+ default: false
146802
+ },
146797
146803
  vacuumOnOff: {
146798
146804
  title: "Vacuum: Include OnOff Cluster (Alexa)",
146799
146805
  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.",
@@ -146858,6 +146864,12 @@ var init_bridge_config_schema = __esm({
146858
146864
  minimum: 1,
146859
146865
  maximum: 999
146860
146866
  },
146867
+ serialNumberSuffix: {
146868
+ title: "Serial Number Suffix",
146869
+ type: "string",
146870
+ description: "Append a suffix to every entity serial number on this bridge. Useful for forcing controllers like Aqara to treat devices as new and bypass cached device data. Leave empty for default behavior.",
146871
+ maxLength: 16
146872
+ },
146861
146873
  filter: homeAssistantFilterSchema,
146862
146874
  featureFlags: featureFlagSchema
146863
146875
  },
@@ -165146,6 +165158,11 @@ function deepEqual(a, b) {
165146
165158
  return a === b;
165147
165159
  }
165148
165160
 
165161
+ // src/utils/sanitize-matter-string.ts
165162
+ function sanitizeMatterString(value) {
165163
+ return value.replace(/[*!~\x00-\x1f\x7f]/g, "").trim();
165164
+ }
165165
+
165149
165166
  // src/utils/trim-to-length.ts
165150
165167
  function trimToLength(value, maxLength, suffix) {
165151
165168
  const stringValue = value?.toString();
@@ -165162,6 +165179,7 @@ function trimToLength(value, maxLength, suffix) {
165162
165179
  var ServerModeServerNode = class extends ServerNode {
165163
165180
  deviceEndpoint;
165164
165181
  featureFlags;
165182
+ serialNumberSuffix;
165165
165183
  constructor(env, bridgeData) {
165166
165184
  super({
165167
165185
  id: bridgeData.id,
@@ -165191,6 +165209,7 @@ var ServerModeServerNode = class extends ServerNode {
165191
165209
  }
165192
165210
  });
165193
165211
  this.featureFlags = bridgeData.featureFlags;
165212
+ this.serialNumberSuffix = bridgeData.serialNumberSuffix;
165194
165213
  }
165195
165214
  /**
165196
165215
  * Add the device endpoint to this server node.
@@ -165219,13 +165238,15 @@ var ServerModeServerNode = class extends ServerNode {
165219
165238
  */
165220
165239
  updateDeviceIdentity(entityId, device, mapping, friendlyName) {
165221
165240
  const nodeLabel = trimToLength(mapping?.customName, 32, "...") ?? trimToLength(friendlyName, 32, "...") ?? trimToLength(entityId, 32, "...");
165222
- const productNameFromNodeLabel = this.featureFlags?.productNameFromNodeLabel === true ? nodeLabel : void 0;
165241
+ const productNameFromNodeLabel = this.featureFlags?.productNameFromNodeLabel === true ? trimToLength(sanitizeMatterString(nodeLabel ?? ""), 32, "...") ?? void 0 : void 0;
165242
+ const rawSerial = trimToLength(mapping?.customSerialNumber, 32, "...");
165243
+ const serialNumber = rawSerial && this.serialNumberSuffix ? trimToLength(`${rawSerial}${this.serialNumberSuffix}`, 32, "...") : rawSerial;
165223
165244
  applyPatchState(this.state.basicInformation, {
165224
165245
  vendorName: trimToLength(mapping?.customVendorName, 32, "...") ?? trimToLength(device?.manufacturer, 32, "..."),
165225
165246
  productName: trimToLength(mapping?.customProductName, 32, "...") ?? productNameFromNodeLabel ?? trimToLength(device?.model_id, 32, "...") ?? trimToLength(device?.model, 32, "..."),
165226
165247
  productLabel: trimToLength(device?.model, 64, "..."),
165227
165248
  nodeLabel,
165228
- serialNumber: trimToLength(mapping?.customSerialNumber, 32, "..."),
165249
+ serialNumber,
165229
165250
  hardwareVersionString: trimToLength(device?.hw_version, 64, "..."),
165230
165251
  softwareVersionString: trimToLength(device?.sw_version, 64, "...")
165231
165252
  });
@@ -166299,6 +166320,9 @@ var BridgeDataProvider = class extends Service {
166299
166320
  get priority() {
166300
166321
  return this.data.priority;
166301
166322
  }
166323
+ get serialNumberSuffix() {
166324
+ return this.data.serialNumberSuffix;
166325
+ }
166302
166326
  /************************************************
166303
166327
  * Functions
166304
166328
  ************************************************/
@@ -166323,6 +166347,7 @@ var BridgeDataProvider = class extends Service {
166323
166347
  countryCode: this.countryCode,
166324
166348
  icon: this.icon,
166325
166349
  priority: this.priority,
166350
+ serialNumberSuffix: this.serialNumberSuffix,
166326
166351
  status: status3.code,
166327
166352
  statusReason: status3.reason,
166328
166353
  commissioning: commissioning ? {
@@ -168101,8 +168126,12 @@ var BasicInformationServer2 = class extends BridgedDeviceBasicInformationServer
168101
168126
  const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
168102
168127
  const device = entity.deviceRegistry;
168103
168128
  const mapping = homeAssistant.state.mapping;
168104
- const nodeLabel = ellipse(32, homeAssistant.state.customName) ?? ellipse(32, entity.state?.attributes?.friendly_name) ?? ellipse(32, entity.entity_id);
168105
- const productNameFromNodeLabel = featureFlags?.productNameFromNodeLabel === true ? nodeLabel : void 0;
168129
+ const registryName = featureFlags?.preferEntityRegistryName ? entity.registry?.name ?? entity.registry?.original_name : void 0;
168130
+ const nodeLabel = ellipse(32, homeAssistant.state.customName) ?? ellipse(32, registryName) ?? ellipse(32, entity.state?.attributes?.friendly_name) ?? ellipse(32, entity.entity_id);
168131
+ const productNameFromNodeLabel = featureFlags?.productNameFromNodeLabel === true ? ellipse(32, sanitizeMatterString(nodeLabel ?? "")) ?? void 0 : void 0;
168132
+ const serialNumberSuffix = this.env.get(BridgeDataProvider).serialNumberSuffix;
168133
+ const rawSerial = ellipse(32, mapping?.customSerialNumber) ?? hash(32, entity.entity_id);
168134
+ const serialNumber = serialNumberSuffix ? ellipse(32, `${rawSerial}${serialNumberSuffix}`) : rawSerial;
168106
168135
  applyPatchState(this.state, {
168107
168136
  vendorId: VendorId(basicInformation.vendorId),
168108
168137
  vendorName: ellipse(32, mapping?.customVendorName) ?? ellipse(32, device?.manufacturer) ?? hash(32, basicInformation.vendorName),
@@ -168114,7 +168143,7 @@ var BasicInformationServer2 = class extends BridgedDeviceBasicInformationServer
168114
168143
  softwareVersionString: ellipse(64, device?.sw_version),
168115
168144
  nodeLabel,
168116
168145
  reachable: entity.state?.state != null && entity.state.state !== "unavailable",
168117
- serialNumber: ellipse(32, mapping?.customSerialNumber) ?? hash(32, entity.entity_id),
168146
+ serialNumber,
168118
168147
  // UniqueId helps controllers (especially Alexa) identify devices across
168119
168148
  // multiple fabric connections. Using MD5 hash of entity_id for stability.
168120
168149
  uniqueId: crypto6.createHash("md5").update(entity.entity_id).digest("hex").substring(0, 32)