@riddix/hamh 2.1.0-alpha.584 → 2.1.0-alpha.585

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.
@@ -164899,6 +164899,74 @@ init_esm5();
164899
164899
  init_nodejs();
164900
164900
  init_esm3();
164901
164901
 
164902
+ // src/utils/apply-patch-state.ts
164903
+ init_esm();
164904
+ var logger157 = Logger.get("ApplyPatchState");
164905
+ function applyPatchState(state, patch, options) {
164906
+ return applyPatch(state, patch, options?.force);
164907
+ }
164908
+ function applyPatch(state, patch, force = false) {
164909
+ const actualPatch = {};
164910
+ for (const key in patch) {
164911
+ if (Object.hasOwn(patch, key)) {
164912
+ const patchValue = patch[key];
164913
+ if (patchValue !== void 0) {
164914
+ const stateValue = state[key];
164915
+ if (force || !deepEqual(stateValue, patchValue)) {
164916
+ actualPatch[key] = patchValue;
164917
+ }
164918
+ }
164919
+ }
164920
+ }
164921
+ const failedKeys = [];
164922
+ for (const key in actualPatch) {
164923
+ if (!Object.hasOwn(actualPatch, key)) continue;
164924
+ try {
164925
+ state[key] = actualPatch[key];
164926
+ } catch (e) {
164927
+ const errorMessage = e instanceof Error ? e.message : String(e);
164928
+ if (errorMessage.includes(
164929
+ "Endpoint storage inaccessible because endpoint is not a node and is not owned by another endpoint"
164930
+ )) {
164931
+ logger157.debug(
164932
+ `Suppressed endpoint storage error, patch not applied: ${JSON.stringify(actualPatch)}`
164933
+ );
164934
+ return actualPatch;
164935
+ }
164936
+ if (errorMessage.includes("synchronous-transaction-conflict")) {
164937
+ logger157.warn(
164938
+ `Transaction conflict, state update DROPPED: ${JSON.stringify(actualPatch)}`
164939
+ );
164940
+ return actualPatch;
164941
+ }
164942
+ failedKeys.push(key);
164943
+ logger157.warn(`Failed to set property '${key}': ${errorMessage}`);
164944
+ }
164945
+ }
164946
+ if (failedKeys.length > 0) {
164947
+ logger157.warn(
164948
+ `${failedKeys.length} properties failed to update: [${failedKeys.join(", ")}]`
164949
+ );
164950
+ }
164951
+ return actualPatch;
164952
+ }
164953
+ function deepEqual(a, b) {
164954
+ if (a == null || b == null) {
164955
+ return a === b;
164956
+ }
164957
+ if (typeof a !== typeof b || Array.isArray(a) !== Array.isArray(b)) {
164958
+ return false;
164959
+ }
164960
+ if (Array.isArray(a) && Array.isArray(b)) {
164961
+ return a.length === b.length && a.every((vA, idx) => deepEqual(vA, b[idx]));
164962
+ }
164963
+ if (typeof a === "object" && typeof b === "object") {
164964
+ const keys3 = Object.keys({ ...a, ...b });
164965
+ return keys3.every((key) => deepEqual(a[key], b[key]));
164966
+ }
164967
+ return a === b;
164968
+ }
164969
+
164902
164970
  // src/utils/trim-to-length.ts
