homebridge 2.0.0-alpha.40 → 2.0.0-alpha.41

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.
Files changed (92) hide show
  1. package/config-sample.json +1 -12
  2. package/dist/api.d.ts +4 -20
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +1 -27
  5. package/dist/api.js.map +1 -1
  6. package/dist/bridgeService.d.ts +12 -15
  7. package/dist/bridgeService.d.ts.map +1 -1
  8. package/dist/bridgeService.js +7 -7
  9. package/dist/bridgeService.js.map +1 -1
  10. package/dist/childBridgeService.d.ts +1 -0
  11. package/dist/childBridgeService.d.ts.map +1 -1
  12. package/dist/childBridgeService.js +1 -0
  13. package/dist/childBridgeService.js.map +1 -1
  14. package/dist/childMatterBridgeFork.d.ts +108 -0
  15. package/dist/childMatterBridgeFork.d.ts.map +1 -0
  16. package/dist/childMatterBridgeFork.js +330 -0
  17. package/dist/childMatterBridgeFork.js.map +1 -0
  18. package/dist/childMatterBridgeService.d.ts +166 -0
  19. package/dist/childMatterBridgeService.d.ts.map +1 -0
  20. package/dist/childMatterBridgeService.js +623 -0
  21. package/dist/childMatterBridgeService.js.map +1 -0
  22. package/dist/index.d.ts +8 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +2 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/ipcService.d.ts +19 -3
  27. package/dist/ipcService.d.ts.map +1 -1
  28. package/dist/ipcService.js +13 -0
  29. package/dist/ipcService.js.map +1 -1
  30. package/dist/matter/index.d.ts +13 -0
  31. package/dist/matter/index.d.ts.map +1 -0
  32. package/dist/matter/index.js +12 -0
  33. package/dist/matter/index.js.map +1 -0
  34. package/dist/matter/matterBridge.d.ts +64 -0
  35. package/dist/matter/matterBridge.d.ts.map +1 -0
  36. package/dist/matter/matterBridge.js +154 -0
  37. package/dist/matter/matterBridge.js.map +1 -0
  38. package/dist/matter/matterConfigValidator.d.ts +27 -0
  39. package/dist/matter/matterConfigValidator.d.ts.map +1 -0
  40. package/dist/matter/matterConfigValidator.js +162 -0
  41. package/dist/matter/matterConfigValidator.js.map +1 -0
  42. package/dist/matter/matterDevice.d.ts +107 -0
  43. package/dist/matter/matterDevice.d.ts.map +1 -0
  44. package/dist/matter/matterDevice.js +913 -0
  45. package/dist/matter/matterDevice.js.map +1 -0
  46. package/dist/matter/matterDiagnostics.d.ts +121 -0
  47. package/dist/matter/matterDiagnostics.d.ts.map +1 -0
  48. package/dist/matter/matterDiagnostics.js +323 -0
  49. package/dist/matter/matterDiagnostics.js.map +1 -0
  50. package/dist/matter/matterErrorHandler.d.ts +113 -0
  51. package/dist/matter/matterErrorHandler.d.ts.map +1 -0
  52. package/dist/matter/matterErrorHandler.js +482 -0
  53. package/dist/matter/matterErrorHandler.js.map +1 -0
  54. package/dist/matter/matterNetworkMonitor.d.ts +65 -0
  55. package/dist/matter/matterNetworkMonitor.d.ts.map +1 -0
  56. package/dist/matter/matterNetworkMonitor.js +227 -0
  57. package/dist/matter/matterNetworkMonitor.js.map +1 -0
  58. package/dist/matter/matterServer.d.ts +110 -0
  59. package/dist/matter/matterServer.d.ts.map +1 -0
  60. package/dist/matter/matterServer.js +584 -0
  61. package/dist/matter/matterServer.js.map +1 -0
  62. package/dist/matter/matterSharedTypes.d.ts +167 -0
  63. package/dist/matter/matterSharedTypes.d.ts.map +1 -0
  64. package/dist/matter/matterSharedTypes.js +55 -0
  65. package/dist/matter/matterSharedTypes.js.map +1 -0
  66. package/dist/{matterTypes.d.ts → matter/matterTypes.d.ts} +15 -0
  67. package/dist/matter/matterTypes.d.ts.map +1 -0
  68. package/dist/{matterTypes.js → matter/matterTypes.js} +4 -4
  69. package/dist/matter/matterTypes.js.map +1 -0
  70. package/dist/matter/portAllocator.d.ts +85 -0
  71. package/dist/matter/portAllocator.d.ts.map +1 -0
  72. package/dist/matter/portAllocator.js +296 -0
  73. package/dist/matter/portAllocator.js.map +1 -0
  74. package/dist/server.d.ts +9 -3
  75. package/dist/server.d.ts.map +1 -1
  76. package/dist/server.js +363 -31
  77. package/dist/server.js.map +1 -1
  78. package/package.json +10 -10
  79. package/dist/matterConfigValidator.d.ts +0 -34
  80. package/dist/matterConfigValidator.d.ts.map +0 -1
  81. package/dist/matterConfigValidator.js +0 -249
  82. package/dist/matterConfigValidator.js.map +0 -1
  83. package/dist/matterService.d.ts +0 -168
  84. package/dist/matterService.d.ts.map +0 -1
  85. package/dist/matterService.js +0 -677
  86. package/dist/matterService.js.map +0 -1
  87. package/dist/matterTypes.d.ts.map +0 -1
  88. package/dist/matterTypes.js.map +0 -1
  89. package/dist/util/matter-cli.d.ts +0 -3
  90. package/dist/util/matter-cli.d.ts.map +0 -1
  91. package/dist/util/matter-cli.js +0 -211
  92. package/dist/util/matter-cli.js.map +0 -1
