homebridge-lg-airco
Version:
Homebridge plugin to control a Smart Thinq enabled LG airco unit. Makes use of WideQ => https://github.com/sampsyo/wideq
303 lines (271 loc) • 10.4 kB
text/typescript
import {PythonUtils} from "../utils/python-utils";
const {resolve} = require('path');
export class WideqAdapter {
private static readonly wideqFolder: string = resolve(__dirname + '../../../resources/wideq/');
private static readonly wideqScriptFile: string = 'example.py';
private readonly country: string;
private readonly language: string;
private readonly storagePath: string;
private readonly debug: boolean;
private readonly logDebug: Function;
constructor(country: string, language: string, storagePath: string, debug: boolean, debugLogger: Function) {
this.country = country;
this.language = language;
this.storagePath = storagePath;
this.logDebug = debugLogger;
}
public static async listAirCoolers(country: string, language: string, storagePath: string): Promise<Array<AirCooler>> {
console.log(storagePath);
const data: string = await PythonUtils.executePython3(this.wideqFolder, this.wideqScriptFile, ['-c', country, '-l', language, '-p', storagePath, '-v', 'ls']);
const devices = data.split('\n');
const processedDevices: AirCooler[] = [];
for (const device of devices) {
const deviceInfoValues = device.split(':');
if (deviceInfoValues.length > 1) {
const modelInfoValues = deviceInfoValues[1].split('(');
const deviceId: string = deviceInfoValues[0].trim();
const deviceType: string = modelInfoValues[0].trim();
const modelName: string = modelInfoValues[1].replace(')', '').trim();
processedDevices.push({
deviceId,
deviceType,
modelName,
country,
language
});
}
}
return processedDevices;
}
public async getStatus(deviceId: string): Promise<AirCoolerStatus> {
try {
const data: string = await PythonUtils.executePython3(WideqAdapter.wideqFolder, WideqAdapter.wideqScriptFile, ['-c', this.country, '-l', this.language, '-p', this.storagePath, this.debug ? '-v' : null, 'ac-mon', deviceId]);
this.logDebug(data);
const dataPieces: string[] = data.split(';').map(s => s.trim());
this.logDebug(dataPieces);
return {
isOn: dataPieces[0].toLowerCase() === 'on',
mode: (<any>Mode)[dataPieces[1]],
currentTempInCelsius: parseFloat(dataPieces[2].substring(4)),
targetTempInCelsius: parseFloat(dataPieces[3].substring(4)),
fanSpeed: (<any>FanSpeed)[dataPieces[4].substring(10)]
};
} catch (error) {
this.logDebug(error);
return null;
}
}
public async getCurrentPowerUsage(deviceId: string): Promise<number> {
try {
const data: string = await PythonUtils.executePython3(WideqAdapter.wideqFolder, WideqAdapter.wideqScriptFile, ['-c', this.country, '-l', this.language, '-p', this.storagePath, this.debug ? '-v' : null, 'get-power-draw', deviceId]);
this.logDebug(data);
return parseInt(data);
} catch (error) {
this.logDebug(error);
return null;
}
}
public async setPowerOnOff(deviceId: string, poweredOn: boolean): Promise<boolean> {
try {
const data: string = await PythonUtils.executePython3(WideqAdapter.wideqFolder, WideqAdapter.wideqScriptFile, ['-c', this.country, '-l', this.language, '-p', this.storagePath, this.debug ? '-v' : null, 'turn', deviceId, (poweredOn ? 'on': 'off')]);
this.logDebug(data);
return true;
} catch (error) {
this.logDebug(error);
return false;
}
}
public async setTargetTemperature(deviceId: string, temperatureInCelsius: number): Promise<boolean> {
try {
const data: string = await PythonUtils.executePython3(WideqAdapter.wideqFolder, WideqAdapter.wideqScriptFile, ['-c', this.country, '-l', this.language, '-p', this.storagePath, this.debug ? '-v' : null, 'set-temp', deviceId, (temperatureInCelsius + '')]);
this.logDebug(data);
return true;
} catch (error) {
this.logDebug(error);
return false;
}
}
public async setMode(deviceId: string, mode: Mode): Promise<boolean> {
try {
const data: string = await PythonUtils.executePython3(WideqAdapter.wideqFolder, WideqAdapter.wideqScriptFile, ['-c', this.country, '-l', this.language, '-p', this.storagePath, this.debug ? '-v' : null, 'set-mode', deviceId, mode]);
this.logDebug(data);
return true;
} catch (error) {
this.logDebug(error);
return false;
}
}
public async setFanSpeed(deviceId: string, fanSpeed: FanSpeed): Promise<boolean> {
try {
const data: string = await PythonUtils.executePython3(WideqAdapter.wideqFolder, WideqAdapter.wideqScriptFile, ['-c', this.country, '-l', this.language, '-p', this.storagePath, this.debug ? '-v' : null, 'set-speed', deviceId, fanSpeed]);
this.logDebug(data);
return true;
} catch (error) {
this.logDebug(error);
return false;
}
}
public async setSwingModeV(deviceId: string, swingModeV: VSwingMode): Promise<boolean> {
try {
const data: string = await PythonUtils.executePython3(WideqAdapter.wideqFolder, WideqAdapter.wideqScriptFile, ['-c', this.country, '-l', this.language, '-p', this.storagePath, this.debug ? '-v' : null, 'set-swing-v', deviceId, swingModeV]);
this.logDebug(data);
return true;
} catch (error) {
this.logDebug(error);
return false;
}
}
public async setSwingModeH(deviceId: string, swingModeH: HSwingMode): Promise<boolean> {
try {
const data: string = await PythonUtils.executePython3(WideqAdapter.wideqFolder, WideqAdapter.wideqScriptFile, ['-c', this.country, '-l', this.language, '-p', this.storagePath, this.debug ? '-v' : null, 'set-swing-h', deviceId, swingModeH]);
this.logDebug(data);
return true;
} catch (error) {
this.logDebug(error);
return false;
}
}
public static fanSpeedToPercentage(fanSpeed: FanSpeed): number {
switch (fanSpeed) {
case FanSpeed.SLOW:
return 12.5;
case FanSpeed.SLOW_LOW:
return 25;
case FanSpeed.LOW:
return 37.5;
case FanSpeed.LOW_MID:
return 50;
case FanSpeed.MID:
return 62.5;
case FanSpeed.MID_HIGH:
return 75;
case FanSpeed.HIGH:
return 87.5;
case FanSpeed.POWER:
return 100;
case FanSpeed.AUTO:
case FanSpeed.NATURE:
case FanSpeed.R_LOW:
case FanSpeed.R_MID:
case FanSpeed.R_HIGH:
case FanSpeed.L_LOW:
case FanSpeed.L_MID:
case FanSpeed.L_HIGH:
case FanSpeed.L_LOWR_LOW:
case FanSpeed.L_LOWR_MID:
case FanSpeed.L_LOWR_HIGH:
case FanSpeed.L_MIDR_LOW:
case FanSpeed.L_MIDR_MID:
case FanSpeed.L_MIDR_HIGH:
case FanSpeed.L_HIGHR_LOW:
case FanSpeed.L_HIGHR_MID:
case FanSpeed.L_HIGHR_HIGH:
case FanSpeed.AUTO_2:
case FanSpeed.POWER_2:
case FanSpeed.LONGPOWER:
return 0;
}
}
public static percentageToFanSpeed(percentage: number): FanSpeed {
if (percentage <= 12.5) {
return FanSpeed.SLOW;
} else if (percentage <= 25) {
return FanSpeed.SLOW_LOW;
} else if (percentage <= 37.5) {
return FanSpeed.LOW;
} else if (percentage <= 50) {
return FanSpeed.LOW_MID;
} else if (percentage <= 62.5) {
return FanSpeed.MID;
} else if (percentage <= 75) {
return FanSpeed.MID_HIGH;
} else if (percentage <= 87.5) {
return FanSpeed.HIGH;
} else if (percentage <= 100) {
return FanSpeed.POWER;
}
}
}
export interface AirCooler {
deviceId: string;
deviceType: string;
modelName: string;
country: string;
language: string;
}
export interface AirCoolerStatus {
isOn: boolean
mode: Mode,
currentTempInCelsius: number,
targetTempInCelsius: number,
fanSpeed: FanSpeed
}
/*
* WIDEQ AC related enums
* Please check ac.py for updated values & documentation
**/
export enum HSwingMode {
OFF = "OFF",
ONE = "ONE",
TWO = "TWO",
THREE = "THREE",
FOUR = "FOUR",
FIVE = "FIVE",
LEFT_HALF = "LEFT_HALF",
RIGHT_HALF = "RIGHT_HALF",
ALL = "ALL",
}
export enum VSwingMode {
OFF = "OFF",
ONE = "ONE",
TWO = "TWO",
THREE = "THREE",
FOUR = "FOUR",
FIVE = "FIVE",
SIX = "SIX",
ALL = "ALL"
}
export enum Mode {
COOL = "COOL",
DRY = "DRY",
FAN = "FAN",
AI = "AI",
HEAT = "HEAT",
//TODO: Figure out which mode settings actually work!
AIRCLEAN = "AIRCLEAN",
ACO = "ACO",
AROMA = "AROMA",
ENERGY_SAVING = "ENERGY_SAVING",
ENERGY_SAVER = "ENERGY_SAVER",
}
export enum FanSpeed {
SLOW = 'SLOW',
SLOW_LOW = 'SLOW_LOW',
LOW = 'LOW',
LOW_MID = 'LOW_MID',
MID = 'MID',
MID_HIGH = 'MID_HIGH',
HIGH = 'HIGH',
//TODO: Figure out which fan speed settings actually work!
POWER = 'POWER',
AUTO = 'AUTO',
NATURE = 'NATURE',
R_LOW = 'R_LOW',
R_MID = 'R_MID',
R_HIGH = 'R_HIGH',
L_LOW = 'L_LOW',
L_MID = 'L_MID',
L_HIGH = 'L_HIGH',
L_LOWR_LOW = 'L_LOWR_LOW',
L_LOWR_MID = 'L_LOWR_MID',
L_LOWR_HIGH = 'L_LOWR_HIGH',
L_MIDR_LOW = 'L_MIDR_LOW',
L_MIDR_MID = 'L_MIDR_MID',
L_MIDR_HIGH = 'L_MIDR_HIGH',
L_HIGHR_LOW = 'L_HIGHR_LOW',
L_HIGHR_MID = 'L_HIGHR_MID',
L_HIGHR_HIGH = 'L_HIGHR_HIGH',
AUTO_2 = 'AUTO_2',
POWER_2 = 'POWER_2',
LONGPOWER = 'LONGPOWER'
}