homebridge-zwave-usb 2.3.1 → 2.5.0

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.
@@ -11,6 +11,10 @@ export declare class ZWaveAccessory {
11
11
  private initialized;
12
12
  constructor(platform: ZWaveUsbPlatform, node: IZWaveNode, homeId: number);
13
13
  addFeature(feature: ZWaveFeature): void;
14
+ /**
15
+ * Syncs the HomeKit name and service names when the node is renamed.
16
+ */
17
+ rename(newName: string): void;
14
18
  /**
15
19
  * HOT-RECOVERY FIX: Update stale node references.
16
20
  * When the driver restarts (hot-plug), the IZWaveNode instance changes.
@@ -82,6 +82,24 @@ class ZWaveAccessory {
82
82
  addFeature(feature) {
83
83
  this.features.push(feature);
84
84
  }
85
+ /**
86
+ * Syncs the HomeKit name and service names when the node is renamed.
87
+ */
88
+ rename(newName) {
89
+ this.platform.log.info(`Syncing HomeKit name for Node ${this.node.nodeId} -> ${newName}`);
90
+ this.platformAccessory.displayName = newName;
91
+ // Update the Model and Serial if they were using the generic name
92
+ const model = this.node.deviceConfig?.label || newName;
93
+ this.platformAccessory
94
+ .getService(this.platform.Service.AccessoryInformation)
95
+ .setCharacteristic(this.platform.Characteristic.Model, model);
96
+ // Update all features
97
+ for (const feature of this.features) {
98
+ feature.rename(newName);
99
+ }
100
+ // Notify Homebridge of changes
101
+ this.platform.api.updatePlatformAccessories([this.platformAccessory]);
102
+ }
85
103
  /**
86
104
  * HOT-RECOVERY FIX: Update stale node references.
87
105
  * When the driver restarts (hot-plug), the IZWaveNode instance changes.
@@ -9,6 +9,7 @@ export interface ZWaveFeature {
9
9
  getEndpointIndex(): number;
10
10
  stop(): void;
11
11
  updateNode(node: IZWaveNode, endpoint: Endpoint): void;
12
+ rename(newName: string): void;
12
13
  }
13
14
  export declare abstract class BaseFeature implements ZWaveFeature {
14
15
  protected readonly platform: ZWaveUsbPlatform;
@@ -21,6 +22,10 @@ export declare abstract class BaseFeature implements ZWaveFeature {
21
22
  abstract update(args?: ZWaveValueEvent): void;
22
23
  stop(): void;
23
24
  updateNode(node: IZWaveNode, endpoint: Endpoint): void;
25
+ /**
26
+ * Dynamically updates the Name characteristic of all managed services.
27
+ */
28
+ rename(newName: string): void;
24
29
  getServices(): Service[];
25
30
  getEndpointIndex(): number;
26
31
  /**
@@ -21,6 +21,20 @@ class BaseFeature {
21
21
  this.node = node;
22
22
  this.endpoint = endpoint;
23
23
  }
24
+ /**
25
+ * Dynamically updates the Name characteristic of all managed services.
26
+ */
27
+ rename(newName) {
28
+ const serviceName = this.endpoint.index > 0 ? `${newName} ${this.endpoint.index}` : newName;
29
+ for (const service of this.managedServices) {
30
+ if (service.testCharacteristic(this.platform.Characteristic.Name)) {
31
+ service.getCharacteristic(this.platform.Characteristic.Name).updateValue(serviceName);
32
+ }
33
+ if (service.testCharacteristic(this.platform.Characteristic.ConfiguredName)) {
34
+ service.getCharacteristic(this.platform.Characteristic.ConfiguredName).updateValue(serviceName);
35
+ }
36
+ }
37
+ }
24
38
  getServices() {
25
39
  return this.managedServices;
26
40
  }
@@ -76,6 +90,11 @@ class BaseFeature {
76
90
  perms: [settings_1.HAPPerm.PAIRED_READ],
77
91
  })
78
92
  .updateValue(serviceName);
93
+ // Also set ConfiguredName which HomeKit often prioritizes for display
94
+ if (!service.testCharacteristic(this.platform.Characteristic.ConfiguredName)) {
95
+ service.addOptionalCharacteristic(this.platform.Characteristic.ConfiguredName);
96
+ }
97
+ service.getCharacteristic(this.platform.Characteristic.ConfiguredName).updateValue(serviceName);
79
98
  // Add Service Label Index for multi-endpoint devices to help with ordering/naming
