@homebridge-plugins/homebridge-smarthq 0.5.0-beta.3 → 0.5.0-beta.31

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 (145) hide show
  1. package/.github/ISSUE_TEMPLATE/config.yml +1 -1
  2. package/.github/copilot-instructions.md +90 -0
  3. package/.github/scripts/branch-helper.sh +41 -0
  4. package/.github/workflows/beta-release.yml +1 -1
  5. package/.github/workflows/release.yml +53 -17
  6. package/CHANGELOG.md +563 -18
  7. package/MATTER.md +304 -0
  8. package/README.md +15 -0
  9. package/config.schema.json +14 -5
  10. package/dist/devices/OpalIceMaker/Managers/OpalDescaleSvcManager.d.ts.map +1 -1
  11. package/dist/devices/OpalIceMaker/Managers/OpalDescaleSvcManager.js +3 -1
  12. package/dist/devices/OpalIceMaker/Managers/OpalDescaleSvcManager.js.map +1 -1
  13. package/dist/devices/OpalIceMaker/Managers/OpalFilterMaintenanceSvcManager.d.ts.map +1 -1
  14. package/dist/devices/OpalIceMaker/Managers/OpalFilterMaintenanceSvcManager.js +3 -1
  15. package/dist/devices/OpalIceMaker/Managers/OpalFilterMaintenanceSvcManager.js.map +1 -1
  16. package/dist/devices/OpalIceMaker/Managers/OpalPowerSvcManager.js +1 -1
  17. package/dist/devices/OpalIceMaker/Managers/OpalPowerSvcManager.js.map +1 -1
  18. package/dist/devices/OpalIceMaker/Managers/OpalProgressSvcManager.d.ts +1 -1
  19. package/dist/devices/OpalIceMaker/Managers/OpalProgressSvcManager.d.ts.map +1 -1
  20. package/dist/devices/OpalIceMaker/Managers/OpalProgressSvcManager.js +12 -5
  21. package/dist/devices/OpalIceMaker/Managers/OpalProgressSvcManager.js.map +1 -1
  22. package/dist/devices/OpalIceMaker/Managers/StatusManagers/OpalStatusBase.d.ts.map +1 -1
  23. package/dist/devices/OpalIceMaker/Managers/StatusManagers/OpalStatusBase.js +4 -2
  24. package/dist/devices/OpalIceMaker/Managers/StatusManagers/OpalStatusBase.js.map +1 -1
  25. package/dist/devices/OpalIceMaker/OpalDeviceBase.d.ts +3 -4
  26. package/dist/devices/OpalIceMaker/OpalDeviceBase.d.ts.map +1 -1
  27. package/dist/devices/OpalIceMaker/OpalDeviceBase.js +3 -18
  28. package/dist/devices/OpalIceMaker/OpalDeviceBase.js.map +1 -1
  29. package/dist/devices/advantium.d.ts +10 -0
  30. package/dist/devices/advantium.d.ts.map +1 -0
  31. package/dist/devices/advantium.js +75 -0
  32. package/dist/devices/advantium.js.map +1 -0
  33. package/dist/devices/airConditioner.d.ts +11 -2
  34. package/dist/devices/airConditioner.d.ts.map +1 -1
  35. package/dist/devices/airConditioner.js +108 -17
  36. package/dist/devices/airConditioner.js.map +1 -1
  37. package/dist/devices/beverageCenter.d.ts +10 -0
  38. package/dist/devices/beverageCenter.d.ts.map +1 -0
  39. package/dist/devices/beverageCenter.js +125 -0
  40. package/dist/devices/beverageCenter.js.map +1 -0
  41. package/dist/devices/clothesDryer.d.ts +21 -0
  42. package/dist/devices/clothesDryer.d.ts.map +1 -0
  43. package/dist/devices/clothesDryer.js +240 -0
  44. package/dist/devices/clothesDryer.js.map +1 -0
  45. package/dist/devices/clothesWasher.d.ts +21 -0
  46. package/dist/devices/clothesWasher.d.ts.map +1 -0
  47. package/dist/devices/clothesWasher.js +251 -0
  48. package/dist/devices/clothesWasher.js.map +1 -0
  49. package/dist/devices/coffeeMaker.d.ts +10 -0
  50. package/dist/devices/coffeeMaker.d.ts.map +1 -0
  51. package/dist/devices/coffeeMaker.js +79 -0
  52. package/dist/devices/coffeeMaker.js.map +1 -0
  53. package/dist/devices/device.d.ts +107 -13
  54. package/dist/devices/device.d.ts.map +1 -1
  55. package/dist/devices/device.js +386 -60
  56. package/dist/devices/device.js.map +1 -1
  57. package/dist/devices/dishwasher.d.ts +9 -3
  58. package/dist/devices/dishwasher.d.ts.map +1 -1
  59. package/dist/devices/dishwasher.js +142 -29
  60. package/dist/devices/dishwasher.js.map +1 -1
  61. package/dist/devices/hood.d.ts +41 -0
  62. package/dist/devices/hood.d.ts.map +1 -0
  63. package/dist/devices/hood.js +332 -0
  64. package/dist/devices/hood.js.map +1 -0
  65. package/dist/devices/microwave.d.ts +19 -0
  66. package/dist/devices/microwave.d.ts.map +1 -0
  67. package/dist/devices/microwave.js +144 -0
  68. package/dist/devices/microwave.js.map +1 -0
  69. package/dist/devices/oven.d.ts +9 -2
  70. package/dist/devices/oven.d.ts.map +1 -1
  71. package/dist/devices/oven.js +245 -43
  72. package/dist/devices/oven.js.map +1 -1
  73. package/dist/devices/refrigerator.d.ts +37 -2
  74. package/dist/devices/refrigerator.d.ts.map +1 -1
  75. package/dist/devices/refrigerator.js +548 -34
  76. package/dist/devices/refrigerator.js.map +1 -1
  77. package/dist/devices/waterFilter.d.ts +10 -0
  78. package/dist/devices/waterFilter.d.ts.map +1 -0
  79. package/dist/devices/waterFilter.js +67 -0
  80. package/dist/devices/waterFilter.js.map +1 -0
  81. package/dist/devices/waterHeater.d.ts +19 -0
  82. package/dist/devices/waterHeater.d.ts.map +1 -0
  83. package/dist/devices/waterHeater.js +158 -0
  84. package/dist/devices/waterHeater.js.map +1 -0
  85. package/dist/devices/waterSoftener.d.ts +10 -0
  86. package/dist/devices/waterSoftener.d.ts.map +1 -0
  87. package/dist/devices/waterSoftener.js +67 -0
  88. package/dist/devices/waterSoftener.js.map +1 -0
  89. package/dist/getAccessToken.d.ts.map +1 -1
  90. package/dist/getAccessToken.js +6 -0
  91. package/dist/getAccessToken.js.map +1 -1
  92. package/dist/platform.d.ts +25 -1
  93. package/dist/platform.d.ts.map +1 -1
  94. package/dist/platform.js +548 -70
  95. package/dist/platform.js.map +1 -1
  96. package/dist/platform.test.d.ts +2 -0
  97. package/dist/platform.test.d.ts.map +1 -0
  98. package/dist/platform.test.js +80 -0
  99. package/dist/platform.test.js.map +1 -0
  100. package/dist/settings.d.ts +23 -0
  101. package/dist/settings.d.ts.map +1 -1
  102. package/dist/settings.js +13 -0
  103. package/dist/settings.js.map +1 -1
  104. package/docs/assets/highlight.css +7 -0
  105. package/docs/assets/main.js +5 -5
  106. package/docs/assets/navigation.js +1 -0
  107. package/docs/assets/search.js +1 -0
  108. package/docs/assets/style.css +248 -226
  109. package/docs/classes/SmartHQPlatform.html +51 -56
  110. package/docs/hierarchy.html +1 -0
  111. package/docs/index.html +22 -12
  112. package/docs/interfaces/DeviceOptions.html +2 -3
  113. package/docs/interfaces/SmartHQPlatformConfig.html +6 -17
  114. package/docs/interfaces/SmartHqContext.html +6 -4
  115. package/docs/interfaces/SmartHqERDResponse.html +7 -8
  116. package/docs/interfaces/credentials.html +3 -4
  117. package/docs/interfaces/devicesConfig.html +8 -8
  118. package/docs/interfaces/options.html +7 -8
  119. package/docs/media/copilot-instructions.md +90 -0
  120. package/docs/modules.html +1 -2
  121. package/docs/variables/API_URL.html +1 -2
  122. package/docs/variables/ERD_CODES.html +1 -2
  123. package/docs/variables/ERD_TYPES.html +1 -2
  124. package/docs/variables/KEEPALIVE_TIMEOUT.html +1 -2
  125. package/docs/variables/LOGIN_URL.html +2 -3
  126. package/docs/variables/OAUTH2_CLIENT_ID.html +1 -2
  127. package/docs/variables/OAUTH2_CLIENT_SECRET.html +1 -2
  128. package/docs/variables/OAUTH2_REDIRECT_URI.html +1 -2
  129. package/docs/variables/PLATFORM_NAME.html +2 -3
  130. package/docs/variables/PLUGIN_NAME.html +2 -3
  131. package/docs/variables/SECURE_URL.html +2 -3
  132. package/docs/variables/default.html +1 -0
  133. package/package.json +22 -33
  134. package/typedoc.json +0 -4
  135. package/vitest.config.ts +6 -5
  136. package/.github/workflows/build.yml +0 -18
  137. package/.github/workflows/changerelease.yml +0 -11
  138. package/.github/workflows/labeler.yml +0 -9
  139. package/.github/workflows/release-drafter.yml +0 -14
  140. package/docs/assets/dmt/dmt-component-data.js +0 -1
  141. package/docs/assets/dmt/dmt-components.css +0 -20
  142. package/docs/assets/dmt/dmt-components.js +0 -67
  143. package/docs/assets/dmt/dmt-search.cmp +0 -0
  144. package/docs/assets/dmt/dmt-theme.css +0 -1
  145. package/docs/functions/default.html +0 -2
