@homebridge-plugins/homebridge-smarthq 0.5.0-beta.4 → 0.5.0-beta.40
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.
- package/.github/ISSUE_TEMPLATE/config.yml +1 -1
- package/.github/copilot-instructions.md +361 -0
- package/.github/scripts/branch-helper.sh +41 -0
- package/.github/workflows/beta-release.yml +1 -1
- package/.github/workflows/release.yml +53 -17
- package/CHANGELOG.md +563 -18
- package/MATTER.md +304 -0
- package/README.md +15 -0
- package/config.schema.json +24 -5
- package/dist/devices/OpalIceMaker/Managers/OpalDescaleSvcManager.d.ts.map +1 -1
- package/dist/devices/OpalIceMaker/Managers/OpalDescaleSvcManager.js +3 -1
- package/dist/devices/OpalIceMaker/Managers/OpalDescaleSvcManager.js.map +1 -1
- package/dist/devices/OpalIceMaker/Managers/OpalFilterMaintenanceSvcManager.d.ts.map +1 -1
- package/dist/devices/OpalIceMaker/Managers/OpalFilterMaintenanceSvcManager.js +3 -1
- package/dist/devices/OpalIceMaker/Managers/OpalFilterMaintenanceSvcManager.js.map +1 -1
- package/dist/devices/OpalIceMaker/Managers/OpalPowerSvcManager.js +1 -1
- package/dist/devices/OpalIceMaker/Managers/OpalPowerSvcManager.js.map +1 -1
- package/dist/devices/OpalIceMaker/Managers/OpalProgressSvcManager.d.ts +1 -1
- package/dist/devices/OpalIceMaker/Managers/OpalProgressSvcManager.d.ts.map +1 -1
- package/dist/devices/OpalIceMaker/Managers/OpalProgressSvcManager.js +12 -5
- package/dist/devices/OpalIceMaker/Managers/OpalProgressSvcManager.js.map +1 -1
- package/dist/devices/OpalIceMaker/Managers/StatusManagers/OpalStatusBase.d.ts.map +1 -1
- package/dist/devices/OpalIceMaker/Managers/StatusManagers/OpalStatusBase.js +4 -2
- package/dist/devices/OpalIceMaker/Managers/StatusManagers/OpalStatusBase.js.map +1 -1
- package/dist/devices/OpalIceMaker/OpalDeviceBase.d.ts +3 -4
- package/dist/devices/OpalIceMaker/OpalDeviceBase.d.ts.map +1 -1
- package/dist/devices/OpalIceMaker/OpalDeviceBase.js +3 -18
- package/dist/devices/OpalIceMaker/OpalDeviceBase.js.map +1 -1
- package/dist/devices/advantium.d.ts +10 -0
- package/dist/devices/advantium.d.ts.map +1 -0
- package/dist/devices/advantium.js +75 -0
- package/dist/devices/advantium.js.map +1 -0
- package/dist/devices/airConditioner.d.ts +11 -2
- package/dist/devices/airConditioner.d.ts.map +1 -1
- package/dist/devices/airConditioner.js +111 -17
- package/dist/devices/airConditioner.js.map +1 -1
- package/dist/devices/beverageCenter.d.ts +10 -0
- package/dist/devices/beverageCenter.d.ts.map +1 -0
- package/dist/devices/beverageCenter.js +125 -0
- package/dist/devices/beverageCenter.js.map +1 -0
- package/dist/devices/clothesDryer.d.ts +21 -0
- package/dist/devices/clothesDryer.d.ts.map +1 -0
- package/dist/devices/clothesDryer.js +273 -0
- package/dist/devices/clothesDryer.js.map +1 -0
- package/dist/devices/clothesWasher.d.ts +21 -0
- package/dist/devices/clothesWasher.d.ts.map +1 -0
- package/dist/devices/clothesWasher.js +284 -0
- package/dist/devices/clothesWasher.js.map +1 -0
- package/dist/devices/coffeeMaker.d.ts +10 -0
- package/dist/devices/coffeeMaker.d.ts.map +1 -0
- package/dist/devices/coffeeMaker.js +79 -0
- package/dist/devices/coffeeMaker.js.map +1 -0
- package/dist/devices/device.d.ts +108 -13
- package/dist/devices/device.d.ts.map +1 -1
- package/dist/devices/device.js +381 -60
- package/dist/devices/device.js.map +1 -1
- package/dist/devices/dishwasher.d.ts +9 -3
- package/dist/devices/dishwasher.d.ts.map +1 -1
- package/dist/devices/dishwasher.js +164 -29
- package/dist/devices/dishwasher.js.map +1 -1
- package/dist/devices/hood.d.ts +41 -0
- package/dist/devices/hood.d.ts.map +1 -0
- package/dist/devices/hood.js +336 -0
- package/dist/devices/hood.js.map +1 -0
- package/dist/devices/microwave.d.ts +19 -0
- package/dist/devices/microwave.d.ts.map +1 -0
- package/dist/devices/microwave.js +147 -0
- package/dist/devices/microwave.js.map +1 -0
- package/dist/devices/oven.d.ts +9 -2
- package/dist/devices/oven.d.ts.map +1 -1
- package/dist/devices/oven.js +267 -43
- package/dist/devices/oven.js.map +1 -1
- package/dist/devices/refrigerator.d.ts +37 -2
- package/dist/devices/refrigerator.d.ts.map +1 -1
- package/dist/devices/refrigerator.js +583 -34
- package/dist/devices/refrigerator.js.map +1 -1
- package/dist/devices/waterFilter.d.ts +10 -0
- package/dist/devices/waterFilter.d.ts.map +1 -0
- package/dist/devices/waterFilter.js +67 -0
- package/dist/devices/waterFilter.js.map +1 -0
- package/dist/devices/waterHeater.d.ts +19 -0
- package/dist/devices/waterHeater.d.ts.map +1 -0
- package/dist/devices/waterHeater.js +161 -0
- package/dist/devices/waterHeater.js.map +1 -0
- package/dist/devices/waterSoftener.d.ts +10 -0
- package/dist/devices/waterSoftener.d.ts.map +1 -0
- package/dist/devices/waterSoftener.js +67 -0
- package/dist/devices/waterSoftener.js.map +1 -0
- package/dist/getAccessToken.d.ts.map +1 -1
- package/dist/getAccessToken.js +190 -2
- package/dist/getAccessToken.js.map +1 -1
- package/dist/platform.d.ts +32 -1
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +853 -151
- package/dist/platform.js.map +1 -1
- package/dist/platform.test.d.ts +2 -0
- package/dist/platform.test.d.ts.map +1 -0
- package/dist/platform.test.js +80 -0
- package/dist/platform.test.js.map +1 -0
- package/dist/settings.d.ts +24 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +13 -0
- package/dist/settings.js.map +1 -1
- package/docs/assets/highlight.css +7 -0
- package/docs/assets/main.js +5 -5
- package/docs/assets/navigation.js +1 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +248 -226
- package/docs/classes/SmartHQPlatform.html +54 -56
- package/docs/hierarchy.html +1 -0
- package/docs/index.html +22 -12
- package/docs/interfaces/DeviceOptions.html +2 -3
- package/docs/interfaces/SmartHQPlatformConfig.html +6 -17
- package/docs/interfaces/SmartHqContext.html +6 -4
- package/docs/interfaces/SmartHqERDResponse.html +7 -8
- package/docs/interfaces/credentials.html +3 -4
- package/docs/interfaces/devicesConfig.html +9 -8
- package/docs/interfaces/options.html +7 -8
- package/docs/media/copilot-instructions.md +361 -0
- package/docs/modules.html +1 -2
- package/docs/variables/API_URL.html +1 -2
- package/docs/variables/ERD_CODES.html +1 -2
- package/docs/variables/ERD_TYPES.html +1 -2
- package/docs/variables/KEEPALIVE_TIMEOUT.html +1 -2
- package/docs/variables/LOGIN_URL.html +2 -3
- package/docs/variables/OAUTH2_CLIENT_ID.html +1 -2
- package/docs/variables/OAUTH2_CLIENT_SECRET.html +1 -2
- package/docs/variables/OAUTH2_REDIRECT_URI.html +1 -2
- package/docs/variables/PLATFORM_NAME.html +2 -3
- package/docs/variables/PLUGIN_NAME.html +2 -3
- package/docs/variables/SECURE_URL.html +2 -3
- package/docs/variables/default.html +1 -0
- package/package.json +22 -33
- package/typedoc.json +0 -4
- package/vitest.config.ts +6 -5
- package/.github/workflows/build.yml +0 -18
- package/.github/workflows/changerelease.yml +0 -11
- package/.github/workflows/labeler.yml +0 -9
- package/.github/workflows/release-drafter.yml +0 -14
- package/docs/assets/dmt/dmt-component-data.js +0 -1
- package/docs/assets/dmt/dmt-components.css +0 -20
- package/docs/assets/dmt/dmt-components.js +0 -67
- package/docs/assets/dmt/dmt-search.cmp +0 -0
- package/docs/assets/dmt/dmt-theme.css +0 -1
- 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}
|
|
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');
|
|
@@ -226,6 +283,37 @@ export class SmartHQPlatform {
|
|
|
226
283
|
case 'Split Air Conditioner':
|
|
227
284
|
await this.createSmartHQAirConditioner(userId, device, details, features);
|
|
228
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;
|
|
229
317
|
default:
|
|
230
318
|
await this.warnLog(`Device Type Not Supported: ${device.type}`);
|
|
231
319
|
break;
|
|
@@ -241,232 +329,786 @@ export class SmartHQPlatform {
|
|
|
241
329
|
}
|
|
242
330
|
}
|
|
243
331
|
async createSmartHQDishWasher(userId, device, details, features) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
//
|
|
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);
|
|
247
337
|
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
338
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
248
339
|
if (existingAccessory) {
|
|
249
340
|
// the accessory already exists
|
|
250
|
-
if (!
|
|
251
|
-
// if
|
|
252
|
-
existingAccessory
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
341
|
+
if (!deviceData.hide_device) {
|
|
342
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
343
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
344
|
+
// Device removed from HAP, will be registered as Matter accessory in device class
|
|
345
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
346
|
+
accessory.context.device = deviceData;
|
|
347
|
+
accessory.context = { device: deviceData, userId };
|
|
348
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
349
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
350
|
+
new SmartHQDishWasher(this, accessory, deviceData);
|
|
351
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
// Still using HAP, restore normally
|
|
355
|
+
existingAccessory.context.device = deviceData;
|
|
356
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
357
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
358
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
359
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
360
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
361
|
+
new SmartHQDishWasher(this, existingAccessory, deviceData);
|
|
362
|
+
await this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
363
|
+
}
|
|
263
364
|
}
|
|
264
365
|
else {
|
|
265
366
|
this.unregisterPlatformAccessories(existingAccessory);
|
|
266
367
|
}
|
|
267
368
|
}
|
|
268
|
-
else if (!
|
|
269
|
-
this.infoLog(`Adding new accessory: ${
|
|
270
|
-
const accessory = new this.api.platformAccessory(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
accessory.
|
|
274
|
-
accessory.context =
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
// the accessory does not yet exist, so we need to create it
|
|
278
|
-
// create the accessory handler for the newly create accessory
|
|
279
|
-
// this is imported from `platformAccessory.ts`
|
|
280
|
-
new SmartHQDishWasher(this, accessory, device);
|
|
281
|
-
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
|
|
282
|
-
// link the accessory to your platform
|
|
369
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
370
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
371
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
372
|
+
accessory.context.device = deviceData;
|
|
373
|
+
accessory.context = { device: deviceData, userId };
|
|
374
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
375
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
376
|
+
new SmartHQDishWasher(this, accessory, deviceData);
|
|
377
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
283
378
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
284
379
|
this.accessories.push(accessory);
|
|
285
380
|
}
|
|
286
381
|
else {
|
|
287
|
-
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(
|
|
382
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
288
383
|
}
|
|
289
384
|
}
|
|
290
385
|
async createSmartHQOven(userId, device, details, features) {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
//
|
|
386
|
+
// Merge device data
|
|
387
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
388
|
+
// Determine protocol (Matter or HAP)
|
|
389
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
390
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
294
391
|
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
392
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
295
393
|
if (existingAccessory) {
|
|
296
394
|
// the accessory already exists
|
|
297
|
-
if (!
|
|
298
|
-
// if
|
|
299
|
-
existingAccessory
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
395
|
+
if (!deviceData.hide_device) {
|
|
396
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
397
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
398
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
399
|
+
accessory.context.device = deviceData;
|
|
400
|
+
accessory.context = { device: deviceData, userId };
|
|
401
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
402
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
403
|
+
new SmartHQOven(this, accessory, deviceData);
|
|
404
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
existingAccessory.context.device = deviceData;
|
|
408
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
409
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
410
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
411
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
412
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
413
|
+
new SmartHQOven(this, existingAccessory, deviceData);
|
|
414
|
+
await this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
415
|
+
}
|
|
310
416
|
}
|
|
311
417
|
else {
|
|
312
418
|
this.unregisterPlatformAccessories(existingAccessory);
|
|
313
419
|
}
|
|
314
420
|
}
|
|
315
|
-
else if (!
|
|
316
|
-
this.infoLog(`Adding new accessory: ${
|
|
317
|
-
const accessory = new this.api.platformAccessory(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
accessory.
|
|
321
|
-
accessory.context =
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
// the accessory does not yet exist, so we need to create it
|
|
325
|
-
// create the accessory handler for the newly create accessory
|
|
326
|
-
// this is imported from `platformAccessory.ts`
|
|
327
|
-
new SmartHQOven(this, accessory, device);
|
|
328
|
-
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
|
|
329
|
-
// link the accessory to your platform
|
|
421
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
422
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
423
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
424
|
+
accessory.context.device = deviceData;
|
|
425
|
+
accessory.context = { device: deviceData, userId };
|
|
426
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
427
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
428
|
+
new SmartHQOven(this, accessory, deviceData);
|
|
429
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
330
430
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
331
431
|
this.accessories.push(accessory);
|
|
332
432
|
}
|
|
333
433
|
else {
|
|
334
|
-
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(
|
|
434
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
335
435
|
}
|
|
336
436
|
}
|
|
337
437
|
async createSmartHQIceMaker(userId, device, details, features) {
|
|
338
|
-
|
|
438
|
+
// Merge device data
|
|
439
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
440
|
+
// Determine protocol (Matter or HAP)
|
|
441
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
442
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
339
443
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
340
444
|
// the cached devices we stored in the `configureAccessory` method above
|
|
341
445
|
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
446
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
342
447
|
if (existingAccessory) {
|
|
343
448
|
// the accessory already exists
|
|
344
|
-
if (!
|
|
345
|
-
// if
|
|
346
|
-
existingAccessory
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
449
|
+
if (!deviceData.hide_device) {
|
|
450
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
451
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
452
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
453
|
+
accessory.context.device = deviceData;
|
|
454
|
+
accessory.context = { device: deviceData, userId };
|
|
455
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
456
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
457
|
+
new SmartHQIceMaker(this, accessory, deviceData);
|
|
458
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
|
|
462
|
+
existingAccessory.context.device = deviceData;
|
|
463
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
464
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
465
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
466
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
467
|
+
// Restore accessory
|
|
468
|
+
// create the accessory handler for the restored accessory
|
|
469
|
+
// this is imported from `platformAccessory.ts`
|
|
470
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
471
|
+
new SmartHQIceMaker(this, existingAccessory, deviceData);
|
|
472
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
473
|
+
}
|
|
356
474
|
}
|
|
357
475
|
else {
|
|
358
476
|
this.unregisterPlatformAccessories(existingAccessory);
|
|
359
477
|
}
|
|
360
478
|
}
|
|
361
|
-
else if (!
|
|
362
|
-
this.infoLog(`Adding new accessory: ${
|
|
363
|
-
const accessory = new this.api.platformAccessory(
|
|
479
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
480
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
481
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
364
482
|
// store a copy of the device object in the `accessory.context`
|
|
365
483
|
// the `context` property can be used to store any data about the accessory you may need
|
|
366
|
-
accessory.context.device =
|
|
367
|
-
accessory.context = { device:
|
|
368
|
-
accessory.displayName = await this.validateAndCleanDisplayName(
|
|
369
|
-
accessory.context.device.firmware =
|
|
484
|
+
accessory.context.device = deviceData;
|
|
485
|
+
accessory.context = { device: deviceData, userId };
|
|
486
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
487
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
370
488
|
// the accessory does not yet exist, so we need to create it
|
|
371
489
|
// create the accessory handler for the newly create accessory
|
|
372
490
|
// this is imported from `platformAccessory.ts`
|
|
373
|
-
new SmartHQIceMaker(this, accessory,
|
|
374
|
-
this.debugLog(`${
|
|
491
|
+
new SmartHQIceMaker(this, accessory, deviceData);
|
|
492
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
375
493
|
// link the accessory to your platform
|
|
376
494
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
377
495
|
this.accessories.push(accessory);
|
|
378
496
|
}
|
|
379
497
|
else {
|
|
380
|
-
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(
|
|
498
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
381
499
|
}
|
|
382
500
|
}
|
|
501
|
+
/**
|
|
502
|
+
* Create Refrigerator accessory (unified HAP/Matter)
|
|
503
|
+
* The SmartHQRefrigerator class now handles both protocols internally
|
|
504
|
+
*/
|
|
383
505
|
async createSmartHQRefrigerator(userId, device, details, features) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
//
|
|
506
|
+
// Merge device data
|
|
507
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
508
|
+
// Determine protocol (Matter or HAP)
|
|
509
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
510
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
387
511
|
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
512
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
388
513
|
if (existingAccessory) {
|
|
389
514
|
// the accessory already exists
|
|
390
|
-
if (!
|
|
391
|
-
// if
|
|
392
|
-
existingAccessory
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
515
|
+
if (!deviceData.hide_device) {
|
|
516
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
517
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
518
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
519
|
+
accessory.context.device = deviceData;
|
|
520
|
+
accessory.context = { device: deviceData, userId };
|
|
521
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
522
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
523
|
+
new SmartHQRefrigerator(this, accessory, deviceData);
|
|
524
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
existingAccessory.context.device = deviceData;
|
|
528
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
529
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
530
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
531
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
532
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
533
|
+
new SmartHQRefrigerator(this, existingAccessory, deviceData);
|
|
534
|
+
await this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
535
|
+
}
|
|
403
536
|
}
|
|
404
537
|
else {
|
|
405
538
|
this.unregisterPlatformAccessories(existingAccessory);
|
|
406
539
|
}
|
|
407
540
|
}
|
|
408
|
-
else if (!
|
|
409
|
-
this.infoLog(`Adding new accessory: ${
|
|
410
|
-
const accessory = new this.api.platformAccessory(
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
accessory.
|
|
414
|
-
accessory.context =
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
// the accessory does not yet exist, so we need to create it
|
|
418
|
-
// create the accessory handler for the newly create accessory
|
|
419
|
-
// this is imported from `platformAccessory.ts`
|
|
420
|
-
new SmartHQRefrigerator(this, accessory, device);
|
|
421
|
-
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
|
|
422
|
-
// link the accessory to your platform
|
|
541
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
542
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
543
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
544
|
+
accessory.context.device = deviceData;
|
|
545
|
+
accessory.context = { device: deviceData, userId };
|
|
546
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
547
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
548
|
+
new SmartHQRefrigerator(this, accessory, deviceData);
|
|
549
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
423
550
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
424
551
|
this.accessories.push(accessory);
|
|
425
552
|
}
|
|
426
553
|
else {
|
|
427
|
-
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(
|
|
554
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
428
555
|
}
|
|
429
556
|
}
|
|
430
557
|
async createSmartHQAirConditioner(userId, device, details, features) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
//
|
|
558
|
+
// Merge device data
|
|
559
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
560
|
+
// Determine protocol (Matter or HAP)
|
|
561
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
562
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
434
563
|
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
564
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
435
565
|
if (existingAccessory) {
|
|
436
566
|
// the accessory already exists
|
|
437
|
-
if (!
|
|
438
|
-
// if
|
|
439
|
-
existingAccessory
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
567
|
+
if (!deviceData.hide_device) {
|
|
568
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
569
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
570
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
571
|
+
accessory.context.device = deviceData;
|
|
572
|
+
accessory.context = { device: deviceData, userId };
|
|
573
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
574
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
575
|
+
new SmartHQAirConditioner(this, accessory, deviceData);
|
|
576
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
existingAccessory.context.device = deviceData;
|
|
580
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
581
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
582
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
583
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
584
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
585
|
+
new SmartHQAirConditioner(this, existingAccessory, deviceData);
|
|
586
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
587
|
+
}
|
|
450
588
|
}
|
|
451
589
|
else {
|
|
452
590
|
this.unregisterPlatformAccessories(existingAccessory);
|
|
453
591
|
}
|
|
454
592
|
}
|
|
455
|
-
else if (!
|
|
456
|
-
this.infoLog(`Adding new accessory: ${
|
|
457
|
-
const accessory = new this.api.platformAccessory(
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
accessory.
|
|
461
|
-
accessory.context =
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
this.
|
|
469
|
-
|
|
593
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
594
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
595
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
596
|
+
accessory.context.device = deviceData;
|
|
597
|
+
accessory.context = { device: deviceData, userId };
|
|
598
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
599
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
600
|
+
new SmartHQAirConditioner(this, accessory, deviceData);
|
|
601
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
602
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
603
|
+
this.accessories.push(accessory);
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
async createSmartHQHood(userId, device, details, features) {
|
|
610
|
+
// Merge device data
|
|
611
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
612
|
+
// Determine protocol (Matter or HAP)
|
|
613
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
614
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
615
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
616
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
617
|
+
if (existingAccessory) {
|
|
618
|
+
if (!deviceData.hide_device) {
|
|
619
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
620
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
621
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
622
|
+
accessory.context.device = deviceData;
|
|
623
|
+
accessory.context = { device: deviceData, userId };
|
|
624
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
625
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
626
|
+
new SmartHQHood(this, accessory, deviceData);
|
|
627
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
existingAccessory.context.device = deviceData;
|
|
631
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
632
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
633
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
634
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
635
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
636
|
+
new SmartHQHood(this, existingAccessory, deviceData);
|
|
637
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
645
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
646
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
647
|
+
accessory.context.device = deviceData;
|
|
648
|
+
accessory.context = { device: deviceData, userId };
|
|
649
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
650
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
651
|
+
new SmartHQHood(this, accessory, deviceData);
|
|
652
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
653
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
654
|
+
this.accessories.push(accessory);
|
|
655
|
+
}
|
|
656
|
+
else {
|
|
657
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
async createSmartHQClothesWasher(userId, device, details, features) {
|
|
661
|
+
// Merge device data
|
|
662
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
663
|
+
// Determine protocol (Matter or HAP)
|
|
664
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
665
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
666
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
667
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
668
|
+
if (existingAccessory) {
|
|
669
|
+
if (!deviceData.hide_device) {
|
|
670
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
671
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
672
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
673
|
+
accessory.context.device = deviceData;
|
|
674
|
+
accessory.context = { device: deviceData, userId };
|
|
675
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
676
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
677
|
+
new SmartHQClothesWasher(this, accessory, deviceData);
|
|
678
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
679
|
+
}
|
|
680
|
+
else {
|
|
681
|
+
existingAccessory.context.device = deviceData;
|
|
682
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
683
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
684
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
685
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
686
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
687
|
+
new SmartHQClothesWasher(this, existingAccessory, deviceData);
|
|
688
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
else {
|
|
692
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
696
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
697
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
698
|
+
accessory.context.device = deviceData;
|
|
699
|
+
accessory.context = { device: deviceData, userId };
|
|
700
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
701
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
702
|
+
new SmartHQClothesWasher(this, accessory, deviceData);
|
|
703
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
704
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
705
|
+
this.accessories.push(accessory);
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
async createSmartHQClothesDryer(userId, device, details, features) {
|
|
712
|
+
// Merge device data
|
|
713
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
714
|
+
// Determine protocol (Matter or HAP)
|
|
715
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
716
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
717
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
718
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
719
|
+
if (existingAccessory) {
|
|
720
|
+
if (!deviceData.hide_device) {
|
|
721
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
722
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
723
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
724
|
+
accessory.context.device = deviceData;
|
|
725
|
+
accessory.context = { device: deviceData, userId };
|
|
726
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
727
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
728
|
+
new SmartHQClothesDryer(this, accessory, deviceData);
|
|
729
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
730
|
+
}
|
|
731
|
+
else {
|
|
732
|
+
existingAccessory.context.device = deviceData;
|
|
733
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
734
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
735
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
736
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
737
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
738
|
+
new SmartHQClothesDryer(this, existingAccessory, deviceData);
|
|
739
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
747
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
748
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
749
|
+
accessory.context.device = deviceData;
|
|
750
|
+
accessory.context = { device: deviceData, userId };
|
|
751
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
752
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
753
|
+
new SmartHQClothesDryer(this, accessory, deviceData);
|
|
754
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
755
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
756
|
+
this.accessories.push(accessory);
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
async createSmartHQWaterFilter(userId, device, details, features) {
|
|
763
|
+
// Merge device data
|
|
764
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
765
|
+
// Determine protocol (Matter or HAP)
|
|
766
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
767
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
768
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
769
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
770
|
+
if (existingAccessory) {
|
|
771
|
+
if (!deviceData.hide_device) {
|
|
772
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
773
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
774
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
775
|
+
accessory.context.device = deviceData;
|
|
776
|
+
accessory.context = { device: deviceData, userId };
|
|
777
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
778
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
779
|
+
new SmartHQWaterFilter(this, accessory, deviceData);
|
|
780
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
existingAccessory.context.device = deviceData;
|
|
784
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
785
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
786
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
787
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
788
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
789
|
+
new SmartHQWaterFilter(this, existingAccessory, deviceData);
|
|
790
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
798
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
799
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
800
|
+
accessory.context.device = deviceData;
|
|
801
|
+
accessory.context = { device: deviceData, userId };
|
|
802
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
803
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
804
|
+
new SmartHQWaterFilter(this, accessory, deviceData);
|
|
805
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
806
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
807
|
+
this.accessories.push(accessory);
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
async createSmartHQWaterSoftener(userId, device, details, features) {
|
|
814
|
+
// Merge device data
|
|
815
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
816
|
+
// Determine protocol (Matter or HAP)
|
|
817
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
818
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
819
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
820
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
821
|
+
if (existingAccessory) {
|
|
822
|
+
if (!deviceData.hide_device) {
|
|
823
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
824
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
825
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
826
|
+
accessory.context.device = deviceData;
|
|
827
|
+
accessory.context = { device: deviceData, userId };
|
|
828
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
829
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
830
|
+
new SmartHQWaterSoftener(this, accessory, deviceData);
|
|
831
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
832
|
+
}
|
|
833
|
+
else {
|
|
834
|
+
existingAccessory.context.device = deviceData;
|
|
835
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
836
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
837
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
838
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
839
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
840
|
+
new SmartHQWaterSoftener(this, existingAccessory, deviceData);
|
|
841
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
849
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
850
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
851
|
+
accessory.context.device = deviceData;
|
|
852
|
+
accessory.context = { device: deviceData, userId };
|
|
853
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
854
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
855
|
+
new SmartHQWaterSoftener(this, accessory, deviceData);
|
|
856
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
857
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
858
|
+
this.accessories.push(accessory);
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
async createSmartHQWaterHeater(userId, device, details, features) {
|
|
865
|
+
// Merge device data
|
|
866
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
867
|
+
// Determine protocol (Matter or HAP)
|
|
868
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
869
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
870
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
871
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
872
|
+
if (existingAccessory) {
|
|
873
|
+
if (!deviceData.hide_device) {
|
|
874
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
875
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
876
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
877
|
+
accessory.context.device = deviceData;
|
|
878
|
+
accessory.context = { device: deviceData, userId };
|
|
879
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
880
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
881
|
+
new SmartHQWaterHeater(this, accessory, deviceData);
|
|
882
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
existingAccessory.context.device = deviceData;
|
|
886
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
887
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
888
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
889
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
890
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
891
|
+
new SmartHQWaterHeater(this, existingAccessory, deviceData);
|
|
892
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
900
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
901
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
902
|
+
accessory.context.device = deviceData;
|
|
903
|
+
accessory.context = { device: deviceData, userId };
|
|
904
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
905
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
906
|
+
new SmartHQWaterHeater(this, accessory, deviceData);
|
|
907
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
908
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
909
|
+
this.accessories.push(accessory);
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
async createSmartHQAdvantium(userId, device, details, features) {
|
|
916
|
+
// Merge device data
|
|
917
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
918
|
+
// Determine protocol (Matter or HAP)
|
|
919
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
920
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
921
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
922
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
923
|
+
if (existingAccessory) {
|
|
924
|
+
if (!deviceData.hide_device) {
|
|
925
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
926
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
927
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
928
|
+
accessory.context.device = deviceData;
|
|
929
|
+
accessory.context = { device: deviceData, userId };
|
|
930
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
931
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
932
|
+
new SmartHQAdvantium(this, accessory, deviceData);
|
|
933
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
existingAccessory.context.device = deviceData;
|
|
937
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
938
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
939
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
940
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
941
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
942
|
+
new SmartHQAdvantium(this, existingAccessory, deviceData);
|
|
943
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
else {
|
|
947
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
951
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
952
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
953
|
+
accessory.context.device = deviceData;
|
|
954
|
+
accessory.context = { device: deviceData, userId };
|
|
955
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
956
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
957
|
+
new SmartHQAdvantium(this, accessory, deviceData);
|
|
958
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
959
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
960
|
+
this.accessories.push(accessory);
|
|
961
|
+
}
|
|
962
|
+
else {
|
|
963
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
async createSmartHQMicrowave(userId, device, details, features) {
|
|
967
|
+
// Merge device data
|
|
968
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
969
|
+
// Determine protocol (Matter or HAP)
|
|
970
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
971
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
972
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
973
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
974
|
+
if (existingAccessory) {
|
|
975
|
+
if (!deviceData.hide_device) {
|
|
976
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
977
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
978
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
979
|
+
accessory.context.device = deviceData;
|
|
980
|
+
accessory.context = { device: deviceData, userId };
|
|
981
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
982
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
983
|
+
new SmartHQMicrowave(this, accessory, deviceData);
|
|
984
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
985
|
+
}
|
|
986
|
+
else {
|
|
987
|
+
existingAccessory.context.device = deviceData;
|
|
988
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
989
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
990
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
991
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
992
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
993
|
+
new SmartHQMicrowave(this, existingAccessory, deviceData);
|
|
994
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
else {
|
|
998
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
1002
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
1003
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
1004
|
+
accessory.context.device = deviceData;
|
|
1005
|
+
accessory.context = { device: deviceData, userId };
|
|
1006
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
1007
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
1008
|
+
new SmartHQMicrowave(this, accessory, deviceData);
|
|
1009
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
1010
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
1011
|
+
this.accessories.push(accessory);
|
|
1012
|
+
}
|
|
1013
|
+
else {
|
|
1014
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
async createSmartHQCoffeeMaker(userId, device, details, features) {
|
|
1018
|
+
// Merge device data
|
|
1019
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
1020
|
+
// Determine protocol (Matter or HAP)
|
|
1021
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
1022
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
1023
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
1024
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
1025
|
+
if (existingAccessory) {
|
|
1026
|
+
if (!deviceData.hide_device) {
|
|
1027
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
1028
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
1029
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
1030
|
+
accessory.context.device = deviceData;
|
|
1031
|
+
accessory.context = { device: deviceData, userId };
|
|
1032
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
1033
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
1034
|
+
new SmartHQCoffeeMaker(this, accessory, deviceData);
|
|
1035
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
1036
|
+
}
|
|
1037
|
+
else {
|
|
1038
|
+
existingAccessory.context.device = deviceData;
|
|
1039
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
1040
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
1041
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
1042
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
1043
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
1044
|
+
new SmartHQCoffeeMaker(this, existingAccessory, deviceData);
|
|
1045
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
1053
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
1054
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
1055
|
+
accessory.context.device = deviceData;
|
|
1056
|
+
accessory.context = { device: deviceData, userId };
|
|
1057
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
1058
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
1059
|
+
new SmartHQCoffeeMaker(this, accessory, deviceData);
|
|
1060
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
1061
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
1062
|
+
this.accessories.push(accessory);
|
|
1063
|
+
}
|
|
1064
|
+
else {
|
|
1065
|
+
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(deviceData.nickname)}`);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
async createSmartHQBeverageCenter(userId, device, details, features) {
|
|
1069
|
+
// Merge device data
|
|
1070
|
+
const deviceData = { brand: 'GE', ...details, ...features, ...device };
|
|
1071
|
+
// Determine protocol (Matter or HAP)
|
|
1072
|
+
deviceData.useMatter = this.shouldUseMatter(deviceData);
|
|
1073
|
+
const uuid = this.api.hap.uuid.generate(deviceData.applianceId);
|
|
1074
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
1075
|
+
const protocol = deviceData.useMatter ? 'Matter' : 'HAP';
|
|
1076
|
+
if (existingAccessory) {
|
|
1077
|
+
if (!deviceData.hide_device) {
|
|
1078
|
+
// Check if protocol changed to Matter - if so, remove from HAP bridge
|
|
1079
|
+
if (this.shouldUnregisterForMatter(existingAccessory, deviceData)) {
|
|
1080
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
1081
|
+
accessory.context.device = deviceData;
|
|
1082
|
+
accessory.context = { device: deviceData, userId };
|
|
1083
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
1084
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
1085
|
+
new SmartHQBeverageCenter(this, accessory, deviceData);
|
|
1086
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
1087
|
+
}
|
|
1088
|
+
else {
|
|
1089
|
+
existingAccessory.context.device = deviceData;
|
|
1090
|
+
existingAccessory.context = { device: deviceData, userId };
|
|
1091
|
+
existingAccessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
1092
|
+
existingAccessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
1093
|
+
this.api.updatePlatformAccessories([existingAccessory]);
|
|
1094
|
+
this.infoLog(`[${protocol}] Restoring existing accessory from cache: ${existingAccessory.displayName}`);
|
|
1095
|
+
new SmartHQBeverageCenter(this, existingAccessory, deviceData);
|
|
1096
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
else {
|
|
1100
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
else if (!deviceData.hide_device && !existingAccessory) {
|
|
1104
|
+
this.infoLog(`[${protocol}] Adding new accessory: ${deviceData.nickname}`);
|
|
1105
|
+
const accessory = new this.api.platformAccessory(deviceData.nickname, uuid);
|
|
1106
|
+
accessory.context.device = deviceData;
|
|
1107
|
+
accessory.context = { device: deviceData, userId };
|
|
1108
|
+
accessory.displayName = await this.validateAndCleanDisplayName(deviceData.nickname, 'nickname', deviceData.nickname);
|
|
1109
|
+
accessory.context.device.firmware = deviceData.firmware ?? await this.getVersion();
|
|
1110
|
+
new SmartHQBeverageCenter(this, accessory, deviceData);
|
|
1111
|
+
this.debugLog(`${deviceData.nickname} uuid: ${deviceData.applianceId}`);
|
|
470
1112
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
471
1113
|
this.accessories.push(accessory);
|
|
472
1114
|
}
|
|
@@ -627,5 +1269,65 @@ export class SmartHQPlatform {
|
|
|
627
1269
|
async enablingPlatformLogging() {
|
|
628
1270
|
return this.platformLogging === 'debugMode' || this.platformLogging === 'debug' || this.platformLogging === 'standard';
|
|
629
1271
|
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Check if Matter is available and enabled in Homebridge
|
|
1274
|
+
*/
|
|
1275
|
+
checkMatterSupport() {
|
|
1276
|
+
// Check if Matter API is available (Homebridge 2.0+)
|
|
1277
|
+
const api = this.api;
|
|
1278
|
+
if (typeof api.isMatterAvailable === 'function') {
|
|
1279
|
+
this.matterAvailable = api.isMatterAvailable();
|
|
1280
|
+
if (!this.matterAvailable) {
|
|
1281
|
+
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.');
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
else {
|
|
1285
|
+
this.log.debug('Matter API not detected - running on Homebridge < 2.0.0');
|
|
1286
|
+
}
|
|
1287
|
+
// Check if Matter is enabled by user
|
|
1288
|
+
if (this.matterAvailable && typeof api.isMatterEnabled === 'function') {
|
|
1289
|
+
this.matterEnabled = api.isMatterEnabled();
|
|
1290
|
+
if (!this.matterEnabled) {
|
|
1291
|
+
this.log.warn('Matter is available but not enabled. Please enable Matter in Homebridge settings to use Matter devices.');
|
|
1292
|
+
}
|
|
1293
|
+
else {
|
|
1294
|
+
this.log.info('✓ Matter is available and enabled - devices will use Matter protocol');
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
// Log final status
|
|
1298
|
+
if (this.matterAvailable && this.matterEnabled) {
|
|
1299
|
+
this.log.success('Matter support: ENABLED - Devices will register as Matter accessories');
|
|
1300
|
+
}
|
|
1301
|
+
else {
|
|
1302
|
+
this.log.info('Matter support: DISABLED - Devices will register as HAP accessories');
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Determine if a device should use Matter based on platform and device config
|
|
1307
|
+
*/
|
|
1308
|
+
shouldUseMatter(device) {
|
|
1309
|
+
// If Matter isn't available or enabled, use HAP
|
|
1310
|
+
if (!this.matterAvailable || !this.matterEnabled) {
|
|
1311
|
+
return false;
|
|
1312
|
+
}
|
|
1313
|
+
// Check per-device preference (if specified in config)
|
|
1314
|
+
if (device.useMatter !== undefined) {
|
|
1315
|
+
return device.useMatter;
|
|
1316
|
+
}
|
|
1317
|
+
// Default: use Matter when available
|
|
1318
|
+
return true;
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Handle accessory that needs to switch from HAP to Matter
|
|
1322
|
+
* Returns true if accessory was unregistered and needs to be recreated
|
|
1323
|
+
*/
|
|
1324
|
+
shouldUnregisterForMatter(existingAccessory, deviceData) {
|
|
1325
|
+
if (deviceData.useMatter && existingAccessory) {
|
|
1326
|
+
this.infoLog(`Removing ${existingAccessory.displayName} from HAP bridge (switching to Matter)`);
|
|
1327
|
+
this.unregisterPlatformAccessories(existingAccessory);
|
|
1328
|
+
return true;
|
|
1329
|
+
}
|
|
1330
|
+
return false;
|
|
1331
|
+
}
|
|
630
1332
|
}
|
|
631
1333
|
//# sourceMappingURL=platform.js.map
|