164903
164971
  function trimToLength(value, maxLength, suffix) {
164904
164972
  const stringValue = value?.toString();
@@ -164962,6 +165030,23 @@ var ServerModeServerNode = class extends ServerNode {
164962
165030
  clearDevice() {
164963
165031
  this.deviceEndpoint = void 0;
164964
165032
  }
165033
+ /**
165034
+ * Update root-level BasicInformation with entity-specific data.
165035
+ * In server mode, controllers (Apple Home, Alexa) read the root node's
165036
+ * BasicInformation — not the device endpoint's BridgedDeviceBasicInformation.
165037
+ * Without this, server-mode devices show bridge defaults (e.g. "riddix" / "MatterHub").
165038
+ */
165039
+ updateDeviceIdentity(entityId, device, mapping, friendlyName) {
165040
+ applyPatchState(this.state.basicInformation, {
165041
+ vendorName: trimToLength(mapping?.customVendorName, 32, "...") ?? trimToLength(device?.manufacturer, 32, "..."),
165042
+ productName: trimToLength(mapping?.customProductName, 32, "...") ?? trimToLength(device?.model_id, 32, "...") ?? trimToLength(device?.model, 32, "..."),
165043
+ productLabel: trimToLength(device?.model, 64, "..."),
165044
+ nodeLabel: trimToLength(mapping?.customName, 32, "...") ?? trimToLength(friendlyName, 32, "...") ?? trimToLength(entityId, 32, "..."),
165045
+ serialNumber: trimToLength(mapping?.customSerialNumber, 32, "..."),
165046
+ hardwareVersionString: trimToLength(device?.hw_version, 64, "..."),
165047
+ softwareVersionString: trimToLength(device?.sw_version, 64, "...")
165048
+ });
165049
+ }
164965
165050
  async factoryReset() {
164966
165051
  await this.cancel();
164967
165052
  await this.erase();
@@ -165053,7 +165138,7 @@ init_basic_information2();
165053
165138
  init_descriptor2();
165054
165139
  init_aggregator();
165055
165140
  init_esm();
165056
- var logger157 = Logger.get("BridgedDeviceBasicInformationServer");
165141
+ var logger158 = Logger.get("BridgedDeviceBasicInformationServer");
165057
165142
  var BridgedDeviceBasicInformationServer = class extends BridgedDeviceBasicInformationBehavior {
165058
165143
  async initialize() {
165059
165144
  if (this.endpoint.lifecycle.isInstalled) {
@@ -165068,7 +165153,7 @@ var BridgedDeviceBasicInformationServer = class extends BridgedDeviceBasicInform
165068
165153
  this.state.uniqueId = BasicInformationServer.createUniqueId();
165069
165154
  }
165070
165155
  if (serialNumber !== void 0 && uniqueId === this.state.serialNumber) {
165071
- logger157.warn("uniqueId and serialNumber shall not be the same.");
165156
+ logger158.warn("uniqueId and serialNumber shall not be the same.");
165072
165157
  }
165073
165158
  }
165074
165159
  static schema = BasicInformationServer.enableUniqueIdPersistence(
@@ -165940,7 +166025,7 @@ var IdentifyServer2 = class extends IdentifyServer {
165940
166025
  // src/matter/endpoints/validate-endpoint-type.ts
165941
166026
  init_esm();
165942
166027
  init_esm7();
165943
- var logger158 = Logger.get("EndpointValidation");
166028
+ var logger159 = Logger.get("EndpointValidation");
165944
166029
  function toCamelCase(name) {
165945
166030
  return name.charAt(0).toLowerCase() + name.slice(1);
165946
166031
  }
@@ -165970,12 +166055,12 @@ function validateEndpointType(endpointType, entityId) {
165970
166055
  }
165971
166056
  const prefix = entityId ? `[${entityId}] ` : "";
165972
166057
  if (missingMandatory.length > 0) {
165973
- logger158.warn(
166058
+ logger159.warn(
165974
166059
  `${prefix}${deviceTypeModel.name} (0x${endpointType.deviceType.toString(16)}): missing mandatory clusters: ${missingMandatory.join(", ")}`
165975
166060
  );
165976
166061
  }
165977
166062
  if (availableOptional.length > 0) {
165978
- logger158.debug(
166063
+ logger159.debug(
165979
166064
  `${prefix}${deviceTypeModel.name} (0x${endpointType.deviceType.toString(16)}): optional clusters not used: ${availableOptional.join(", ")}`
165980
166065
  );
165981
166066
  }
@@ -166078,74 +166163,6 @@ var BridgeDataProvider = class extends Service {
166078
166163
  }
166079
166164
  };
166080
166165
 
166081
- // src/utils/apply-patch-state.ts
166082
- init_esm();
166083
- var logger159 = Logger.get("ApplyPatchState");
166084
- function applyPatchState(state, patch, options) {
166085
- return applyPatch(state, patch, options?.force);
166086
- }
166087
- function applyPatch(state, patch, force = false) {
166088
- const actualPatch = {};
166089
- for (const key in patch) {
166090
- if (Object.hasOwn(patch, key)) {
166091
- const patchValue = patch[key];
166092
- if (patchValue !== void 0) {
166093
- const stateValue = state[key];
166094
- if (force || !deepEqual(stateValue, patchValue)) {
166095
- actualPatch[key] = patchValue;
166096
- }
166097
- }
166098
- }
166099
- }
166100
- const failedKeys = [];
166101
- for (const key in actualPatch) {
166102
- if (!Object.hasOwn(actualPatch, key)) continue;
166103
- try {
166104
- state[key] = actualPatch[key];
166105
- } catch (e) {
166106
- const errorMessage = e instanceof Error ? e.message : String(e);
166107
- if (errorMessage.includes(
166108
- "Endpoint storage inaccessible because endpoint is not a node and is not owned by another endpoint"
166109
- )) {
166110
- logger159.debug(
166111
- `Suppressed endpoint storage error, patch not applied: ${JSON.stringify(actualPatch)}`
166112
- );
166113
- return actualPatch;
166114
- }
166115
- if (errorMessage.includes("synchronous-transaction-conflict")) {
166116
- logger159.warn(
166117
- `Transaction conflict, state update DROPPED: ${JSON.stringify(actualPatch)}`
166118
- );
166119
- return actualPatch;
166120
- }
166121
- failedKeys.push(key);
166122
- logger159.warn(`Failed to set property '${key}': ${errorMessage}`);
166123
- }
166124
- }
166125
- if (failedKeys.length > 0) {
166126
- logger159.warn(
166127
- `${failedKeys.length} properties failed to update: [${failedKeys.join(", ")}]`
166128
- );
166129
- }
166130
- return actualPatch;
166131
- }
166132
- function deepEqual(a, b) {
166133
- if (a == null || b == null) {
166134
- return a === b;
166135
- }
166136
- if (typeof a !== typeof b || Array.isArray(a) !== Array.isArray(b)) {
166137
- return false;
166138
- }
166139
- if (Array.isArray(a) && Array.isArray(b)) {
166140
- return a.length === b.length && a.every((vA, idx) => deepEqual(vA, b[idx]));
166141
- }
166142
- if (typeof a === "object" && typeof b === "object") {
166143
- const keys3 = Object.keys({ ...a, ...b });
166144
- return keys3.every((key) => deepEqual(a[key], b[key]));
166145
- }
166146
- return a === b;
166147
- }
166148
-
166149
166166
  // src/plugins/plugin-behavior.ts
166150
166167
  init_esm7();
166151
166168
  var PluginDeviceBehavior = class extends Behavior {
@@ -181592,6 +181609,7 @@ var ServerModeEndpointManager = class extends Service {
181592
181609
  await this.serverNode.addDevice(endpoint2);
181593
181610
  this.deviceEndpoint = endpoint2;
181594
181611
  this.mappingFingerprint = currentFp;
181612
+ this.updateServerNodeIdentity(entityId, mapping);
181595
181613
  this.log.info(
181596
181614
  `Server mode: Added vacuum ${entityId} as standalone device`
181597
181615
  );
@@ -181612,6 +181630,7 @@ var ServerModeEndpointManager = class extends Service {
181612
181630
  await this.serverNode.addDevice(endpoint);
181613
181631
  this.deviceEndpoint = endpoint;
181614
181632
  this.mappingFingerprint = currentFp;
181633
+ this.updateServerNodeIdentity(entityId, mapping);
181615
181634
  this.log.info(`Server mode: Added device ${entityId}`);
181616
181635
  } catch (e) {
181617
181636
  const reason = e instanceof Error ? e.message : String(e);
@@ -181632,6 +181651,17 @@ var ServerModeEndpointManager = class extends Service {
181632
181651
  }
181633
181652
  }
181634
181653
  }
181654
+ updateServerNodeIdentity(entityId, mapping) {
181655
+ const device = this.registry.deviceOf(entityId);
181656
+ const state = this.registry.initialState(entityId);
181657
+ const friendlyName = state?.attributes?.friendly_name;
181658
+ this.serverNode.updateDeviceIdentity(
181659
+ entityId,
181660
+ device,
181661
+ mapping,
181662
+ friendlyName
181663
+ );
181664
+ }
181635
181665
  /**
181636
181666
  * Creates a Server Mode Vacuum endpoint without BridgedDeviceBasicInformation.
181637
181667
  * This makes the vacuum appear as a standalone Matter device, which is required