package/dist/platform.js CHANGED
@@ -4,10 +4,20 @@ import { SmartHQIceMaker } from './devices/OpalIceMaker/index.js';
4
4
  import axios from 'axios';
5
5
  import pkg from 'lodash';
6
6
  import ws from 'ws';
7
+ import { SmartHQAdvantium } from './devices/advantium.js';
7
8
  import { SmartHQAirConditioner } from './devices/airConditioner.js';
9
+ import { SmartHQBeverageCenter } from './devices/beverageCenter.js';
10
+ import { SmartHQClothesDryer } from './devices/clothesDryer.js';
11
+ import { SmartHQClothesWasher } from './devices/clothesWasher.js';
12
+ import { SmartHQCoffeeMaker } from './devices/coffeeMaker.js';
8
13
  import { SmartHQDishWasher } from './devices/dishwasher.js';
14
+ import { SmartHQHood } from './devices/hood.js';
15
+ import { SmartHQMicrowave } from './devices/microwave.js';
9
16
  import { SmartHQOven } from './devices/oven.js';
10
17
  import { SmartHQRefrigerator } from './devices/refrigerator.js';
18
+ import { SmartHQWaterFilter } from './devices/waterFilter.js';
19
+ import { SmartHQWaterHeater } from './devices/waterHeater.js';
20
+ import { SmartHQWaterSoftener } from './devices/waterSoftener.js';
11
21
  import getAccessToken, { refreshAccessToken } from './getAccessToken.js';