80
99
  if (this.endpoint.index > 0) {
81
100
  if (!service.testCharacteristic(this.platform.Characteristic.ServiceLabelIndex)) {
@@ -140,9 +140,7 @@ class ZWaveUsbPlatform {
140
140
  // Update Homebridge Accessory Name
141
141
  const accessory = this.zwaveAccessories.get(nodeId);
142
142
  if (accessory) {
143
- this.log.info(`Renaming HomeKit accessory for Node ${nodeId} to: ${name}`);
144
- accessory.platformAccessory.displayName = name;
145
- this.api.updatePlatformAccessories([accessory.platformAccessory]);
143
+ accessory.rename(name);
146
144
  }
147
145
  return sendJson({ success: true });
148
146
  }
@@ -326,7 +324,8 @@ class ZWaveUsbPlatform {
326
324
  this.log.info(`Node ${node.nodeId} added to the network. Waiting for interview to complete...`);
327
325
  }
328
326
  handleNodeReady(node) {
329
- this.log.info(`Node ${node.nodeId} ready`);
327
+ const nodeName = node.name || node.deviceConfig?.label || `Node ${node.nodeId}`;
328
+ this.log.info(`Node ${node.nodeId} (${nodeName}) ready`);
330
329
  // Skip Node 1 (the controller itself) as it's handled by ControllerAccessory
331
330
  if (Number(node.nodeId) === 1) {
332
331
  this.log.info('System: Controller node (Node 1) identified. Skipping generic accessory creation.');
@@ -345,6 +344,9 @@ class ZWaveUsbPlatform {
345
344
  if (existing || this.discoveryInFlight.has(node.nodeId)) {
346
345
  if (existing) {
347
346
  existing.updateNode(node);
347
+ if (existing.platformAccessory.displayName !== nodeName) {
348
+ existing.rename(nodeName);
349
+ }
348
350
  existing.refresh();
349
351
  }
350
352
  return;
@@ -353,11 +355,8 @@ class ZWaveUsbPlatform {
353
355
  try {
354
356
  const accessory = AccessoryFactory_1.AccessoryFactory.create(this, node, homeId);
355
357
  this.zwaveAccessories.set(node.nodeId, accessory);
356
- const nodeName = node.name || node.deviceConfig?.label || `Node ${node.nodeId}`;
357
358
  if (accessory.platformAccessory.displayName !== nodeName) {
358
- this.log.info(`Renaming accessory ${accessory.platformAccessory.displayName} -> ${nodeName}`);
359
- accessory.platformAccessory.displayName = nodeName;
360
- this.api.updatePlatformAccessories([accessory.platformAccessory]);
359
+ accessory.rename(nodeName);
361
360
  }
362
361
  accessory.initialize();
363
362
  }
@@ -154,7 +154,8 @@ class ZWaveController extends events_1.EventEmitter {
154
154
  */
155
155
  const statusMap = ['Unknown', 'Asleep', 'Awake', 'Dead', 'Alive'];
156
156
  const status = statusMap[node.status] || node.status.toString();
157
- this.log.info(`Node ${node.nodeId} added to controller (Status: ${status}, Interview Stage: ${node.interviewStage})`);
157
+ const nodeName = node.name || node.deviceConfig?.label || `Node ${node.nodeId}`;
158
+ this.log.info(`Node ${node.nodeId} (${nodeName}) added to controller (Status: ${status}, Interview Stage: ${node.interviewStage})`);
158
159
  const onReady = () => {
159
160
  this.log.info(`Node ${node.nodeId} is ready (Interview Stage: ${node.interviewStage})`);
160
161
  this.emit('status updated', `Node ${node.nodeId} Ready`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-zwave-usb",
3
3
  "displayName": "Homebridge Z-Wave USB",
4
- "version": "2.3.1",
4
+ "version": "2.5.0",
5
5
  "description": "A Homebridge dynamic platform plugin for Z-Wave USB controllers using zwave-js.",
6
6
  "license": "Polyform-Noncommercial-1.0.0",
7
7
  "funding": {