@homebridge-plugins/homebridge-smarthq
Version:
The SmartHQ plugin allows you to interact with SmartHQ Devices in HomeKit and with Siri.
847 lines • 61.2 kB
JavaScript
import { readFileSync } from 'node:fs';
import { argv } from 'node:process';
import { SmartHQIceMaker } from './devices/OpalIceMaker/index.js';
import axios from 'axios';
import pkg from 'lodash';
import ws from 'ws';
import { SmartHQAdvantium } from './devices/advantium.js';
import { SmartHQAirConditioner } from './devices/airConditioner.js';
import { SmartHQBeverageCenter } from './devices/beverageCenter.js';
import { SmartHQClothesDryer } from './devices/clothesDryer.js';
import { SmartHQClothesWasher } from './devices/clothesWasher.js';
import { SmartHQCoffeeMaker } from './devices/coffeeMaker.js';
import { SmartHQDishWasher } from './devices/dishwasher.js';
import { SmartHQHood } from './devices/hood.js';
import { SmartHQMicrowave } from './devices/microwave.js';
import { SmartHQOven } from './devices/oven.js';
import { SmartHQRefrigerator } from './devices/refrigerator.js';
import { SmartHQWaterFilter } from './devices/waterFilter.js';
import { SmartHQWaterHeater } from './devices/waterHeater.js';
import { SmartHQWaterSoftener } from './devices/waterSoftener.js';
import getAccessToken, { refreshAccessToken } from './getAccessToken.js';
import { API_URL, ERD_CODES, ERD_TYPES, KEEPALIVE_TIMEOUT, PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
const { find } = pkg;
axios.defaults.baseURL = API_URL;
/**
* HomebridgePlatform
* This class is the main constructor for your plugin, this is where you should
* parse the user config and discover/register accessories with Homebridge.
*/
export class SmartHQPlatform {
accessories;
api;
log;
hap;
config;
Service;
Characteristic;
tokenSet;
platformConfig;
platformLogging;
platformRefreshRate;
platformPushRate;
platformUpdateRate;
debugMode;
version;
constructor(log, config, api) {
this.accessories = [];
this.api = api;
this.hap = this.api.hap;
this.log = log;
// only load if configured
if (!config) {
return;
}
// Plugin options into our config variables.
this.config = {
platform: PLATFORM_NAME,
name: config.name,
credentials: config.credentials,
devices: config.devices,
options: config.options,
deviceOptions: config.deviceOptions,
};
// Plugin Configuration
this.getPlatformLogSettings();
this.getPlatformRateSettings();
this.getPlatformConfigSettings();
this.getVersion();
// Finish initializing the platform
this.Service = this.api.hap.Service;
this.Characteristic = this.api.hap.Characteristic;
this.debugLog(`Finished initializing platform: ${config.name}`);
// verify the config
(async () => {
try {
await this.verifyConfig();
await this.debugLog('Config OK');
}
catch (e) {
await this.errorLog(`Verify Config, Error Message: ${e.message}, Submit Bugs Here: https://bit.ly/@homebridge-plugins/homebridge-smarthq-bug-report`);
this.debugErrorLog(`Verify Config, Error: ${e}`);
}
})();
// When this event is fired it means Homebridge has restored all cached accessories from disk.
// Dynamic Platform plugins should only register new accessories after this event was fired,
// in order to ensure they weren't added to homebridge already. This event can also be used
// to start discovery of new accessories.
this.api.on('didFinishLaunching', async () => {
log.debug('Executed didFinishLaunching callback');
// run the method to discover / register your devices as accessories
try {
await this.discoverDevices();
}
catch (e) {
await this.errorLog(`Failed to Discover Devices ${JSON.stringify(e.message ?? e)}`);
}
});
}
/**
* This function is invoked when homebridge restores cached accessories from disk at startup.
* It should be used to setup event handlers for characteristics and update respective values.
*/
configureAccessory(accessory) {
this.infoLog(`Loading accessory from cache: ${accessory.displayName}`);
// add the restored accessory to the accessories cache so we can track if it has already been registered
this.accessories.push(accessory);
}
/**
* Verify the config passed to the plugin is valid
*/
async verifyConfig() {
if (!this.config.credentials) {
throw new Error('No Credentials Found');
}
else {
if (!this.config.credentials.username) {
throw new Error('No Username Found');
}
if (!this.config.credentials.password) {
throw new Error('No Password Found');
}
}
}
async startRefreshTokenLogic() {
if (!this.tokenSet) {
throw new Error('Token set is undefined');
}
if (this.tokenSet.refresh_token) {
try {
this.tokenSet = await refreshAccessToken(this.tokenSet.refresh_token);
}
catch (e) {
await this.debugErrorLog(`Failed to refresh Access Token, Error Message: ${e.message ?? e}`);
// Handle invalid_grant error (expired/revoked refresh token)
if (e.error === 'invalid_grant' || e.message?.includes('invalid_grant') || e.message?.includes('Invalid refresh token')) {
await this.debugWarnLog('Refresh token is invalid or expired. Attempting to re-authenticate with username and password...');
// Try to get a new token using username/password
const { username, password } = this.config.credentials ?? {};
if (username && password) {
try {
this.tokenSet = await getAccessToken(username, password);
await this.successLog('Successfully re-authenticated with credentials');
// Set up axios with new token
if (this.tokenSet.access_token) {
axios.defaults.headers.common = {
Authorization: `Bearer ${this.tokenSet.access_token}`,
};
// Schedule next refresh
if (this.tokenSet.expires_in) {
setTimeout(this.startRefreshTokenLogic.bind(this), 1000 * (this.tokenSet.expires_in - 2000));
}
return; // Successfully recovered
}
}
catch (reAuthError) {
await this.errorLog(`Failed to re-authenticate: ${reAuthError.message ?? reAuthError}`);
await this.errorLog('Please verify your SmartHQ credentials are correct in the Homebridge config');
await this.errorLog('You may need to log in to the GE SmartHQ app to ensure your account is active');
}
}
else {
await this.errorLog('No credentials available for re-authentication');
await this.errorLog('Please ensure username and password are set in your Homebridge config');
}
}
await this.errorLog('Submit Bugs Here: https://bit.ly/smarthq-bug-report');
throw e; // Re-throw to stop execution only if recovery failed
}
}
else {
throw new Error('Refresh token is undefined');
}
if (!this.tokenSet.access_token) {
throw new Error('Access token is undefined after refresh');
}
axios.defaults.headers.common = {
Authorization: `Bearer ${this.tokenSet.access_token}`,
};
if (this.tokenSet.expires_in) {
setTimeout(this.startRefreshTokenLogic.bind(this), 1000 * (this.tokenSet.expires_in - 2000));
}
else {
throw new Error('Token expiration time is undefined');
}
}
/**
* This method is used to discover the your location and devices.
* Accessories are registered by either their DeviceClass, DeviceModel, or DeviceID
*/
async discoverDevices() {
try {
const { username, password } = this.config.credentials ?? {};
if (!username || !password) {
throw new Error('Username or password is undefined');
}
try {
this.tokenSet = await getAccessToken(username, password);
}
catch (e) {
await this.errorLog(`discoverDevices, Failed to get Access Token, Error Message: ${e.message ?? e}, Submit Bugs Here: https://bit.ly/smarthq-bug-report`);
return; // Stop execution if authentication fails
}
try {
await this.startRefreshTokenLogic();
}
catch (e) {
await this.errorLog(`discoverDevices, Failed to start Refresh Token Logic, Error Message: ${e.message ?? e}, Submit Bugs Here: https://bit.ly/smarthq-bug-report`);
return; // Stop execution if token refresh setup fails
}
try {
const wssData = await axios.get('/websocket');
const connection = new ws(wssData.data.endpoint);
connection.on('message', (data) => {
const obj = JSON.parse(data.toString());
this.debugLog(`data: ${JSON.stringify(obj)}`);
if (obj.kind === 'publish#erd') {
const accessory = find(this.accessories, a => a.context.device.applianceId === obj.item.applianceId);
if (!accessory) {
this.infoLog('Device not found in my list. Maybe we should rerun this plugin?');
return;
}
if (ERD_CODES[obj.item.erd]) {
this.debugLog(`ERD_CODES: ${ERD_CODES[obj.item.erd]}`);
this.debugLog(`obj>item>value: ${obj.item.value}`);
if (obj.item.erd === ERD_TYPES.UPPER_OVEN_LIGHT) {
const service = accessory.getService('Upper Oven Light');
if (service) {
service.updateCharacteristic(this.Characteristic.On, obj.item.value === '01');
}
}
}
}
});
connection.on('close', (_, reason) => {
this.debugLog('Connection closed');
this.debugLog(`reason: ${reason.toString()}`);
});
connection.on('open', () => {
connection.send(JSON.stringify({
kind: 'websocket#subscribe',
action: 'subscribe',
resources: ['/appliance/*/erd/*'],
}));
setInterval(() => connection.send(JSON.stringify({
kind: 'websocket#ping',
id: 'keepalive-ping',
action: 'ping',
})), KEEPALIVE_TIMEOUT);
});
}
catch (e) {
await this.errorLog(`discoverDevices, Failed to get Websocket Data, Error Message: ${e.message ?? e}, Submit Bugs Here: https://bit.ly/smarthq-bug-report`);
}
try {
const devices = await axios.get('/appliance');
const userId = devices.data.userId;
for (const device of devices.data.items) {
const [{ data: details }, { data: features }] = await Promise.all([
axios.get(`/appliance/${device.applianceId}`),
axios.get(`/appliance/${device.applianceId}/feature`),
]);
this.debugLog(`Device: ${JSON.stringify(device)}`);
switch (device.type) {
case 'Dishwasher':
await this.createSmartHQDishWasher(userId, device, details, features);
break;
case 'Oven':
await this.createSmartHQOven(userId, device, details, features);
break;
case 'Refrigerator':
await this.createSmartHQRefrigerator(userId, device, details, features);
break;
case 'Opal Nugget Ice Maker':
await this.createSmartHQIceMaker(userId, device, details, features);
break;
case 'Air Conditioner':
case 'Portable AC':
case 'Split Air Conditioner':
case 'Through Wall AC':
await this.createSmartHQAirConditioner(userId, device, details, features);
break;
case 'Hood':
await this.createSmartHQHood(userId, device, details, features);
break;
case 'Clothes Washer':
await this.createSmartHQClothesWasher(userId, device, details, features);
break;
case 'Clothes Dryer':
await this.createSmartHQClothesDryer(userId, device, details, features);
break;
case 'Whole Home Water Filter':
await this.createSmartHQWaterFilter(userId, device, details, features);
break;
case 'Whole Home Water Softener':
await this.createSmartHQWaterSoftener(userId, device, details, features);
break;
case 'Whole Home Water Heater':
await this.createSmartHQWaterHeater(userId, device, details, features);
break;
case 'Advantium':
await this.createSmartHQAdvantium(userId, device, details, features);
break;
case 'Microwave':
await this.createSmartHQMicrowave(userId, device, details, features);
break;
case 'Coffee Maker':
case 'Espresso Maker':
await this.createSmartHQCoffeeMaker(userId, device, details, features);
break;
case 'Beverage Center':
await this.createSmartHQBeverageCenter(userId, device, details, features);
break;
default:
await this.warnLog(`Device Type Not Supported: ${device.type}`);
break;
}
}
}
catch (e) {
await this.errorLog(`discoverDevices, Failed to get Devices Data, Error Message: ${e.message ?? e}, Submit Bugs Here: https://bit.ly/smarthq-bug-report`);
}
}
catch (e) {
await this.errorLog(`discoverDevices, No Device Config, Error Message: ${e.message ?? e}, Submit Bugs Here: https://bit.ly/smarthq-bug-report`);
}
}
async createSmartHQDishWasher(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
// see if an accessory with the same uuid has already been registered and restored from
// the cached devices we stored in the `configureAccessory` method above
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
// the accessory already exists
if (!device.hide_device) {
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
// Restore accessory
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
// create the accessory handler for the restored accessory
// this is imported from `platformAccessory.ts`
new SmartHQDishWasher(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
// store a copy of the device object in the `accessory.context`
// the `context` property can be used to store any data about the accessory you may need
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
// the accessory does not yet exist, so we need to create it
// create the accessory handler for the newly create accessory
// this is imported from `platformAccessory.ts`
new SmartHQDishWasher(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
// link the accessory to your platform
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQOven(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
// see if an accessory with the same uuid has already been registered and restored from
// the cached devices we stored in the `configureAccessory` method above
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
// the accessory already exists
if (!device.hide_device) {
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
// Restore accessory
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
// create the accessory handler for the restored accessory
// this is imported from `platformAccessory.ts`
new SmartHQOven(this, existingAccessory, device);
await this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
// store a copy of the device object in the `accessory.context`
// the `context` property can be used to store any data about the accessory you may need
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
// the accessory does not yet exist, so we need to create it
// create the accessory handler for the newly create accessory
// this is imported from `platformAccessory.ts`
new SmartHQOven(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
// link the accessory to your platform
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQIceMaker(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
// see if an accessory with the same uuid has already been registered and restored from
// the cached devices we stored in the `configureAccessory` method above
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
// the accessory already exists
if (!device.hide_device) {
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
// Restore accessory
// create the accessory handler for the restored accessory
// this is imported from `platformAccessory.ts`
new SmartHQIceMaker(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
// store a copy of the device object in the `accessory.context`
// the `context` property can be used to store any data about the accessory you may need
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
// the accessory does not yet exist, so we need to create it
// create the accessory handler for the newly create accessory
// this is imported from `platformAccessory.ts`
new SmartHQIceMaker(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
// link the accessory to your platform
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQRefrigerator(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
// see if an accessory with the same uuid has already been registered and restored from
// the cached devices we stored in the `configureAccessory` method above
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
// the accessory already exists
if (!device.hide_device) {
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
// Restore accessory
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
// create the accessory handler for the restored accessory
// this is imported from `platformAccessory.ts`
new SmartHQRefrigerator(this, existingAccessory, device);
await this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
// store a copy of the device object in the `accessory.context`
// the `context` property can be used to store any data about the accessory you may need
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
// the accessory does not yet exist, so we need to create it
// create the accessory handler for the newly create accessory
// this is imported from `platformAccessory.ts`
new SmartHQRefrigerator(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
// link the accessory to your platform
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQAirConditioner(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
// see if an accessory with the same uuid has already been registered and restored from
// the cached devices we stored in the `configureAccessory` method above
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
// the accessory already exists
if (!device.hide_device) {
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
// Restore accessory
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
// create the accessory handler for the restored accessory
// this is imported from `platformAccessory.ts`
new SmartHQAirConditioner(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
// store a copy of the device object in the `accessory.context`
// the `context` property can be used to store any data about the accessory you may need
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
// the accessory does not yet exist, so we need to create it
// create the accessory handler for the newly create accessory
// this is imported from `platformAccessory.ts`
new SmartHQAirConditioner(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
// link the accessory to your platform
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQHood(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
new SmartHQHood(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
new SmartHQHood(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQClothesWasher(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
// create the accessory handler for the restored accessory
new SmartHQClothesWasher(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
new SmartHQClothesWasher(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQClothesDryer(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
// create the accessory handler for the restored accessory
new SmartHQClothesDryer(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
new SmartHQClothesDryer(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQWaterFilter(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
new SmartHQWaterFilter(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
new SmartHQWaterFilter(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQWaterSoftener(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
new SmartHQWaterSoftener(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
new SmartHQWaterSoftener(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQWaterHeater(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
new SmartHQWaterHeater(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
new SmartHQWaterHeater(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQAdvantium(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
new SmartHQAdvantium(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
new SmartHQAdvantium(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQMicrowave(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
new SmartHQMicrowave(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
}
else {
this.unregisterPlatformAccessories(existingAccessory);
}
}
else if (!device.hide_device && !existingAccessory) {
this.infoLog(`Adding new accessory: ${device.nickname}`);
const accessory = new this.api.platformAccessory(device.nickname, uuid);
accessory.context.device = device;
accessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
accessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
accessory.context.device.firmware = device.firmware ?? await this.getVersion();
new SmartHQMicrowave(this, accessory, device);
this.debugLog(`${device.nickname} uuid: ${device.applianceId}`);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
else {
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.nickname)}`);
}
}
async createSmartHQCoffeeMaker(userId, device, details, features) {
const uuid = this.api.hap.uuid.generate(device.applianceId);
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory) {
if (!device.hide_device) {
existingAccessory.context.device = device;
existingAccessory.context = { device: { brand: 'GE', ...details, ...features }, userId };
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.nickname, 'nickname', device.nickname);
existingAccessory.context.device.firmware = device.firmware ?? await this.getVersion();
this.api.updatePlatformAccessories([existingAccessory]);
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName}`);
new SmartHQCoffeeMaker(this, existingAccessory, device);
this.debugLog(`${device.nickname} uuid: ${device.appl