homebridge-panasonic-ac-platform
Version:
Homebridge platform plugin providing HomeKit support for Panasonic Comfort Cloud devices.
664 lines • 39.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* An instance of this class is created for each accessory the platform registers.
* Each accessory may expose multiple services of different service types.
*/
class IndoorUnitAccessory {
constructor(platform, accessory) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
this.platform = platform;
this.accessory = accessory;
this.sendDeviceUpdatePayload = {};
// Individual config for each device (if exists).
if (this.platform.platformConfig.devices) {
this.devConfig = this.platform.platformConfig.devices.find((item) => { var _a; return item.name === ((_a = accessory.context.device) === null || _a === void 0 ? void 0 : _a.deviceName); })
|| this.platform.platformConfig.devices.find((item) => { var _a; return item.name === ((_a = accessory.context.device) === null || _a === void 0 ? void 0 : _a.deviceGuid); });
}
// Accessory Information
(_a = this.accessory.getService(this.platform.Service.AccessoryInformation)) === null || _a === void 0 ? void 0 : _a.setCharacteristic(this.platform.Characteristic.Manufacturer, 'Panasonic').setCharacteristic(this.platform.Characteristic.Model, ((_b = accessory.context.device) === null || _b === void 0 ? void 0 : _b.deviceModuleNumber) || 'Unknown').setCharacteristic(this.platform.Characteristic.SerialNumber, ((_c = accessory.context.device) === null || _c === void 0 ? void 0 : _c.deviceGuid) || 'Unknown');
// Heater Cooler
// https://developers.homebridge.io/#/service/HeaterCooler
this.service = this.accessory.getService(this.platform.Service.HeaterCooler)
|| this.accessory.addService(this.platform.Service.HeaterCooler);
// Characteristics configuration
// Each service must implement at-minimum the "required characteristics"
// See https://developers.homebridge.io/#/service/HeaterCooler
// Name (optional)
// This is what is displayed as the default name on the Home app
this.service.setCharacteristic(this.platform.Characteristic.Name, ((_d = accessory.context.device) === null || _d === void 0 ? void 0 : _d.deviceName) || 'Unnamed');
// Active (required)
this.service.getCharacteristic(this.platform.Characteristic.Active).onSet(this.setActive.bind(this));
// Current Temperature (required)
this.service.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
.setProps({ minValue: -100, maxValue: 100, minStep: 0.01 });
// Target Heater-Cooler State (required)
this.service
.getCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState)
.onSet(this.setTargetHeaterCoolerState.bind(this));
// Rotation Speed (optional)
this.service
.getCharacteristic(this.platform.Characteristic.RotationSpeed)
.setProps({ minValue: 0, maxValue: 8, minStep: 1 })
.onSet(this.setRotationSpeed.bind(this));
// Swing Mode (optional)
this.service
.getCharacteristic(this.platform.Characteristic.SwingMode)
.onSet(this.setSwingMode.bind(this));
// Cooling Threshold Temperature (optional)
this.service
.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature)
.setProps({ minValue: 16, maxValue: 30, minStep: 0.5 })
.onSet(this.setThresholdTemperature.bind(this));
// Heating Threshold Temperature (optional)
this.service
.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature)
.setProps({ minValue: ((_e = this.devConfig) === null || _e === void 0 ? void 0 : _e.minHeatingTemperature) || 16, maxValue: 30, minStep: 0.5 })
.onSet(this.setThresholdTemperature.bind(this));
// Expose additional features - helper function
const manageService = (exposeFlag, serviceName, serviceType, // Replace with proper Homebridge Service type if available
setter = null) => {
const fullName = `${this.accessory.displayName} ${serviceName}`;
if (exposeFlag) {
const service = this.accessory.getService(fullName) || this.accessory.addService(serviceType, fullName, serviceName);
service.setCharacteristic(this.platform.Characteristic.ConfiguredName, fullName);
if (setter) {
service.getCharacteristic(this.platform.Characteristic.On).onSet(setter.bind(this));
}
this.platform.log.debug(`${this.accessory.displayName}: add ${serviceName}`);
return service;
}
else {
const service = this.accessory.getService(fullName);
if (service) {
this.accessory.removeService(service);
this.platform.log.debug(`${this.accessory.displayName}: remove ${serviceName}`);
}
}
};
// Expose additional features
manageService((_f = this.devConfig) === null || _f === void 0 ? void 0 : _f.exposeInsideTemp, 'inside temp', this.platform.Service.TemperatureSensor);
manageService((_g = this.devConfig) === null || _g === void 0 ? void 0 : _g.exposeOutdoorTemp, 'out temp', this.platform.Service.TemperatureSensor);
manageService((_h = this.devConfig) === null || _h === void 0 ? void 0 : _h.exposePower, 'power', this.platform.Service.Switch, this.setPower);
manageService((_j = this.devConfig) === null || _j === void 0 ? void 0 : _j.exposeNanoe, 'nanoe', this.platform.Service.Switch, this.setNanoe);
manageService((_k = this.devConfig) === null || _k === void 0 ? void 0 : _k.exposeInsideCleaning, 'inside cleaning', this.platform.Service.Switch, this.setInsideCleaning);
manageService((_l = this.devConfig) === null || _l === void 0 ? void 0 : _l.exposeEcoNavi, 'eco navi', this.platform.Service.Switch, this.setEcoNavi);
manageService((_m = this.devConfig) === null || _m === void 0 ? void 0 : _m.exposeEcoFunction, 'eco function', this.platform.Service.Switch, this.setEcoFunction);
manageService((_o = this.devConfig) === null || _o === void 0 ? void 0 : _o.exposeAutoMode, 'auto mode', this.platform.Service.Switch, this.setAutoMode);
manageService((_p = this.devConfig) === null || _p === void 0 ? void 0 : _p.exposeCoolMode, 'cool mode', this.platform.Service.Switch, this.setCoolMode);
manageService((_q = this.devConfig) === null || _q === void 0 ? void 0 : _q.exposeHeatMode, 'heat mode', this.platform.Service.Switch, this.setHeatMode);
manageService((_r = this.devConfig) === null || _r === void 0 ? void 0 : _r.exposeDryMode, 'dry mode', this.platform.Service.Switch, this.setDryMode);
manageService((_s = this.devConfig) === null || _s === void 0 ? void 0 : _s.exposeFanMode, 'fan mode', this.platform.Service.Switch, this.setFanMode);
// Fan Speed (special case with RotationSpeed)
if ((_t = this.devConfig) === null || _t === void 0 ? void 0 : _t.exposeFanSpeed) {
this.exposeFanSpeed = manageService(true, 'fan speed', this.platform.Service.Fan);
this.exposeFanSpeed.getCharacteristic(this.platform.Characteristic.RotationSpeed).onSet(this.setFanSpeed.bind(this));
}
else {
manageService(false, 'fan speed', this.platform.Service.Fan);
}
// Update characteristic values asynchronously instead of using onGet handlers
this.refreshDeviceStatus();
}
// ===============================================================================================================================================
/**
* Retrieves the device status from Comfort Cloud and updates its characteristics.
*/
async refreshDeviceStatus() {
let logOutput = '';
this.platform.log.debug(`${this.accessory.displayName}: refresh status`);
try {
this.deviceStatusFull = await this.platform.comfortCloud.getDeviceStatus(this.accessory.context.device.deviceGuid, this.accessory.displayName);
this.deviceStatus = this.deviceStatusFull.parameters;
// Active
if (this.deviceStatus.operate !== undefined) {
const active = this.deviceStatus.operate === 1
? this.platform.Characteristic.Active.ACTIVE
: this.platform.Characteristic.Active.INACTIVE;
this.service.updateCharacteristic(this.platform.Characteristic.Active, active);
logOutput += `${(active === 1) ? 'On' : 'Off'}`;
}
// Current Temperature
// If the temperature of the indoor unit is not available,
// default values will be used: 8°C for heating and 30°C for cooling and else.
// Temperature of 126 or higher from the API = null/failure
if (this.deviceStatus.insideTemperature < 126) {
this.service.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.deviceStatus.insideTemperature);
logOutput += `, Inside Temp. ${this.deviceStatus.insideTemperature}`;
}
else {
logOutput += ', Inside Temp. not available';
this.platform.log.debug(`${this.accessory.displayName}: Inside temperature is not available - setting default temperature`);
this.service.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, (this.deviceStatus.operationMode === 3) ? 8 : 30);
}
// Inside temperature for virtual sensor
if (this.exposeInsideTemp && this.deviceStatus.insideTemperature < 126) {
this.exposeInsideTemp.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.deviceStatus.insideTemperature);
}
// Outdoor temperature for logs
if (this.deviceStatus.outTemperature >= 126) {
logOutput += ', Outdoor Temp. not available';
}
else {
logOutput += `, Outdoor Temp. ${this.deviceStatus.outTemperature}`;
}
// Outdoor temperature for virtual sensor
// Only check and set if the user wants to display the virtual sensor showing temp from outdoor unit.
if (this.exposeOutdoorTemp && this.deviceStatus.outTemperature < 126) {
this.exposeOutdoorTemp.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.deviceStatus.outTemperature);
}
// Current Heater-Cooler State and Target Heater-Cooler State
const currentTemp = this.service.getCharacteristic(this.platform.Characteristic.CurrentTemperature).value;
const setTemp = this.deviceStatus.temperatureSet;
const { operationMode } = this.deviceStatus;
const modes = {
0: { log: 'Auto Mode', target: 'AUTO', current: currentTemp < setTemp ? 'HEATING' : currentTemp > setTemp ? 'COOLING' : 'IDLE' },
3: { log: 'Heat Mode', target: 'HEAT', current: currentTemp < setTemp ? 'HEATING' : 'IDLE' },
2: { log: 'Cool Mode', target: 'COOL', current: currentTemp > setTemp ? 'COOLING' : 'IDLE' },
1: { log: 'Dry Mode', target: 'AUTO', current: 'IDLE' },
4: { log: 'Fan Mode', target: 'AUTO', current: 'IDLE' },
};
if (modes[operationMode]) {
const { log, target, current } = modes[operationMode];
logOutput += `, ${log}`;
this.service.updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState[target]);
this.service.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.platform.Characteristic.CurrentHeaterCoolerState[current]);
}
else {
this.platform.log.error(`Unknown operation mode: '${operationMode}'`);
}
// Rotation Speed
/**
* 1) The fanSpeed value in the Comfort Cloud payload doesn't always reflect
* the current operation mode. For example, when switching from
* fan speed 4 to Quiet Mode, the fanSpeed in the payload will remain 4.
* Based on tests, ecoMode seems to take precedence and we'll check it first.
*
* 2) HomeKit automatically moves the slider into the 0 position when
* the device is switched off. We don't have to handle this case manually.
*
* 3) See README for the mapping of Comfort Cloud payload to slider position.
*/
// Check status only when device is on
if (this.deviceStatus.operate === 1) {
let sliderValue = 8; // default AUTO
if (this.deviceStatus.ecoMode === 2) {
sliderValue = 1; // Quiet Mode
logOutput += ', Speed 1 (Quiet Mode)';
}
else if (this.deviceStatus.ecoMode === 1) {
sliderValue = 7; // Powerful Mode
logOutput += ', Speed 5 (Powerful Mode)';
}
else if (this.deviceStatus.ecoMode === 0) {
const fanSpeedMap = { 0: 8, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6 };
sliderValue = fanSpeedMap[this.deviceStatus.fanSpeed] || 8;
logOutput += `, Speed ${this.deviceStatus.fanSpeed || 'Auto'}`;
}
this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed)
.updateValue(sliderValue);
}
// Swing Mode
if (this.deviceStatus.fanAutoMode !== 1) {
this.service.getCharacteristic(this.platform.Characteristic.SwingMode)
.updateValue(this.platform.Characteristic.SwingMode.SWING_ENABLED);
}
else {
this.service.getCharacteristic(this.platform.Characteristic.SwingMode)
.updateValue(this.platform.Characteristic.SwingMode.SWING_DISABLED);
}
// Expose additional features
const updateChar = (expose, condition) => expose === null || expose === void 0 ? void 0 : expose.updateCharacteristic(this.platform.Characteristic.On, condition);
const isOn = this.deviceStatus.operate === 1;
updateChar(this.exposePower, isOn);
updateChar(this.exposeNanoe, this.deviceStatus.nanoe === 2);
updateChar(this.exposeInsideCleaning, this.deviceStatus.insideCleaning === 2);
updateChar(this.exposeEcoNavi, this.deviceStatus.ecoNavi === 2);
updateChar(this.exposeEcoFunction, this.deviceStatus.ecoFunctionData === 2);
updateChar(this.exposeAutoMode, isOn && this.deviceStatus.operationMode === 0);
updateChar(this.exposeCoolMode, isOn && this.deviceStatus.operationMode === 2);
updateChar(this.exposeHeatMode, isOn && this.deviceStatus.operationMode === 3);
updateChar(this.exposeDryMode, isOn && this.deviceStatus.operationMode === 1);
updateChar(this.exposeFanMode, isOn && this.deviceStatus.operationMode === 4 && this.deviceStatus.lastSettingMode === 1);
updateChar(this.exposeNanoeStandAloneMode, isOn && this.deviceStatus.operationMode === 4 && this.deviceStatus.lastSettingMode === 2);
updateChar(this.exposeSwingUpDown, [0, 2].includes(this.deviceStatus.fanAutoMode));
updateChar(this.exposeSwingLeftRight, [0, 3].includes(this.deviceStatus.fanAutoMode));
if (isOn) {
updateChar(this.exposeQuietMode, this.deviceStatus.ecoMode === 2);
updateChar(this.exposePowerfulMode, this.deviceStatus.ecoMode === 1);
}
// Expose fan speed
if (this.exposeFanSpeed) {
const isOn = this.deviceStatus.operate === 1;
const fanSpeed = this.deviceStatus.fanSpeed;
const speedMap = { 1: 10, 2: 30, 3: 50, 4: 70, 5: 90 };
const rotationSpeed = isOn ? (speedMap[fanSpeed] || 100) : 0;
this.exposeFanSpeed.updateCharacteristic(this.platform.Characteristic.On, isOn);
this.exposeFanSpeed.updateCharacteristic(this.platform.Characteristic.RotationSpeed, rotationSpeed);
}
// Cooling Threshold Temperature (optional)
// Heating Threshold Temperature (optional)
this.service.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature)
.updateValue(setTemp);
this.service.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature)
.updateValue(setTemp);
// log
if (this.platform.platformConfig.logsLevel >= 1) {
this.platform.log.info(`${this.accessory.displayName}: ${logOutput}.`);
}
}
catch (error) {
this.platform.log.error('An error occurred while refreshing the device status. '
+ 'Turn on debug mode for more information.');
// Only log if a Promise rejection reason was provided.
// Some errors are already logged at source.
if (error) {
this.platform.log.debug(error);
}
// if you need to return an error to show the device as "Not Responding" in the Home app:
// throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
/**
* We should be able to pass an error object to the function to mark a service/accessory
* as 'Not Responding' in the Home App.
* (Only needs to be set on a single/primary characteristic of an accessory,
* and needs to be updated with a valid value when the accessory is available again.
* The error message text is for internal use only, and is not passed to the Home App.)
*
* Problem: The Typescript definitions suggest this is not permitted - commenting for now.
*/
/*
this.service.updateCharacteristic(
this.platform.Characteristic.Active,
new Error('Exception occurred in refreshDeviceStatus()'),
);
*/
}
// Schedule continuous device updates on the first run
// 10 minutes when device is on, 60 minutes device is off
clearTimeout(this.timerRefreshDeviceStatus);
this.timerRefreshDeviceStatus = null;
this.timerRefreshDeviceStatus = setTimeout(this.refreshDeviceStatus.bind(this), (this.service.getCharacteristic(this.platform.Characteristic.Active).value === 1) ? 10 * 60 * 1000 : 60 * 60 * 1000);
}
// ===============================================================================================================================================
/**
* Handle 'SET' requests from HomeKit
* These are sent when the user changes the state of an accessory,
* for example, turning on a Light bulb.
*/
async setActive(value) {
this.platform.log.debug(`${this.accessory.displayName}: setActive()`);
const parameters = {
operate: value === this.platform.Characteristic.Active.ACTIVE ? 1 : 0,
};
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: ${value === this.platform.Characteristic.Active.ACTIVE ? 'set On' : 'set Off'}`);
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
async setTargetHeaterCoolerState(value) {
this.platform.log.debug(`${this.accessory.displayName}: setTargetHeaterCoolerState()`);
const parameters = {
operate: 1,
};
switch (value) {
case this.platform.Characteristic.TargetHeaterCoolerState.AUTO:
if (this.platform.platformConfig.autoMode === 'fan') {
parameters.operationMode = 4;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Fan Mode`);
}
else if (this.platform.platformConfig.autoMode === 'dry') {
parameters.operationMode = 1;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Dry mode`);
}
else {
parameters.operationMode = 0;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Auto mode`);
}
break;
case this.platform.Characteristic.TargetHeaterCoolerState.COOL:
parameters.operationMode = 2;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Mode Cool`);
break;
case this.platform.Characteristic.TargetHeaterCoolerState.HEAT:
parameters.operationMode = 3;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Mode Heat`);
break;
default:
this.platform.log.error(`${this.accessory.displayName}: Unknown TargetHeaterCoolerState`, value);
return;
}
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
async setRotationSpeed(value) {
this.platform.log.debug(`${this.accessory.displayName}: setRotationSpeed()`);
const parameters = {};
switch (value) {
// See README for the mapping of slider position to Comfort Cloud payload.
case 0:
// HomeKit independently switches off the accessory
// in this case, which triggers setActive().
// Nothing to handle here, but documenting for clarity.
break;
case 1:
parameters.ecoMode = 2;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Quiet Mode`);
break;
case 2:
case 3:
case 4:
case 5:
case 6:
parameters.ecoMode = 0;
parameters.fanSpeed = 1;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Fan speed ${value - 1}`);
break;
case 7:
parameters.ecoMode = 1;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Powerful Mode`);
break;
case 8:
parameters.ecoMode = 0;
parameters.fanSpeed = 0;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Auto Mode`);
break;
default:
parameters.ecoMode = 0;
parameters.fanSpeed = 0;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Auto Mode`);
break;
}
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
async setSwingMode(value) {
var _a, _b, _c, _d;
this.platform.log.debug(`${this.accessory.displayName}: setSwingMode()`);
const parameters = {};
if (value === this.platform.Characteristic.SwingMode.SWING_ENABLED) {
parameters.fanAutoMode = 0;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Swing mode Auto`);
}
else if (value === this.platform.Characteristic.SwingMode.SWING_DISABLED) {
parameters.fanAutoMode = 1;
parameters.airSwingUD = (((_a = this.devConfig) === null || _a === void 0 ? void 0 : _a.swingDefaultUD) !== null) ? (_b = this.devConfig) === null || _b === void 0 ? void 0 : _b.swingDefaultUD : 2;
parameters.airSwingLR = (((_c = this.devConfig) === null || _c === void 0 ? void 0 : _c.swingDefaultLR) !== null) ? (_d = this.devConfig) === null || _d === void 0 ? void 0 : _d.swingDefaultLR : 2;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Swing mode Off`);
}
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
// Expose additional features - helper function
async setMode(modeName, value) {
this.platform.log.debug(`${this.accessory.displayName}: ${modeName}()`);
// Configuration map for different modes
const MODE_CONFIGS = {
setPower: { key: 'operate', on: 1, off: 0 },
setNanoe: { key: 'nanoe', on: 2, off: 1 },
setInsideCleaning: { key: 'insideCleaning', on: 2, off: 1 },
setEcoNavi: { key: 'ecoNavi', on: 2, off: 1 },
setEcoFunction: { key: 'ecoFunctionData', on: 2, off: 1 },
setAutoMode: { key: 'operationMode', on: 0, off: 0, operate: true },
setCoolMode: { key: 'operationMode', on: 2, off: 0, operate: true },
setHeatMode: { key: 'operationMode', on: 3, off: 0, operate: true },
setDryMode: { key: 'operationMode', on: 1, off: 0, operate: true },
setFanMode: { key: 'operationMode', on: 4, off: 0, operate: true },
setNanoeStandAloneMode: { key: 'operationMode', on: 5, off: 0, operate: true },
setQuietMode: { key: 'ecoMode', on: 2, off: 0 },
setPowerfulMode: { key: 'ecoMode', on: 1, off: 0 },
};
const config = MODE_CONFIGS[modeName];
const parameters = {};
if (config.operate) {
parameters.operate = value ? 1 : 0;
if (value) {
parameters[config.key] = config.on;
}
}
else {
parameters[config.key] = value ? config.on : config.off;
}
const logLevel = this.platform.platformConfig.logsLevel >= 1 ? 'info' : 'debug';
const state = value ? 'On' : 'Off';
this.platform.log[logLevel](`${this.accessory.displayName}: ${modeName.replace('set', '')} ${state}`);
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
// Expose additional features
async setPower(value) {
await this.setMode('setPower', value);
}
async setNanoe(value) {
await this.setMode('setNanoe', value);
}
async setInsideCleaning(value) {
await this.setMode('setInsideCleaning', value);
}
async setEcoNavi(value) {
await this.setMode('setEcoNavi', value);
}
async setEcoFunction(value) {
await this.setMode('setEcoFunction', value);
}
async setAutoMode(value) {
await this.setMode('setAutoMode', value);
}
async setCoolMode(value) {
await this.setMode('setCoolMode', value);
}
async setHeatMode(value) {
await this.setMode('setHeatMode', value);
}
async setDryMode(value) {
await this.setMode('setDryMode', value);
}
async setFanMode(value) {
await this.setMode('setFanMode', value);
}
async setNanoeStandAloneMode(value) {
await this.setMode('setNanoeStandAloneMode', value);
}
async setQuietMode(value) {
await this.setMode('setQuietMode', value);
}
async setPowerfulMode(value) {
await this.setMode('setPowerfulMode', value);
}
// set Swing Up Down
async setSwingUpDown(value) {
var _a, _b;
this.platform.log.debug(`${this.accessory.displayName}: setSwingUpDown()`);
const parameters = {};
if (value) {
// if Swing Left Right is enabled than set Swing Auto (Up Down and Left Right)
if (this.deviceStatus.fanAutoMode === 3) {
parameters.fanAutoMode = 0;
}
else {
parameters.fanAutoMode = 2;
}
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Swing Up Down On`);
}
else {
if (this.deviceStatus.fanAutoMode === 0) {
parameters.fanAutoMode = 3;
}
else {
parameters.fanAutoMode = 1;
}
parameters.airSwingUD = (((_a = this.devConfig) === null || _a === void 0 ? void 0 : _a.swingDefaultUD) !== null) ? (_b = this.devConfig) === null || _b === void 0 ? void 0 : _b.swingDefaultUD : 2;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Swing Up Down Off`);
}
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
// set Swing Left Right
async setSwingLeftRight(value) {
var _a, _b;
this.platform.log.debug(`${this.accessory.displayName}: setSwingLeftRight()`);
const parameters = {};
if (value) {
// if Swing Up Down is enabled than set Swing Auto (Up Down and Left Right)
if (this.deviceStatus.fanAutoMode === 2) {
parameters.fanAutoMode = 0;
}
else {
parameters.fanAutoMode = 3;
}
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Swing Left Right On`);
}
else {
if (this.deviceStatus.fanAutoMode === 0) {
parameters.fanAutoMode = 2;
}
else {
parameters.fanAutoMode = 1;
}
parameters.airSwingLR = (((_a = this.devConfig) === null || _a === void 0 ? void 0 : _a.swingDefaultLR) !== null) ? (_b = this.devConfig) === null || _b === void 0 ? void 0 : _b.swingDefaultLR : 2;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: Swing Left Right Off`);
}
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
// set Fan speed
async setFanSpeed(value) {
// set Fan speed
if (value >= 0 && value <= 100) {
this.platform.log.debug(`${this.accessory.displayName}: setFanSpeed(), value: ${value}`);
const parameters = {};
if (value === 0) {
// Turn off
parameters.operate = 0;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: set off`);
}
else if (value > 0 && value <= 20) {
parameters.ecoMode = 0;
parameters.fanSpeed = 1;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: set fan speed 1`);
}
else if (value > 20 && value <= 40) {
parameters.ecoMode = 0;
parameters.fanSpeed = 2;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: set fan speed 2`);
}
else if (value > 40 && value <= 60) {
parameters.ecoMode = 0;
parameters.fanSpeed = 3;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: set fan speed 3`);
}
else if (value > 60 && value <= 80) {
parameters.ecoMode = 0;
parameters.fanSpeed = 4;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: set fan speed 4`);
}
else if (value > 80 && value < 100) {
parameters.ecoMode = 0;
parameters.fanSpeed = 5;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: set fan speed 5`);
}
else if (value === 100) {
// Auto mode
parameters.ecoMode = 0;
parameters.fanSpeed = 0;
this.platform.log[(this.platform.platformConfig.logsLevel >= 1) ? 'info' : 'debug'](`${this.accessory.displayName}: set fan speed auto`);
}
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
}
// ===============================================================================================================================================
async setThresholdTemperature(value) {
/**
* This function is used for Cooling AND Heating Threshold Temperature,
* which is fine in HEAT and COOL mode. But in AUTO mode, it results in a conflict
* because HomeKit allows setting a lower and an upper temperature but the remote control
* and Comfort Cloud app only set the target temperature.
*
* Option 1: Don't map the AUTO setting in HomeKit to AUTO on ComfortCloud (CC),
* but switch to COOL or HEAT on CC depending on the current room temperature.
* In that case, we could process the heating and cooling threshold accordingly.
* Caveat: HomeKit set to AUTO would show up as HEAT or COOL in the CC app, i.e.
* we would produce an inconsistent state across control interfaces.
*
* Option 2: Map AUTO in HomeKit to AUTO on CC and set the temperature which was set last
* as target temperature. The user would have to drag both sliders close to each other
* and treat it as one bar.
* Caveat: We cannot replace a range slider in HomeKit by a single value. Any user
* who doesn't read this note might be confused about this.
*
* Current choice is option 2 because the only implication for the user is wrongly set
* temperature in the worst case. Option 1 would offer full functionality, but decrease
* the compatibility with the Comfort Cloud app.
*/
this.platform.log.debug(`Accessory: setThresholdTemperature() for device '${this.accessory.displayName}'`);
const parameters = {
temperatureSet: value,
};
this.sendDeviceUpdate(this.accessory.context.device.deviceGuid, parameters);
}
async sendDeviceUpdate(guid, payload = {}) {
try {
// HomeKit sends commands when a move starts, not when it ends, so there can be several commands during one move.
// Users often send several commands at once, e.g. in automation.
// Collect together all parameters sent in a specified time, so as not to send each parameters separately.
this.sendDeviceUpdatePayload = Object.assign(this.sendDeviceUpdatePayload, payload);
clearTimeout(this.timerSendDeviceUpdate);
this.timerSendDeviceUpdate = null;
// Only send non-empty payloads to prevent a '500 Internal Server Error'
if (Object.keys(this.sendDeviceUpdatePayload).length > 0) {
this.timerSendDeviceUpdate = setTimeout(() => {
// Workaround - API not storing fanSpeed and ecoMode.
// Apply only when device is turned off and it is turning on
// and there is no command to set fanSpeed or ecoMode.
if (this.deviceStatus.operate === 0
&& this.sendDeviceUpdatePayload.operate === 1
&& !Object.prototype.hasOwnProperty.call(this.sendDeviceUpdatePayload, 'fanSpeed')
&& !Object.prototype.hasOwnProperty.call(this.sendDeviceUpdatePayload, 'ecoMode')) {
const parameters = {};
switch (this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed).value) {
case 1:
parameters.ecoMode = 2;
break;
case 2:
parameters.fanSpeed = 1;
break;
case 3:
parameters.fanSpeed = 2;
break;
case 4:
parameters.fanSpeed = 3;
break;
case 5:
parameters.fanSpeed = 4;
break;
case 6:
parameters.fanSpeed = 5;
break;
case 7:
parameters.ecoMode = 1;
break;
default:
parameters.ecoMode = 0;
parameters.fanSpeed = 0;
break;
}
this.platform.log.debug(`${this.accessory.displayName}: Applying workaround fix for speed and eco mode, `
+ `adding parameters ${JSON.stringify(parameters)} to ${JSON.stringify(this.sendDeviceUpdatePayload)}.`);
this.sendDeviceUpdatePayload = Object.assign(this.sendDeviceUpdatePayload, parameters);
}
// Send update
this.platform.log.debug(`${this.accessory.displayName}: sendDeviceUpdatePayload: ${JSON.stringify(this.sendDeviceUpdatePayload)}`);
this.platform.comfortCloud.setDeviceStatus(guid, this.accessory.displayName, this.sendDeviceUpdatePayload);
// Reset payload
this.sendDeviceUpdatePayload = {};
// Refresh device status
clearTimeout(this.timerSendDeviceUpdateRefresh);
this.timerSendDeviceUpdateRefresh = null;
this.timerSendDeviceUpdateRefresh = setTimeout(this.refreshDeviceStatus.bind(this), 7500);
}, 2500);
}
}
catch (error) {
this.platform.log.error('An error occurred while sending a device update. '
+ 'Turn on debug mode for more information.');
// Only log if a Promise rejection reason was provided.
// Some errors are already logged at source.
if (error) {
this.platform.log.debug(error);
}
}
}
}
exports.default = IndoorUnitAccessory;
//# sourceMappingURL=indoor-unit.js.map