@elshaer/homebridge-lg-thinq
Version:
A Homebridge plugin for controlling/monitoring LG ThinQ device via LG ThinQ platform.
198 lines • 9.87 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LGThinQHomebridgePlatform = void 0;
const settings_1 = require("./settings");
const helper_1 = require("./helper");
const ThinQ_1 = require("./lib/ThinQ");
const events_1 = require("events");
const constants_1 = require("./lib/constants");
const errors_1 = require("./errors");
const characteristics_1 = __importDefault(require("./characteristics"));
/**
* 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.
*/
class LGThinQHomebridgePlatform {
constructor(log, config, api) {
this.log = log;
this.config = config;
this.api = api;
this.Service = this.api.hap.Service;
this.Characteristic = this.api.hap.Characteristic;
this.customCharacteristics = (0, characteristics_1.default)(this.api.hap.Characteristic);
// this is used to track restored cached accessories
this.accessories = [];
// enable thinq1 support
this.enable_thinq1 = false;
this.events = new events_1.EventEmitter();
this.enable_thinq1 = config.thinq1;
this.config.devices = this.config.devices || [];
this.intervalTime = (config.refresh_interval || 5) * 1000;
this.ThinQ = new ThinQ_1.ThinQ(this, config, log);
if (!config.country || !config.language || !((config.username && config.password) || config.refresh_token)) {
this.log.error('Missing required config parameter.');
return;
}
const didFinishLaunching = () => {
// run the method to discover / register your devices as accessories
this.ThinQ.isReady().then(() => {
this.log.info('Successfully connected to the ThinQ API.');
const discoverDevices = () => {
this.discoverDevices().then(async () => {
await this.startMonitor();
}).catch(err => {
if (err instanceof errors_1.NotConnectedError) {
setTimeout(() => {
discoverDevices();
}, 30000);
}
else {
this.log.error(err.message);
this.log.debug(err);
}
});
};
discoverDevices();
}).catch(err => {
var _a;
if (err.message === 'Internal Server Error' || ((_a = err.code) === null || _a === void 0 ? void 0 : _a.indexOf('ECONN')) === 0 || err instanceof errors_1.NotConnectedError) {
this.log.error('LG ThinQ internal server error, try again later.');
}
else {
this.log.error('ThinQ API is not ready. please check configuration and try again.');
}
this.log.error(err.message);
this.log.debug(err);
});
};
this.api.on('didFinishLaunching', async () => {
this.log.debug('Executed didFinishLaunching callback');
didFinishLaunching();
});
}
/**
* 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.log.info('Loading accessory from Homebridge 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);
}
async discoverDevices() {
const accessoriesToRemoveUUID = this.accessories.map(accessory => accessory.UUID);
const devices = await this.ThinQ.devices();
if (!devices.length) {
this.log.warn('No ThinQ devices in your account.');
}
for (const device of devices) {
this.log.debug('Device [' + device.name + ']: ', device.toString());
this.log.debug(JSON.stringify(device.data));
if (!this.enable_thinq1 && device.platform === constants_1.PlatformType.ThinQ1) {
this.log.debug('Thinq1 device is skipped: ', device.toString());
continue;
}
if (this.config.devices.length && !this.config.devices.find(enabled => enabled.id === device.id)) {
this.log.info('Device skipped: ', device.id);
continue;
}
this.log.info('[' + device.name + '] Setting up device!');
const setupSuccess = await this.ThinQ.setup(device);
if (!setupSuccess) {
this.log.warn('[' + device.name + '] Failed to setup device!');
continue;
}
const accessoryType = helper_1.Helper.make(device);
if (accessoryType === null) {
this.log.info('Device not supported: ' + device.platform + ': ' + device.toString());
this.ThinQ.unregister(device).then(() => {
this.log.debug(device.id, '- unregistered!');
});
continue;
}
let lgThinQDevice;
const existingAccessory = this.accessories.find(accessory => accessory.UUID === device.id);
if (existingAccessory) {
accessoriesToRemoveUUID.splice(accessoriesToRemoveUUID.indexOf(device.id), 1);
this.log.info('Restoring existing accessory:', device.toString());
existingAccessory.context.device = device;
lgThinQDevice = new accessoryType(this, existingAccessory);
}
else {
this.log.info('Adding new accessory:', device.toString());
const category = helper_1.Helper.category(device);
// create a new accessory
const accessory = new this.api.platformAccessory(device.name, device.id, category);
accessory.context.device = device;
lgThinQDevice = new accessoryType(this, accessory);
// link the accessory to your platform
this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
this.accessories.push(accessory);
}
this.events.on(device.id, lgThinQDevice.update.bind(lgThinQDevice));
// first time update
lgThinQDevice.updateAccessoryCharacteristic(device);
}
const accessoriesToRemove = this.accessories.filter(accessory => accessoriesToRemoveUUID.includes(accessory.UUID));
if (accessoriesToRemove.length) {
accessoriesToRemove.map(accessory => {
this.log.info('Removing accessory:', accessory.displayName);
this.accessories.splice(this.accessories.indexOf(accessory), 1);
});
this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, accessoriesToRemove);
}
}
async startMonitor() {
// thinq2 device
const thinq2devices = this.accessories.filter(accessory => accessory.context.device.platform === constants_1.PlatformType.ThinQ2);
if (thinq2devices.length) {
setInterval(() => {
this.ThinQ.devices().then((devices) => {
devices.filter(device => device.platform === constants_1.PlatformType.ThinQ2).forEach(device => {
this.events.emit(device.id, device.snapshot);
});
});
}, this.intervalTime); // every interval minute - backup method if mqtt not working
this.log.info('Start MQTT listener for thinq2 device');
await this.ThinQ.registerMQTTListener((data) => {
var _a, _b;
if ('data' in data && 'deviceId' in data) {
this.events.emit(data.deviceId, (_b = (_a = data.data) === null || _a === void 0 ? void 0 : _a.state) === null || _b === void 0 ? void 0 : _b.reported);
}
});
}
if (this.accessories.length <= thinq2devices.length) {
return; // no thinq1 device, stop here
}
// polling thinq1 device
this.log.info('Start polling device data every ' + this.config.refresh_interval + ' second.');
const ThinQ = this.ThinQ;
const interval = setInterval(async () => {
try {
for (const accessory of this.accessories) {
const device = accessory.context.device;
if (device.platform === constants_1.PlatformType.ThinQ1 && this.enable_thinq1) {
const deviceWithSnapshot = await ThinQ.pollMonitor(device);
if (deviceWithSnapshot.snapshot.raw !== null) {
this.events.emit(device.id, deviceWithSnapshot.snapshot);
}
}
}
}
catch (err) {
if (err instanceof errors_1.ManualProcessNeeded) {
this.log.info('Stop polling device data.');
this.log.warn(err.message);
clearInterval(interval);
return; // stop plugin here
}
}
}, this.intervalTime);
}
}
exports.LGThinQHomebridgePlatform = LGThinQHomebridgePlatform;
//# sourceMappingURL=platform.js.map