12
22
  import { API_URL, ERD_CODES, ERD_TYPES, KEEPALIVE_TIMEOUT, PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
13
23
  const { find } = pkg;
@@ -33,6 +43,9 @@ export class SmartHQPlatform {
33
43
  platformUpdateRate;
34
44
  debugMode;
35
45
  version;
46
+ // Matter support tracking
47
+ matterEnabled = false;
48
+ matterAvailable = false;
36
49
  constructor(log, config, api) {
37
50
  this.accessories = [];
38
51
  this.api = api;
@@ -60,6 +73,8 @@ export class SmartHQPlatform {
60
73
  this.Service = this.api.hap.Service;
61
74
  this.Characteristic = this.api.hap.Characteristic;
62
75
  this.debugLog(`Finished initializing platform: ${config.name}`);
76
+ // Check Matter availability and enabled status
77
+ this.checkMatterSupport();
63
78
  // verify the config
64
79
  (async () => {
65
80
  try {
@@ -112,17 +127,57 @@ export class SmartHQPlatform {
112
127
  }
113
128
  }
114
129
  async startRefreshTokenLogic() {
130
+ if (!this.tokenSet) {
131
+ throw new Error('Token set is undefined');
132
+ }
115
133
  if (this.tokenSet.refresh_token) {
116
134
  try {
117
135
  this.tokenSet = await refreshAccessToken(this.tokenSet.refresh_token);
118
136
  }
119
137
  catch (e) {
120
- await this.errorLog(`Failed to refresh Access Token, Error Message: ${e.message ?? e}, Submit Bugs Here: https://bit.ly/smarthq-bug-report`);
138
+ await this.errorLog(`Failed to refresh Access Token, Error Message: ${e.message ?? e}`);
139
+ // Handle invalid_grant error (expired/revoked refresh token)
140
+ if (e.error === 'invalid_grant' || e.message?.includes('invalid_grant') || e.message?.includes('Invalid refresh token')) {
141
+ await this.warnLog('Refresh token is invalid or expired. Attempting to re-authenticate with username and password...');
142
+ // Try to get a new token using username/password
143
+ const { username, password } = this.config.credentials ?? {};
144
+ if (username && password) {
145
+ try {
146
+ this.tokenSet = await getAccessToken(username, password);
147
+ await this.successLog('Successfully re-authenticated with credentials');
148
+ // Set up axios with new token
149
+ if (this.tokenSet.access_token) {
150
+ axios.defaults.headers.common = {
151
+ Authorization: `Bearer ${this.tokenSet.access_token}`,
152
+ };
153
+ // Schedule next refresh
154
+ if (this.tokenSet.expires_in) {
155
+ setTimeout(this.startRefreshTokenLogic.bind(this), 1000 * (this.tokenSet.expires_in - 2000));
156
+ }
157
+ return; // Successfully recovered
158
+ }
159
+ }
160
+ catch (reAuthError) {
161
+ await this.errorLog(`Failed to re-authenticate: ${reAuthError.message ?? reAuthError}`);
162
+ await this.errorLog('Please verify your SmartHQ credentials are correct in the Homebridge config');
163
+ await this.errorLog('You may need to log in to the GE SmartHQ app to ensure your account is active');
164
+ }
165
+ }
166
+ else {
167
+ await this.errorLog('No credentials available for re-authentication');
168
+ await this.errorLog('Please ensure username and password are set in your Homebridge config');
169
+ }
170
+ }
171
+ await this.errorLog('Submit Bugs Here: https://bit.ly/smarthq-bug-report');
172
+ throw e; // Re-throw to stop execution only if recovery failed
121
173
  }
122
174
  }
123
175
  else {
124
176
  throw new Error('Refresh token is undefined');
125
177
  }
178
+ if (!this.tokenSet.access_token) {
179
+ throw new Error('Access token is undefined after refresh');
180
+ }
126
181
  axios.defaults.headers.common = {
127
182
  Authorization: `Bearer ${this.tokenSet.access_token}`,
128
183
  };
@@ -148,12 +203,14 @@ export class SmartHQPlatform {
148
203
  }
149
204
  catch (e) {
150
205
  await this.errorLog(`discoverDevices, Failed to get Access Token, Error Message: ${e.message ?? e}, Submit Bugs Here: https://bit.ly/smarthq-bug-report`);
206
+ return; // Stop execution if authentication fails
151
207
  }
152
208
  try {
153
209
  await this.startRefreshTokenLogic();
154
210
  }
155
211
  catch (e) {
156
212
  await this.errorLog(`discoverDevices, Failed to start Refresh Token Logic, Error Message: ${e.message ?? e}, Submit Bugs Here: https://bit.ly/smarthq-bug-report`);
213
+ return; // Stop execution if token refresh setup fails
157
214
  }
158
215
  try {
159
216
  const wssData = await axios.get('/websocket');
@@ -222,9 +279,41 @@ export class SmartHQPlatform {
222
279
  await this.createSmartHQIceMaker(userId, device, details, features);
223
280
  break;
224
281
  case 'Air Conditioner':
282
+ case 'Portable AC':
225
283
  case 'Split Air Conditioner':
226
284
  await this.createSmartHQAirConditioner(userId, device, details, features);
227
285
  break;
286
+ case 'Hood':
287
+ await this.createSmartHQHood(userId, device, details, features);
288
+ break;
289
+ case 'Clothes Washer':
290
+ await this.createSmartHQClothesWasher(userId, device, details, features);
291
+ break;
292
+ case 'Clothes Dryer':
293
+ await this.createSmartHQClothesDryer(userId, device, details, features);
294
+ break;
295
+ case 'Whole Home Water Filter':
296
+ await this.createSmartHQWaterFilter(userId, device, details, features);
297
+ break;
298
+ case 'Whole Home Water Softener':
299
+ await this.createSmartHQWaterSoftener(userId, device, details, features);
300
+ break;
301
+ case 'Whole Home Water Heater':
302
+ await this.createSmartHQWaterHeater(userId, device, details, features);
303
+ break;
304
+ case 'Advantium':
305
+ await this.createSmartHQAdvantium(userId, device, details, features);
306
+ break;
307
+ case 'Microwave':
308
+ await this.createSmartHQMicrowave(userId, device, details, features);
309
+ break;
310
+ case 'Coffee Maker':
311
+ case 'Espresso Maker':
312
+ await this.createSmartHQCoffeeMaker(userId, device, details, features);
313
+ break;
314
+ case 'Beverage Center':
315
+ await this.createSmartHQBeverageCenter(userId, device, details, features);
316
+ break;
228
317
  default:
229
318
  await this.warnLog(`Device Type Not Supported: ${device.type}`);
230
319
  break;
@@ -240,6 +329,86 @@ export class SmartHQPlatform {
240
329
  }
241
330
  }
242
331
  async createSmartHQDishWasher(userId, device, details, features) {
332
+ // Merge device data
333
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
334
+ // Determine protocol (Matter or HAP)
335
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
336
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
337
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
338
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
339
+ if (existingAccessory) {
340
+ // the accessory already exists
341
+ if (!deviceData.hide_device) {
342
+ existingAccessory.context.device = deviceData;
343
+ existingAccessory.context = { device: deviceData, userId };
344
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
345
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
346
+ this.api.updatePlatformAccessories([existingAccessory]);
347
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
348
+ new SmartHQDishWasher(this, existingAccessory, deviceData);
349
+ await this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
350
+ }
351
+ else {
352
+ this.unregisterPlatformAccessories(existingAccessory);
353
+ }
354
+ }
355
+ else if (!deviceData.hide_device && !existingAccessory) {
356
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
357
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
358
+ accessory.context.device = deviceData;
359
+ accessory.context = { device: deviceData, userId };
360
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
361
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
362
+ new SmartHQDishWasher(this, accessory, deviceData);
363
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
364
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
365
+ this.accessories.push(accessory);
366
+ }
367
+ else {
368
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
369
+ }
370
+ }
371
+ async createSmartHQOven(userId, device, details, features) {
372
+ // Merge device data
373
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
374
+ // Determine protocol (Matter or HAP)
375
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
376
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
377
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
378
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
379
+ if (existingAccessory) {
380
+ // the accessory already exists
381
+ if (!deviceData.hide_device) {
382
+ existingAccessory.context.device = deviceData;
383
+ existingAccessory.context = { device: deviceData, userId };
384
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
385
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
386
+ this.api.updatePlatformAccessories([existingAccessory]);
387
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
388
+ new SmartHQOven(this, existingAccessory, deviceData);
389
+ await this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
390
+ }
391
+ else {
392
+ this.unregisterPlatformAccessories(existingAccessory);
393
+ }
394
+ }
395
+ else if (!deviceData.hide_device && !existingAccessory) {
396
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
397
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
398
+ accessory.context.device = deviceData;
399
+ accessory.context = { device: deviceData, userId };
400
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
401
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
402
+ new SmartHQOven(this, accessory, deviceData);
403
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
404
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
405
+ this.accessories.push(accessory);
406
+ }
407
+ else {
408
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
409
+ }
410
+ }
411
+ async createSmartHQIceMaker(userId, device, details, features) {
243
412
  const uuid = this.api.hap.uuid.generate(device.applianceId);
244
413
  // see if an accessory with the same uuid has already been registered and restored from
245
414
  // the cached devices we stored in the `configureAccessory` method above
@@ -254,10 +423,9 @@ export class SmartHQPlatform {
254
423
  existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
255
424
  this.api.updatePlatformAccessories([existingAccessory]);
256
425
  // Restore accessory
257
- this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
258
426
  // create the accessory handler for the restored accessory
259
427
  // this is imported from `platformAccessory.ts`
260
- new SmartHQDishWasher(this, existingAccessory, device);
428
+ new SmartHQIceMaker(this, existingAccessory, device);
261
429
  this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
262
430
  }
263
431
  else {
@@ -276,7 +444,7 @@ export class SmartHQPlatform {
276
444
  // the accessory does not yet exist, so we need to create it
277
445
  // create the accessory handler for the newly create accessory
278
446
  // this is imported from `platformAccessory.ts`
279
- new SmartHQDishWasher(this, accessory, device);
447
+ new SmartHQIceMaker(this, accessory, device);
280
448
  this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
281
449
  // link the accessory to your platform
282
450
  this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
@@ -286,26 +454,220 @@ export class SmartHQPlatform {
286
454
  this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
287
455
  }
288
456
  }
289
- async createSmartHQOven(userId, device, details, features) {
290
- const uuid = this.api.hap.uuid.generate(device.applianceId);
291
- // see if an accessory with the same uuid has already been registered and restored from
292
- // the cached devices we stored in the `configureAccessory` method above
457
+ /**
458
+ * Create Refrigerator accessory (unified HAP/Matter)
459
+ * The SmartHQRefrigerator class now handles both protocols internally
460
+ */
461
+ async createSmartHQRefrigerator(userId, device, details, features) {
462
+ // Merge device data
463
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
464
+ // Determine protocol (Matter or HAP)
465
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
466
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
293
467
  const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
468
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
294
469
  if (existingAccessory) {
295
470
  // the accessory already exists
471
+ if (!deviceData.hide_device) {
472
+ existingAccessory.context.device = deviceData;
473
+ existingAccessory.context = { device: deviceData, userId };
474
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
475
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
476
+ this.api.updatePlatformAccessories([existingAccessory]);
477
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
478
+ new SmartHQRefrigerator(this, existingAccessory, deviceData);
479
+ await this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
480
+ }
481
+ else {
482
+ this.unregisterPlatformAccessories(existingAccessory);
483
+ }
484
+ }
485
+ else if (!deviceData.hide_device && !existingAccessory) {
486
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
487
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
488
+ accessory.context.device = deviceData;
489
+ accessory.context = { device: deviceData, userId };
490
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
491
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
492
+ new SmartHQRefrigerator(this, accessory, deviceData);
493
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
494
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
495
+ this.accessories.push(accessory);
496
+ }
497
+ else {
498
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
499
+ }
500
+ }
501
+ async createSmartHQAirConditioner(userId, device, details, features) {
502
+ // Merge device data
503
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
504
+ // Determine protocol (Matter or HAP)
505
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
506
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
507
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
508
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
509
+ if (existingAccessory) {
510
+ // the accessory already exists
511
+ if (!deviceData.hide_device) {
512
+ existingAccessory.context.device = deviceData;
513
+ existingAccessory.context = { device: deviceData, userId };
514
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
515
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
516
+ this.api.updatePlatformAccessories([existingAccessory]);
517
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
518
+ new SmartHQAirConditioner(this, existingAccessory, deviceData);
519
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
520
+ }
521
+ else {
522
+ this.unregisterPlatformAccessories(existingAccessory);
523
+ }
524
+ }
525
+ else if (!deviceData.hide_device && !existingAccessory) {
526
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
527
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
528
+ accessory.context.device = deviceData;
529
+ accessory.context = { device: deviceData, userId };
530
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
531
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
532
+ new SmartHQAirConditioner(this, accessory, deviceData);
533
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
534
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
535
+ this.accessories.push(accessory);
536
+ }
537
+ else {
538
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
539
+ }
540
+ }
541
+ async createSmartHQHood(userId, device, details, features) {
542
+ // Merge device data
543
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
544
+ // Determine protocol (Matter or HAP)
545
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
546
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
547
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
548
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
549
+ if (existingAccessory) {
550
+ if (!deviceData.hide_device) {
551
+ existingAccessory.context.device = deviceData;
552
+ existingAccessory.context = { device: deviceData, userId };
553
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
554
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
555
+ this.api.updatePlatformAccessories([existingAccessory]);
556
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
557
+ new SmartHQHood(this, existingAccessory, deviceData);
558
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
559
+ }
560
+ else {
561
+ this.unregisterPlatformAccessories(existingAccessory);
562
+ }
563
+ }
564
+ else if (!deviceData.hide_device && !existingAccessory) {
565
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
566
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
567
+ accessory.context.device = deviceData;
568
+ accessory.context = { device: deviceData, userId };
569
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
570
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
571
+ new SmartHQHood(this, accessory, deviceData);
572
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
573
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
574
+ this.accessories.push(accessory);
575
+ }
576
+ else {
577
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
578
+ }
579
+ }
580
+ async createSmartHQClothesWasher(userId, device, details, features) {
581
+ // Merge device data
582
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
583
+ // Determine protocol (Matter or HAP)
584
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
585
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
586
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
587
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
588
+ if (existingAccessory) {
589
+ if (!deviceData.hide_device) {
590
+ existingAccessory.context.device = deviceData;
591
+ existingAccessory.context = { device: deviceData, userId };
592
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
593
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
594
+ this.api.updatePlatformAccessories([existingAccessory]);
595
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
596
+ new SmartHQClothesWasher(this, existingAccessory, deviceData);
597
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
598
+ }
599
+ else {
600
+ this.unregisterPlatformAccessories(existingAccessory);
601
+ }
602
+ }
603
+ else if (!deviceData.hide_device && !existingAccessory) {
604
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
605
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
606
+ accessory.context.device = deviceData;
607
+ accessory.context = { device: deviceData, userId };
608
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
609
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
610
+ new SmartHQClothesWasher(this, accessory, deviceData);
611
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
612
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
613
+ this.accessories.push(accessory);
614
+ }
615
+ else {
616
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
617
+ }
618
+ }
619
+ async createSmartHQClothesDryer(userId, device, details, features) {
620
+ // Merge device data
621
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
622
+ // Determine protocol (Matter or HAP)
623
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
624
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
625
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
626
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
627
+ if (existingAccessory) {
628
+ if (!deviceData.hide_device) {
629
+ existingAccessory.context.device = deviceData;
630
+ existingAccessory.context = { device: deviceData, userId };
631
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
632
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
633
+ this.api.updatePlatformAccessories([existingAccessory]);
634
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
635
+ new SmartHQClothesDryer(this, existingAccessory, deviceData);
636
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
637
+ }
638
+ else {
639
+ this.unregisterPlatformAccessories(existingAccessory);
640
+ }
641
+ }
642
+ else if (!deviceData.hide_device && !existingAccessory) {
643
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
644
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
645
+ accessory.context.device = deviceData;
646
+ accessory.context = { device: deviceData, userId };
647
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
648
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
649
+ new SmartHQClothesDryer(this, accessory, deviceData);
650
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
651
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
652
+ this.accessories.push(accessory);
653
+ }
654
+ else {
655
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
656
+ }
657
+ }
658
+ async createSmartHQWaterFilter(userId, device, details, features) {
659
+ const uuid = this.api.hap.uuid.generate(device.applianceId);
660
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
661
+ if (existingAccessory) {
296
662
  if (!device.hide_device) {
297
- // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
298
663
  existingAccessory.context.device = device;
299
664
  existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
300
665
  existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
301
666
  existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
302
667
  this.api.updatePlatformAccessories([existingAccessory]);
303
- // Restore accessory
304
668
  this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
305
- // create the accessory handler for the restored accessory
306
- // this is imported from `platformAccessory.ts`
307
- new SmartHQOven(this, existingAccessory, device);
308
- await this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
669
+ new SmartHQWaterFilter(this, existingAccessory, device);
670
+ this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
309
671
  }
310
672
  else {
311
673
  this.unregisterPlatformAccessories(existingAccessory);
@@ -314,18 +676,12 @@ export class SmartHQPlatform {
314
676
  else if (!device.hide_device && !existingAccessory) {
315
677
  this.infoLog(`Adding new accessory: ${device.nickname}`);
316
678
  const accessory = new this.api.platformAccessory(device.nickname, uuid);
317
- // store a copy of the device object in the `accessory.context`
318
- // the `context` property can be used to store any data about the accessory you may need
319
679
  accessory.context.device = device;
320
680
  accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
321
681
  accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
322
682
  accessory.context.device.firmware = device.firmware ?? await this.getVersion();
323
- // the accessory does not yet exist, so we need to create it
324
- // create the accessory handler for the newly create accessory
325
- // this is imported from `platformAccessory.ts`
326
- new SmartHQOven(this, accessory, device);
683
+ new SmartHQWaterFilter(this, accessory, device);
327
684
  this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
328
- // link the accessory to your platform
329
685
  this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
330
686
  this.accessories.push(accessory);
331
687
  }
@@ -333,24 +689,18 @@ export class SmartHQPlatform {
333
689
  this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
334
690
  }
335
691
  }
336
- async createSmartHQIceMaker(userId, device, details, features) {
692
+ async createSmartHQWaterSoftener(userId, device, details, features) {
337
693
  const uuid = this.api.hap.uuid.generate(device.applianceId);
338
- // see if an accessory with the same uuid has already been registered and restored from
339
- // the cached devices we stored in the `configureAccessory` method above
340
694
  const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
341
695
  if (existingAccessory) {
342
- // the accessory already exists
343
696
  if (!device.hide_device) {
344
- // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
345
697
  existingAccessory.context.device = device;
346
698
  existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
347
699
  existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
348
700
  existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
349
701
  this.api.updatePlatformAccessories([existingAccessory]);
350
- // Restore accessory
351
- // create the accessory handler for the restored accessory
352
- // this is imported from `platformAccessory.ts`
353
- new SmartHQIceMaker(this, existingAccessory, device);
702
+ this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
703
+ new SmartHQWaterSoftener(this, existingAccessory, device);
354
704
  this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
355
705
  }
356
706
  else {
@@ -360,18 +710,12 @@ export class SmartHQPlatform {
360
710
  else if (!device.hide_device && !existingAccessory) {
361
711
  this.infoLog(`Adding new accessory: ${device.nickname}`);
362
712
  const accessory = new this.api.platformAccessory(device.nickname, uuid);
363
- // store a copy of the device object in the `accessory.context`
364
- // the `context` property can be used to store any data about the accessory you may need
365
713
  accessory.context.device = device;
366
714
  accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
367
715
  accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
368
716
  accessory.context.device.firmware = device.firmware ?? await this.getVersion();
369
- // the accessory does not yet exist, so we need to create it
370
- // create the accessory handler for the newly create accessory
371
- // this is imported from `platformAccessory.ts`
372
- new SmartHQIceMaker(this, accessory, device);
717
+ new SmartHQWaterSoftener(this, accessory, device);
373
718
  this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
374
- // link the accessory to your platform
375
719
  this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
376
720
  this.accessories.push(accessory);
377
721
  }
@@ -379,26 +723,58 @@ export class SmartHQPlatform {
379
723
  this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
380
724
  }
381
725
  }
382
- async createSmartHQRefrigerator(userId, device, details, features) {
726
+ async createSmartHQWaterHeater(userId, device, details, features) {
727
+ // Merge device data
728
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
729
+ // Determine protocol (Matter or HAP)
730
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
731
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
732
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
733
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
734
+ if (existingAccessory) {
735
+ if (!deviceData.hide_device) {
736
+ existingAccessory.context.device = deviceData;
737
+ existingAccessory.context = { device: deviceData, userId };
738
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
739
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
740
+ this.api.updatePlatformAccessories([existingAccessory]);
741
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
742
+ new SmartHQWaterHeater(this, existingAccessory, deviceData);
743
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
744
+ }
745
+ else {
746
+ this.unregisterPlatformAccessories(existingAccessory);
747
+ }
748
+ }
749
+ else if (!deviceData.hide_device && !existingAccessory) {
750
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
751
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
752
+ accessory.context.device = deviceData;
753
+ accessory.context = { device: deviceData, userId };
754
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
755
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
756
+ new SmartHQWaterHeater(this, accessory, deviceData);
757
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
758
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
759
+ this.accessories.push(accessory);
760
+ }
761
+ else {
762
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
763
+ }
764
+ }
765
+ async createSmartHQAdvantium(userId, device, details, features) {
383
766
  const uuid = this.api.hap.uuid.generate(device.applianceId);
384
- // see if an accessory with the same uuid has already been registered and restored from
385
- // the cached devices we stored in the `configureAccessory` method above
386
767
  const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
387
768
  if (existingAccessory) {
388
- // the accessory already exists
389
769
  if (!device.hide_device) {
390
- // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
391
770
  existingAccessory.context.device = device;
392
771
  existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
393
772
  existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
394
773
  existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
395
774
  this.api.updatePlatformAccessories([existingAccessory]);
396
- // Restore accessory
397
775
  this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
398
- // create the accessory handler for the restored accessory
399
- // this is imported from `platformAccessory.ts`
400
- new SmartHQRefrigerator(this, existingAccessory, device);
401
- await this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
776
+ new SmartHQAdvantium(this, existingAccessory, device);
777
+ this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
402
778
  }
403
779
  else {
404
780
  this.unregisterPlatformAccessories(existingAccessory);
@@ -407,18 +783,12 @@ export class SmartHQPlatform {
407
783
  else if (!device.hide_device && !existingAccessory) {
408
784
  this.infoLog(`Adding new accessory: ${device.nickname}`);
409
785
  const accessory = new this.api.platformAccessory(device.nickname, uuid);
410
- // store a copy of the device object in the `accessory.context`
411
- // the `context` property can be used to store any data about the accessory you may need
412
786
  accessory.context.device = device;
413
787
  accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
414
788
  accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
415
789
  accessory.context.device.firmware = device.firmware ?? await this.getVersion();
416
- // the accessory does not yet exist, so we need to create it
417
- // create the accessory handler for the newly create accessory
418
- // this is imported from `platformAccessory.ts`
419
- new SmartHQRefrigerator(this, accessory, device);
790
+ new SmartHQAdvantium(this, accessory, device);
420
791
  this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
421
- // link the accessory to your platform
422
792
  this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
423
793
  this.accessories.push(accessory);
424
794
  }
@@ -426,25 +796,57 @@ export class SmartHQPlatform {
426
796
  this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
427
797
  }
428
798
  }
429
- async createSmartHQAirConditioner(userId, device, details, features) {
799
+ async createSmartHQMicrowave(userId, device, details, features) {
800
+ // Merge device data
801
+ const deviceData = { brand: 'GE', ...details, ...features, ...device };
802
+ // Determine protocol (Matter or HAP)
803
+ deviceData.useMatter = this.shouldUseMatter(deviceData);
804
+ const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
805
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
806
+ const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
807
+ if (existingAccessory) {
808
+ if (!deviceData.hide_device) {
809
+ existingAccessory.context.device = deviceData;
810
+ existingAccessory.context = { device: deviceData, userId };
811
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
812
+ existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
813
+ this.api.updatePlatformAccessories([existingAccessory]);
814
+ this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
815
+ new SmartHQMicrowave(this, existingAccessory, deviceData);
816
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
817
+ }
818
+ else {
819
+ this.unregisterPlatformAccessories(existingAccessory);
820
+ }
821
+ }
822
+ else if (!deviceData.hide_device && !existingAccessory) {
823
+ this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
824
+ const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
825
+ accessory.context.device = deviceData;
826
+ accessory.context = { device: deviceData, userId };
827
+ accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
828
+ accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
829
+ new SmartHQMicrowave(this, accessory, deviceData);
830
+ this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
831
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
832
+ this.accessories.push(accessory);
833
+ }
834
+ else {
835
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
836
+ }
837
+ }
838
+ async createSmartHQCoffeeMaker(userId, device, details, features) {
430
839
  const uuid = this.api.hap.uuid.generate(device.applianceId);
431
- // see if an accessory with the same uuid has already been registered and restored from
432
- // the cached devices we stored in the `configureAccessory` method above
433
840
  const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
434
841
  if (existingAccessory) {
435
- // the accessory already exists
436
842
  if (!device.hide_device) {
437
- // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
438
843
  existingAccessory.context.device = device;
439
844
  existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
440
845
  existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
441
846
  existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
442
847
  this.api.updatePlatformAccessories([existingAccessory]);
443
- // Restore accessory
444
848
  this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
445
- // create the accessory handler for the restored accessory
446
- // this is imported from `platformAccessory.ts`
447
- new SmartHQAirConditioner(this, existingAccessory, device);
849
+ new SmartHQCoffeeMaker(this, existingAccessory, device);
448
850
  this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
449
851
  }
450
852
  else {
@@ -454,18 +856,46 @@ export class SmartHQPlatform {
454
856
  else if (!device.hide_device && !existingAccessory) {
455
857
  this.infoLog(`Adding new accessory: ${device.nickname}`);
456
858
  const accessory = new this.api.platformAccessory(device.nickname, uuid);
457
- // store a copy of the device object in the `accessory.context`
458
- // the `context` property can be used to store any data about the accessory you may need
459
859
  accessory.context.device = device;
460
860
  accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
461
861
  accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
462
862
  accessory.context.device.firmware = device.firmware ?? await this.getVersion();
463
- // the accessory does not yet exist, so we need to create it
464
- // create the accessory handler for the newly create accessory
465
- // this is imported from `platformAccessory.ts`
466
- new SmartHQAirConditioner(this, accessory, device);
863
+ new SmartHQCoffeeMaker(this, accessory, device);
864
+ this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
865
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
866
+ this.accessories.push(accessory);
867
+ }
868
+ else {
869
+ this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
870
+ }
871
+ }
872
+ async createSmartHQBeverageCenter(userId, device, details, features) {
873
+ const uuid = this.api.hap.uuid.generate(device.applianceId);
874
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
875
+ if (existingAccessory) {
876
+ if (!device.hide_device) {
877
+ existingAccessory.context.device = device;
878
+ existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
879
+ existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
880
+ existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
881
+ this.api.updatePlatformAccessories([existingAccessory]);
882
+ this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
883
+ new SmartHQBeverageCenter(this, existingAccessory, device);
884
+ this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
885
+ }
886
+ else {
887
+ this.unregisterPlatformAccessories(existingAccessory);
888
+ }
889
+ }
890
+ else if (!device.hide_device && !existingAccessory) {
891
+ this.infoLog(`Adding new accessory: ${device.nickname}`);
892
+ const accessory = new this.api.platformAccessory(device.nickname, uuid);
893
+ accessory.context.device = device;
894
+ accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
895
+ accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
896
+ accessory.context.device.firmware = device.firmware ?? await this.getVersion();
897
+ new SmartHQBeverageCenter(this, accessory, device);
467
898
  this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
468
- // link the accessory to your platform
469
899
  this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
470
900
  this.accessories.push(accessory);
471
901
  }
@@ -626,5 +1056,53 @@ export class SmartHQPlatform {
626
1056
  async enablingPlatformLogging() {
627
1057
  return this.platformLogging === 'debugMode' || this.platformLogging === 'debug' || this.platformLogging === 'standard';
628
1058
  }
1059
+ /**
1060
+ * Check if Matter is available and enabled in Homebridge
1061
+ */
1062
+ checkMatterSupport() {
1063
+ // Check if Matter API is available (Homebridge 2.0+)
1064
+ const api = this.api;
1065
+ if (typeof api.isMatterAvailable === 'function') {
1066
+ this.matterAvailable = api.isMatterAvailable();
1067
+ if (!this.matterAvailable) {
1068
+ this.log.warn('Matter is not available in this version of Homebridge. Please update to Homebridge 2.0.0-beta.63 or later to use Matter.');
1069
+ }
1070
+ }
1071
+ else {
1072
+ this.log.debug('Matter API not detected - running on Homebridge < 2.0.0');
1073
+ }
1074
+ // Check if Matter is enabled by user
1075
+ if (this.matterAvailable && typeof api.isMatterEnabled === 'function') {
1076
+ this.matterEnabled = api.isMatterEnabled();
1077
+ if (!this.matterEnabled) {
1078
+ this.log.warn('Matter is available but not enabled. Please enable Matter in Homebridge settings to use Matter devices.');
1079
+ }
1080
+ else {
1081
+ this.log.info('✓ Matter is available and enabled - devices will use Matter protocol');
1082
+ }
1083
+ }
1084
+ // Log final status
1085
+ if (this.matterAvailable && this.matterEnabled) {
1086
+ this.log.success('Matter support: ENABLED - Devices will register as Matter accessories');
1087
+ }
1088
+ else {
1089
+ this.log.info('Matter support: DISABLED - Devices will register as HAP accessories');
1090
+ }
1091
+ }
1092
+ /**
1093
+ * Determine if a device should use Matter based on platform and device config
1094
+ */
1095
+ shouldUseMatter(device) {
1096
+ // If Matter isn't available or enabled, use HAP
1097
+ if (!this.matterAvailable || !this.matterEnabled) {
1098
+ return false;
1099
+ }
1100
+ // Check per-device preference (if specified in config)
1101
+ if (device.useMatter !== undefined) {
1102
+ return device.useMatter;
1103
+ }
1104
+ // Default: use Matter when available
1105
+ return true;
1106
+ }
629
1107
  }
630
1108
  //# sourceMappingURL=platform.js.map