@@ -1,677 +0,0 @@
1
- import * as crypto from 'node:crypto';
2
- import * as fs from 'fs-extra';
3
- import { Logger } from './logger.js';
4
- import { MatterConfigValidator } from './matterConfigValidator.js';
5
- import '@matter/main';
6
- const log = Logger.internal;
7
- /**
8
- * Matter service for publishing accessories via Matter protocol
9
- * This runs alongside the existing HAP bridge service
10
- */
11
- export class MatterService {
12
- matterConfiguration;
13
- pluginManager;
14
- externalPortService;
15
- api;
16
- options;
17
- matterServer = null;
18
- commissioningServer = null;
19
- storageManager = null;
20
- isEnabled;
21
- matterConfig;
22
- publishedAccessories = new Map();
23
- isInitialized = false;
24
- isStarted = false;
25
- constructor(matterConfiguration, pluginManager, externalPortService, api, options) {
26
- this.matterConfiguration = matterConfiguration;
27
- this.pluginManager = pluginManager;
28
- this.externalPortService = externalPortService;
29
- this.api = api;
30
- this.options = options;
31
- this.matterConfig = {
32
- enabled: false,
33
- port: 5540,
34
- discriminator: 3840,
35
- passcode: 20202021,
36
- vendorId: 0xFFF1, // Test Vendor ID
37
- productId: 0x8001, // Test Product ID
38
- deviceName: 'Homebridge Matter Bridge',
39
- deviceType: 0x0016, // Matter Bridge device type
40
- storageDir: options.customStoragePath || './persist',
41
- debugEnabled: false,
42
- interfaceName: undefined,
43
- announceInterval: 60,
44
- commissioningTimeout: 900, // 15 minutes
45
- ...matterConfiguration,
46
- };
47
- this.isEnabled = this.matterConfig.enabled || false;
48
- this.validateConfiguration();
49
- if (this.isEnabled) {
50
- log.info('Matter service enabled');
51
- }
52
- else {
53
- log.debug('Matter service disabled');
54
- }
55
- }
56
- /**
57
- * Validate Matter configuration parameters
58
- */
59
- validateConfiguration() {
60
- if (!this.isEnabled) {
61
- return;
62
- }
63
- const validationResult = MatterConfigValidator.validate(this.matterConfig);
64
- if (!validationResult.isValid) {
65
- const errorMessage = `Matter configuration validation failed:\n${validationResult.errors.join('\n')}`;
66
- throw new Error(errorMessage);
67
- }
68
- if (validationResult.warnings.length > 0) {
69
- log.warn('Matter configuration has warnings - see above for details');
70
- }
71
- log.info(`Matter configuration validated successfully: port=${this.matterConfig.port}, discriminator=${this.matterConfig.discriminator}`);
72
- }
73
- /**
74
- * Initialize the Matter server if enabled
75
- */
76
- async initialize() {
77
- if (!this.isEnabled || this.isInitialized) {
78
- return;
79
- }
80
- try {
81
- log.info('Initializing Matter server...');
82
- // Initialize storage
83
- await this.initializeStorage();
84
- // Create and configure Matter server node
85
- await this.createMatterServer();
86
- // Setup commissioning server
87
- await this.setupCommissioningServer();
88
- this.isInitialized = true;
89
- log.info('Matter server initialized successfully');
90
- this.logCommissioningInfo();
91
- }
92
- catch (error) {
93
- log.error('Failed to initialize Matter server:', error);
94
- await this.cleanup();
95
- throw error;
96
- }
97
- }
98
- /**
99
- * Initialize storage for Matter server
100
- */
101
- async initializeStorage() {
102
- try {
103
- // Create storage directory if it doesn't exist
104
- const storageDir = `${this.matterConfig.storageDir}/matter`;
105
- await fs.ensureDir(storageDir);
106
- // Use placeholder storage manager for now
107
- // In production, this would use proper Matter.js storage
108
- this.storageManager = {
109
- initialized: true,
110
- async initialize() {
111
- return Promise.resolve();
112
- },
113
- async close() {
114
- return Promise.resolve();
115
- },
116
- };
117
- await this.storageManager.initialize();
118
- log.debug('Matter storage initialized');
119
- }
120
- catch (error) {
121
- log.error('Failed to initialize Matter storage:', error);
122
- throw error;
123
- }
124
- }
125
- /**
126
- * Create the Matter server node
127
- */
128
- async createMatterServer() {
129
- if (!this.storageManager) {
130
- throw new Error('Storage manager not initialized');
131
- }
132
- try {
133
- // Create placeholder Matter server
134
- // In production, this would be a real Matter.js ServerNode
135
- this.matterServer = {
136
- started: false,
137
- devices: new Map(),
138
- async start() {
139
- this.started = true;
140
- return Promise.resolve();
141
- },
142
- async stop() {
143
- this.started = false;
144
- return Promise.resolve();
145
- },
146
- async addDevice(device) {
147
- const id = crypto.randomUUID();
148
- this.devices.set(id, device);
149
- return { id, device };
150
- },
151
- async removeDevice(endpoint) {
152
- this.devices.delete(endpoint.id);
153
- return Promise.resolve();
154
- },
155
- };
156
- log.debug('Matter server node created (placeholder implementation)');
157
- }
158
- catch (error) {
159
- log.error('Failed to create Matter server node:', error);
160
- throw error;
161
- }
162
- }
163
- /**
164
- * Setup commissioning server for device pairing
165
- */
166
- async setupCommissioningServer() {
167
- if (!this.matterServer) {
168
- throw new Error('Matter server not created');
169
- }
170
- try {
171
- // Create placeholder commissioning server
172
- // In production, this would be a real Matter.js CommissioningServer
173
- this.commissioningServer = {
174
- started: false,
175
- async start() {
176
- this.started = true;
177
- return Promise.resolve();
178
- },
179
- async stop() {
180
- this.started = false;
181
- return Promise.resolve();
182
- },
183
- };
184
- log.debug('Matter commissioning server configured (placeholder implementation)');
185
- }
186
- catch (error) {
187
- log.error('Failed to setup commissioning server:', error);
188
- throw error;
189
- }
190
- }
191
- /**
192
- * Generate a unique serial number for the Matter bridge
193
- */
194
- generateSerialNumber() {
195
- // Use the HAP bridge username as base for consistency
196
- const hapBridge = this.api.hap?.HAPStorage.storage()?.getItem('AccessoryInfo.CC:22:3D:E3:CE:30');
197
- if (hapBridge && hapBridge.serialNumber) {
198
- return `HB-${hapBridge.serialNumber}`;
199
- }
200
- // Fallback to generated serial
201
- return `HB-${crypto.randomBytes(6).toString('hex').toUpperCase()}`;
202
- }
203
- /**
204
- * Generate a unique identifier for the Matter bridge
205
- */
206
- generateUniqueId() {
207
- // Use the HAP bridge ID as base for consistency
208
- const hapBridge = this.api.hap?.HAPStorage.storage()?.getItem('AccessoryInfo.CC:22:3D:E3:CE:30');
209
- if (hapBridge && hapBridge.id) {
210
- return `homebridge-matter-${hapBridge.id}`;
211
- }
212
- // Fallback to generated ID
213
- return `homebridge-matter-${crypto.randomUUID()}`;
214
- }
215
- /**
216
- * Log commissioning information for users
217
- */
218
- logCommissioningInfo() {
219
- try {
220
- // Generate placeholder QR code info
221
- // In production, this would use real Matter.js QrCode.encode()
222
- const setupCode = `MT:${this.matterConfig.discriminator.toString().padStart(4, '0')}${this.matterConfig.passcode}`;
223
- const qrCode = `https://dhrishi.github.io/connectedhomeip/qrcode.html?data=${setupCode}`;
224
- log.info('Matter bridge is ready for commissioning:');
225
- log.info(` Setup Code: ${setupCode}`);
226
- log.info(` QR Code URL: ${qrCode}`);
227
- log.info(` Manual Pairing Code: ${this.formatPairingCode(this.matterConfig.passcode)}`);
228
- log.info(` Discriminator: ${this.matterConfig.discriminator}`);
229
- log.info(` Port: ${this.matterConfig.port}`);
230
- log.info(' Note: This is a development implementation - QR codes may not work with all controllers');
231
- }
232
- catch (error) {
233
- log.warn('Could not generate commissioning QR code:', error);
234
- log.info(`Matter bridge ready - Manual setup: Passcode ${this.matterConfig.passcode}, Discriminator ${this.matterConfig.discriminator}`);
235
- }
236
- }
237
- /**
238
- * Format passcode for manual pairing
239
- */
240
- formatPairingCode(passcode) {
241
- const code = passcode.toString().padStart(8, '0');
242
- return `${code.slice(0, 3)}-${code.slice(3, 5)}-${code.slice(5)}`;
243
- }
244
- /**
245
- * Start the Matter server
246
- */
247
- async start() {
248
- if (!this.isEnabled || !this.matterServer || this.isStarted) {
249
- return;
250
- }
251
- try {
252
- log.info('Starting Matter server...');
253
- // Start the Matter server node
254
- await this.matterServer.start();
255
- // Start commissioning
256
- if (this.commissioningServer) {
257
- await this.commissioningServer.start();
258
- }
259
- this.isStarted = true;
260
- log.info(`Matter server started successfully on port ${this.matterConfig.port}`);
261
- }
262
- catch (error) {
263
- log.error('Failed to start Matter server:', error);
264
- this.isStarted = false;
265
- throw error;
266
- }
267
- }
268
- /**
269
- * Stop the Matter server
270
- */
271
- async stop() {
272
- if (!this.isStarted) {
273
- return;
274
- }
275
- try {
276
- log.info('Stopping Matter server...');
277
- // Stop commissioning server
278
- if (this.commissioningServer) {
279
- await this.commissioningServer.stop();
280
- }
281
- // Stop Matter server
282
- if (this.matterServer) {
283
- await this.matterServer.stop();
284
- }
285
- await this.cleanup();
286
- this.isStarted = false;
287
- log.info('Matter server stopped successfully');
288
- }
289
- catch (error) {
290
- log.error('Failed to stop Matter server:', error);
291
- this.isStarted = false;
292
- }
293
- }
294
- /**
295
- * Clean up resources
296
- */
297
- async cleanup() {
298
- try {
299
- // Close storage
300
- if (this.storageManager) {
301
- await this.storageManager.close();
302
- this.storageManager = null;
303
- }
304
- this.matterServer = null;
305
- this.commissioningServer = null;
306
- this.publishedAccessories.clear();
307
- this.isInitialized = false;
308
- }
309
- catch (error) {
310
- log.error('Error during Matter service cleanup:', error);
311
- }
312
- }
313
- /**
314
- * Publish a platform accessory via Matter protocol
315
- */
316
- async publishAccessory(accessory) {
317
- if (!this.isEnabled || !this.matterServer || !this.isStarted) {
318
- log.debug(`Cannot publish accessory "${accessory.displayName}" - Matter server not ready`);
319
- return;
320
- }
321
- try {
322
- log.debug(`Publishing accessory "${accessory.displayName}" via Matter...`);
323
- // Convert HAP accessory to Matter device
324
- const matterDevice = await this.convertToMatterDevice(accessory);
325
- if (matterDevice) {
326
- // Add the device to the Matter server as a bridged device
327
- const endpoint = await this.matterServer.addDevice(matterDevice);
328
- // Track the published accessory
329
- this.publishedAccessories.set(accessory.UUID, {
330
- accessory,
331
- endpoint,
332
- });
333
- log.info(`Published accessory "${accessory.displayName}" via Matter successfully`);
334
- }
335
- else {
336
- log.warn(`Could not convert accessory "${accessory.displayName}" to Matter device - unsupported services`);
337
- }
338
- }
339
- catch (error) {
340
- log.error(`Failed to publish accessory "${accessory.displayName}" via Matter:`, error);
341
- }
342
- }
343
- /**
344
- * Unpublish a platform accessory from Matter protocol
345
- */
346
- async unpublishAccessory(accessory) {
347
- if (!this.isEnabled || !this.matterServer) {
348
- return;
349
- }
350
- try {
351
- const publishedDevice = this.publishedAccessories.get(accessory.UUID);
352
- if (publishedDevice) {
353
- // Remove the device from the Matter server
354
- await this.matterServer.removeDevice(publishedDevice.endpoint);
355
- // Remove from tracking
356
- this.publishedAccessories.delete(accessory.UUID);
357
- log.info(`Unpublished accessory "${accessory.displayName}" from Matter successfully`);
358
- }
359
- else {
360
- log.debug(`Accessory "${accessory.displayName}" was not published via Matter`);
361
- }
362
- }
363
- catch (error) {
364
- log.error(`Failed to unpublish accessory "${accessory.displayName}" from Matter:`, error);
365
- }
366
- }
367
- /**
368
- * Convert HAP accessory to Matter device
369
- * This maps HAP services and characteristics to appropriate Matter clusters and attributes
370
- */
371
- async convertToMatterDevice(accessory) {
372
- try {
373
- log.debug(`Converting accessory "${accessory.displayName}" to Matter device...`);
374
- // Get the primary service (excluding AccessoryInformation and other utility services)
375
- const primaryService = this.getPrimaryService(accessory);
376
- if (!primaryService) {
377
- log.warn(`No primary service found for accessory "${accessory.displayName}"`);
378
- return null;
379
- }
380
- const serviceType = primaryService.constructor.name;
381
- const characteristics = primaryService.characteristics.map(char => char.constructor.name);
382
- log.debug(`Primary service: ${serviceType}, characteristics: ${characteristics.join(', ')}`);
383
- // Determine the appropriate Matter device type and clusters
384
- const deviceType = this.getMatterDeviceType(serviceType, characteristics);
385
- if (!deviceType) {
386
- log.warn(`Unsupported service type for Matter conversion: ${serviceType}`);
387
- return null;
388
- }
389
- // Create the Matter device with appropriate clusters
390
- const matterDevice = await this.createMatterDevice(deviceType, accessory, primaryService);
391
- log.debug(`Successfully converted "${accessory.displayName}" to Matter ${deviceType} device`);
392
- return matterDevice;
393
- }
394
- catch (error) {
395
- log.error(`Error converting accessory "${accessory.displayName}" to Matter device:`, error);
396
- return null;
397
- }
398
- }
399
- /**
400
- * Get the primary service from an accessory (excluding utility services)
401
- */
402
- getPrimaryService(accessory) {
403
- const utilityServices = [
404
- 'AccessoryInformation',
405
- 'BridgingState',
406
- 'HAPProtocolInformation',
407
- 'Pairing',
408
- 'BridgeConfiguration',
409
- ];
410
- for (const service of accessory.services) {
411
- const serviceType = service.constructor.name;
412
- if (!utilityServices.includes(serviceType)) {
413
- return service;
414
- }
415
- }
416
- return null;
417
- }
418
- /**
419
- * Determine the appropriate Matter device type for a HAP service
420
- */
421
- getMatterDeviceType(serviceType, characteristics) {
422
- // Handle lighting services with specific capabilities
423
- if (serviceType === 'Lightbulb') {
424
- if (characteristics.includes('Hue') && characteristics.includes('Saturation')) {
425
- return 'ExtendedColorLight';
426
- }
427
- else if (characteristics.includes('ColorTemperature')) {
428
- return 'ColorTemperatureLight';
429
- }
430
- else if (characteristics.includes('Brightness')) {
431
- return 'DimmableLight';
432
- }
433
- else {
434
- return 'OnOffLight';
435
- }
436
- }
437
- // Handle outlet services
438
- if (serviceType === 'Outlet') {
439
- if (characteristics.includes('Brightness')) {
440
- return 'DimmablePlugInUnit';
441
- }
442
- else {
443
- return 'OnOffPlugInUnit';
444
- }
445
- }
446
- // Handle switch services
447
- if (serviceType === 'Switch') {
448
- if (characteristics.includes('Brightness')) {
449
- return 'DimmerSwitch';
450
- }
451
- else {
452
- return 'OnOffLightSwitch';
453
- }
454
- }
455
- // Direct mapping for other services
456
- const directMappings = {
457
- TemperatureSensor: 'TemperatureSensor',
458
- HumiditySensor: 'HumiditySensor',
459
- LightSensor: 'LightSensor',
460
- MotionSensor: 'OccupancySensor',
461
- OccupancySensor: 'OccupancySensor',
462
- ContactSensor: 'ContactSensor',
463
- LeakSensor: 'WaterLeakDetector',
464
- SmokeSensor: 'SmokeCoAlarm',
465
- CarbonMonoxideSensor: 'SmokeCoAlarm',
466
- LockManagement: 'DoorLock',
467
- Thermostat: 'Thermostat',
468
- Fan: 'Fan',
469
- Fanv2: 'Fan',
470
- WindowCovering: 'WindowCovering',
471
- StatelessProgrammableSwitch: 'GenericSwitch',
472
- Valve: 'WaterValve',
473
- };
474
- return directMappings[serviceType] || null;
475
- }
476
- /**
477
- * Create a Matter device with the specified type and map characteristics
478
- */
479
- async createMatterDevice(deviceType, accessory, primaryService) {
480
- log.debug(`Creating Matter device of type ${deviceType} (placeholder implementation)`);
481
- // Create a placeholder Matter device
482
- // In production, this would use real Matter.js device classes
483
- const device = {
484
- type: deviceType,
485
- accessoryUUID: accessory.UUID,
486
- displayName: accessory.displayName,
487
- services: accessory.services.map((s) => ({
488
- type: s.constructor.name,
489
- characteristics: s.characteristics.map((c) => ({
490
- type: c.constructor.name,
491
- value: c.value,
492
- })),
493
- })),
494
- // Placeholder clusters based on device type
495
- clusters: this.getPlaceholderClusters(deviceType),
496
- };
497
- // Map characteristics to Matter attributes (placeholder)
498
- await this.mapCharacteristicsToMatter(device, primaryService);
499
- return device;
500
- }
501
- /**
502
- * Get placeholder clusters for a device type
503
- */
504
- getPlaceholderClusters(deviceType) {
505
- const clusterMappings = {
506
- OnOffLight: ['OnOff', 'Identify'],
507
- DimmableLight: ['OnOff', 'LevelControl', 'Identify'],
508
- ExtendedColorLight: ['OnOff', 'LevelControl', 'ColorControl', 'Identify'],
509
- TemperatureSensor: ['TemperatureMeasurement', 'Identify'],
510
- HumiditySensor: ['RelativeHumidityMeasurement', 'Identify'],
511
- ContactSensor: ['BooleanState', 'Identify'],
512
- DoorLock: ['DoorLock', 'Identify'],
513
- WindowCovering: ['WindowCovering', 'Identify'],
514
- Thermostat: ['Thermostat', 'Identify'],
515
- Fan: ['FanControl', 'Identify'],
516
- };
517
- return clusterMappings[deviceType] || ['Identify'];
518
- }
519
- /**
520
- * Map HAP characteristics to Matter cluster attributes
521
- */
522
- async mapCharacteristicsToMatter(matterDevice, hapService) {
523
- try {
524
- log.debug(`Mapping characteristics for service ${hapService.constructor.name} (placeholder implementation)`);
525
- // This is a placeholder implementation that tracks the mapping
526
- // In production, this would actually sync values between HAP and Matter
527
- matterDevice.characteristicMappings = [];
528
- for (const characteristic of hapService.characteristics) {
529
- const charType = characteristic.constructor.name;
530
- const mapping = {
531
- hapCharacteristic: charType,
532
- hapValue: characteristic.value,
533
- matterCluster: this.getMatterClusterForCharacteristic(charType),
534
- matterAttribute: this.getMatterAttributeForCharacteristic(charType),
535
- };
536
- matterDevice.characteristicMappings.push(mapping);
537
- log.debug(`Mapped ${charType} -> ${mapping.matterCluster}.${mapping.matterAttribute}`);
538
- }
539
- }
540
- catch (error) {
541
- log.error('Error mapping characteristics to Matter:', error);
542
- }
543
- }
544
- /**
545
- * Get the Matter cluster name for a HAP characteristic
546
- */
547
- getMatterClusterForCharacteristic(charType) {
548
- const mappings = {
549
- On: 'OnOff',
550
- Brightness: 'LevelControl',
551
- Hue: 'ColorControl',
552
- Saturation: 'ColorControl',
553
- ColorTemperature: 'ColorControl',
554
- CurrentTemperature: 'TemperatureMeasurement',
555
- CurrentRelativeHumidity: 'RelativeHumidityMeasurement',
556
- ContactSensorState: 'BooleanState',
557
- MotionDetected: 'OccupancySensing',
558
- LockCurrentState: 'DoorLock',
559
- CurrentPosition: 'WindowCovering',
560
- CurrentHeatingCoolingState: 'Thermostat',
561
- RotationSpeed: 'FanControl',
562
- };
563
- return mappings[charType] || 'Unknown';
564
- }
565
- /**
566
- * Get the Matter attribute name for a HAP characteristic
567
- */
568
- getMatterAttributeForCharacteristic(charType) {
569
- const mappings = {
570
- On: 'OnOff',
571
- Brightness: 'CurrentLevel',
572
- Hue: 'CurrentHue',
573
- Saturation: 'CurrentSaturation',
574
- ColorTemperature: 'ColorTemperatureMireds',
575
- CurrentTemperature: 'MeasuredValue',
576
- CurrentRelativeHumidity: 'MeasuredValue',
577
- ContactSensorState: 'StateValue',
578
- MotionDetected: 'Occupancy',
579
- LockCurrentState: 'LockState',
580
- CurrentPosition: 'CurrentPositionLiftPercent100ths',
581
- CurrentHeatingCoolingState: 'SystemMode',
582
- RotationSpeed: 'PercentCurrent',
583
- };
584
- return mappings[charType] || 'Value';
585
- }
586
- /**
587
- * Get Matter server status
588
- */
589
- getStatus() {
590
- const status = {
591
- enabled: this.isEnabled,
592
- running: this.isStarted,
593
- accessoryCount: this.publishedAccessories.size,
594
- };
595
- // Add commissioning info if server is running
596
- if (this.isStarted && this.isEnabled) {
597
- try {
598
- const setupCode = `MT:${this.matterConfig.discriminator.toString().padStart(4, '0')}${this.matterConfig.passcode}`;
599
- const qrCodeUrl = `https://dhrishi.github.io/connectedhomeip/qrcode.html?data=${setupCode}`;
600
- return {
601
- ...status,
602
- qrCode: qrCodeUrl,
603
- setupCode,
604
- };
605
- }
606
- catch (error) {
607
- log.debug('Could not generate QR code for status:', error);
608
- }
609
- }
610
- return status;
611
- }
612
- /**
613
- * Get commissioning QR code for setup
614
- */
615
- getCommissioningQRCode() {
616
- if (!this.isEnabled || !this.isStarted) {
617
- return null;
618
- }
619
- try {
620
- // Generate placeholder QR code
621
- // In production, this would use real Matter.js QrCode.encode()
622
- const setupCode = `MT:${this.matterConfig.discriminator.toString().padStart(4, '0')}${this.matterConfig.passcode}`;
623
- return `https://dhrishi.github.io/connectedhomeip/qrcode.html?data=${setupCode}`;
624
- }
625
- catch (error) {
626
- log.error('Failed to generate commissioning QR code:', error);
627
- return null;
628
- }
629
- }
630
- /**
631
- * Get manual pairing code for setup
632
- */
633
- getManualPairingCode() {
634
- if (!this.isEnabled || !this.isStarted) {
635
- return null;
636
- }
637
- return this.formatPairingCode(this.matterConfig.passcode);
638
- }
639
- /**
640
- * Get list of published accessories
641
- */
642
- getPublishedAccessories() {
643
- return Array.from(this.publishedAccessories.values()).map(item => item.accessory);
644
- }
645
- /**
646
- * Check if an accessory is published via Matter
647
- */
648
- isAccessoryPublished(accessory) {
649
- return this.publishedAccessories.has(accessory.UUID);
650
- }
651
- /**
652
- * Get Matter configuration (read-only)
653
- */
654
- getConfiguration() {
655
- return { ...this.matterConfig };
656
- }
657
- /**
658
- * Force restart the Matter server (for configuration changes)
659
- */
660
- async restart() {
661
- if (!this.isEnabled) {
662
- return;
663
- }
664
- log.info('Restarting Matter server...');
665
- try {
666
- await this.stop();
667
- await this.initialize();
668
- await this.start();
669
- log.info('Matter server restarted successfully');
670
- }
671
- catch (error) {
672
- log.error('Failed to restart Matter server:', error);
673
- throw error;
674
- }
675
- }
676
- }
677
- //# sourceMappingURL=matterService.js.map