@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.
- package/.github/ISSUE_TEMPLATE/config.yml +1 -1
- package/.github/copilot-instructions.md +90 -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 +14 -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 +108 -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 +240 -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 +251 -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 +107 -13
- package/dist/devices/device.d.ts.map +1 -1
- package/dist/devices/device.js +386 -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 +142 -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 +332 -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 +144 -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 +245 -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 +548 -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 +158 -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 +6 -0
- package/dist/getAccessToken.js.map +1 -1
- package/dist/platform.d.ts +25 -1
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +548 -70
- 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 +23 -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 +51 -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 +8 -8
- package/docs/interfaces/options.html +7 -8
- package/docs/media/copilot-instructions.md +90 -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');
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
306
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
351
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
399
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|