homebridge-daikin-local-platform
Version:
Homebridge platform plugin providing HomeKit support for Daikin air conditioners with local control
338 lines (336 loc) • 21 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const const_1 = require("../const");
const daikin_local_1 = require("../daikin-local");
/**
* An instance of this class is created for each accessory the platform registers.
* Each accessory may expose multiple services of different service types.
*/
class ClimateAccessory {
constructor(platform, accessory) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
this.platform = platform;
this.accessory = accessory;
this.services = {};
this._lastFanSpeed = 1; // slient
accessory.context.device.setCallback(this.updateDeviceStatus.bind(this));
// Accessory Information
// https://developers.homebridge.io/#/service/AccessoryInformation
(_a = this.accessory.getService(this.platform.Service.AccessoryInformation)) === null || _a === void 0 ? void 0 : _a.setCharacteristic(this.platform.Characteristic.Manufacturer, 'Daikin ' + ((_b = accessory.context.device) === null || _b === void 0 ? void 0 : _b.getDeviceReg())).setCharacteristic(this.platform.Characteristic.Model, ((_c = accessory.context.device) === null || _c === void 0 ? void 0 : _c.getDeviceType()) || 'Unknown').setCharacteristic(this.platform.Characteristic.SerialNumber, ((_d = accessory.context.device) === null || _d === void 0 ? void 0 : _d.getMacAddress()) || 'Unknown').setCharacteristic(this.platform.Characteristic.FirmwareRevision, ((_e = accessory.context.device) === null || _e === void 0 ? void 0 : _e.getFirmwareVersion()) || 'Unknown');
this.services['Climate'] = this.accessory.getService(this.platform.Service.HeaterCooler)
|| this.accessory.addService(this.platform.Service.HeaterCooler);
// This is what is displayed as the default name on the Home app
this.services['Climate'].setCharacteristic(this.platform.Characteristic.Name, ((_f = accessory.context.device) === null || _f === void 0 ? void 0 : _f.getDeviceName()) || '空調');
this.services['Climate']
.getCharacteristic(this.platform.Characteristic.Active)
.onSet(this.setClimateActive.bind(this))
.onGet(this.getClimateActive.bind(this));
this.services['Climate']
.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
.setProps({
minValue: -100,
maxValue: 100,
minStep: 0.01,
});
this.services['Climate']
.getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.onGet(this.getCurrentHeaterCoolerState.bind(this));
this.services['Climate']
.getCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState)
.onSet(this.setTargetHeaterCoolerState.bind(this));
// Cooling Threshold Temperature (optional)
this.services['Climate']
.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature)
.setProps({
minValue: ((_g = accessory.context.device) === null || _g === void 0 ? void 0 : _g.getCoolingThresholdTemperatureRange()[0]) || 10,
maxValue: ((_h = accessory.context.device) === null || _h === void 0 ? void 0 : _h.getCoolingThresholdTemperatureRange()[1]) || 30,
minStep: 0.5,
})
.onSet(this.setCoolingThresholdTemperature.bind(this))
.onGet(this.getCoolingThresholdTemperature.bind(this));
// Heating Threshold Temperature (optional)
this.services['Climate']
.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature)
.setProps({
minValue: ((_j = accessory.context.device) === null || _j === void 0 ? void 0 : _j.getHeatingThresholdTemperatureRange()[0]) || 10,
maxValue: ((_k = accessory.context.device) === null || _k === void 0 ? void 0 : _k.getHeatingThresholdTemperatureRange()[1]) || 30,
minStep: 0.5,
})
.onSet(this.setHeatingThresholdTemperature.bind(this))
.onGet(this.getHeatingThresholdTemperature.bind(this));
// Fan control service
this.services['Fan'] = this.accessory.getService(this.platform.Service.Fan)
|| this.accessory.addService(this.platform.Service.Fan);
this.services['Fan'].getCharacteristic(this.platform.Characteristic.On)
.onGet(this.getFanStatus.bind(this))
.onSet(this.setFanStatus.bind(this));
this.services['Fan'].getCharacteristic(this.platform.Characteristic.RotationSpeed)
.setProps({
unit: null,
format: "uint8" /* this.platform.Characteristic.Formats.UINT8 */,
minValue: 0,
maxValue: 6,
validValues: [0, 1, 2, 3, 4, 5, 6]
})
.onGet(this.getRotationSpeed.bind(this))
.onSet(this.setRotationSpeed.bind(this));
/*
//
// Motion sensor switch
//
const buttonName = 'Motion Sensor';
this.services[buttonName] = this.accessory.getServiceById(this.platform.Service.Switch, buttonName) || this.accessory.addService(this.platform.Service.Switch, 'buttonBuzzerName', buttonName);
this.services[buttonName].setCharacteristic(this.platform.Characteristic.Name, buttonName);
this.services[buttonName].getCharacteristic(this.platform.Characteristic.On)
.onGet(this.getMotionDetection.bind(this))
.onSet(this.setMotionDetection.bind(this));
this.services[buttonName].addOptionalCharacteristic(this.platform.Characteristic.ConfiguredName);
this.services[buttonName].setCharacteristic(this.platform.Characteristic.ConfiguredName, buttonName);
*/
////
this.services['HumiditySensor'] = this.accessory.getService(this.platform.Service.HumiditySensor)
|| this.accessory.addService(this.platform.Service.HumiditySensor);
this.services['HumiditySensor'].getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity)
.onGet(this.getCurrentRelativeHumidity.bind(this));
// Separate service so it doesn't collide with HeaterCooler's
// CurrentTemperature, which reports the indoor value.
this.services['OutdoorTemperatureSensor'] =
this.accessory.getServiceById(this.platform.Service.TemperatureSensor, 'outdoor')
|| this.accessory.addService(this.platform.Service.TemperatureSensor, 'Outdoor Temperature', 'outdoor');
this.services['OutdoorTemperatureSensor']
.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
.setProps({
minValue: -100,
maxValue: 100,
minStep: 0.5,
})
.onGet(this.getOutdoorTemperature.bind(this));
//////////
// Update characteristic values asynchronously instead of using onGet handlers
this.refreshDeviceStatus();
}
async refreshDeviceStatus() {
this.platform.log.debug(`Accessory: Refresh status for device '${this.accessory.displayName}'`);
await this.accessory.context.device.fetchDeviceStatus();
///
// Schedule continuous device updates on the first run
if (!this._refreshInterval) {
this._refreshInterval = setInterval(this.refreshDeviceStatus.bind(this), const_1.DEVICE_STATUS_REFRESH_INTERVAL);
}
}
// Turn a device command result into a HomeKit-visible outcome: a failed command
// must reject the onSet so the Home app doesn't show a stale "success" state.
assertCommand(ok) {
if (!ok) {
throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
}
}
async setClimateActive(value) {
this.platform.log.debug(`Accessory: setClimateActive() for device '${this.accessory.displayName}'`);
this.assertCommand(await this.accessory.context.device.setPowerStatus(value === this.platform.Characteristic.Active.ACTIVE));
}
async getClimateActive() {
this.platform.log.debug(`Accessory: getClimateActive() for device '${this.accessory.displayName}'`);
const active = this.accessory.context.device.getPowerStatus() ?
this.platform.Characteristic.Active.ACTIVE : this.platform.Characteristic.Active.INACTIVE;
return active;
}
async getFanStatus() {
this.platform.log.debug(`Accessory: getFanStatus() for device '${this.accessory.displayName}'`);
const value = this.accessory.context.device.getFanSpeedNumber() !== 0;
return value;
}
async setFanStatus(value) {
this.platform.log.debug(`Accessory: setFanStatus() for device '${this.accessory.displayName}'`);
let speed = this._lastFanSpeed; // restore to previous non-zero speed
if (value === false) {
// turn off fan means turn on auto-speed mode
speed = 0;
}
await this.setRotationSpeed(speed);
}
async getRotationSpeed() {
this.platform.log.debug(`Accessory: getRotationSpeed() for device '${this.accessory.displayName}'`);
let value = this.accessory.context.device.getFanSpeedNumber();
if (value === 0) {
value = this._lastFanSpeed;
}
return value;
}
async setRotationSpeed(value) {
this.platform.log.debug(`Accessory: setRotationSpeed() for device '${this.accessory.displayName}'`);
const entry = daikin_local_1.FAN_SPEED_TABLE.find(e => e.number === value);
if (!entry) {
this.platform.log.error(`Unknown RotationSpeed: ${value}`);
return;
}
// Speed 0 = auto; remember the last explicit speed so turning the fan back on restores it.
if (value === 0) {
const lastFanSpeed = this.accessory.context.device.getFanSpeedNumber();
if (lastFanSpeed !== 0) {
this._lastFanSpeed = lastFanSpeed;
}
}
this.assertCommand(await this.accessory.context.device.setFanSpeed(entry.code));
}
async getCurrentRelativeHumidity() {
try {
this.platform.log.debug(`Accessory: getCurrentRelativeHumidity() for device '${this.accessory.displayName}'`);
}
catch (e) {
this.platform.log.error(e);
}
return this.accessory.context.device.getIndoorHumidity();
}
async getOutdoorTemperature() {
this.platform.log.debug(`Accessory: getOutdoorTemperature() for device '${this.accessory.displayName}'`);
const value = this.accessory.context.device.getOutdoorTemperature();
if (Number.isFinite(value)) {
return value;
}
// Outdoor unit hasn't reported yet (e.g. AC just powered on); keep
// whatever HomeKit already has cached rather than spike to 0.
const cached = this.services['OutdoorTemperatureSensor']
.getCharacteristic(this.platform.Characteristic.CurrentTemperature).value;
return typeof cached === 'number' ? cached : 0;
}
async getCurrentHeaterCoolerState() {
var _a;
if (this.accessory.context.device.getPowerStatus()) {
const currentTemperature = await this.accessory.context.device.getIndoorTemperature() || 0;
const targetTemperature = await this.accessory.context.device.getTargetTemperature() || 0;
const currentMode = await this.accessory.context.device.getOperationMode() || daikin_local_1.CLIMATE_MODE_AUTO;
switch (currentMode) {
// Auto
case daikin_local_1.CLIMATE_MODE_AUTO:
// Set target state and current state (based on current temperature)
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState.AUTO);
if (currentTemperature < targetTemperature) {
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.HEATING);
}
else if (currentTemperature > targetTemperature) {
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.COOLING);
}
else {
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.IDLE);
}
break;
// Heat
case daikin_local_1.CLIMATE_MODE_HEATING:
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState.HEAT);
if (currentTemperature < targetTemperature) {
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.HEATING);
}
else {
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.IDLE);
}
break;
// Cool
case daikin_local_1.CLIMATE_MODE_COOLING:
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState.COOL);
if (currentTemperature > targetTemperature) {
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.COOLING);
}
else {
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.IDLE);
}
break;
// Dry (Dehumidifier)
case daikin_local_1.CLIMATE_MODE_DEHUMIDIFY:
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.IDLE);
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState.AUTO);
break;
// Humidifier
case daikin_local_1.CLIMATE_MODE_HUMIDIFY:
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.IDLE);
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState.AUTO);
break;
// Fan
case daikin_local_1.CLIMATE_MODE_FAN:
this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
.updateValue(this.platform.Characteristic.CurrentHeaterCoolerState.IDLE);
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.platform.Characteristic.TargetHeaterCoolerState.AUTO);
break;
default:
this.platform.log.error(`Unknown TargetHeaterCoolerState state: '${this.accessory.displayName}' '${currentMode}'`);
break;
}
return (_a = this.services['Climate'].getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState).value) !== null && _a !== void 0 ? _a : this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
}
return this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
}
async getCoolingThresholdTemperature() {
this.platform.log.debug(`Accessory: getCoolingThresholdTemperature() for device '${this.accessory.displayName}'`);
const value = this.accessory.context.device.getTargetTemperatureWithMode(daikin_local_1.CLIMATE_MODE_COOLING);
return value;
}
async getHeatingThresholdTemperature() {
this.platform.log.debug(`Accessory: getHeatingThresholdTemperature() for device '${this.accessory.displayName}'`);
const value = this.accessory.context.device.getTargetTemperatureWithMode(daikin_local_1.CLIMATE_MODE_HEATING);
return value;
}
async setCoolingThresholdTemperature(value) {
this.platform.log.debug(`Accessory: setCoolingThresholdTemperature() for device '${this.accessory.displayName}'`);
const threshold = +value;
this.assertCommand(await this.accessory.context.device.setOperationMode(daikin_local_1.CLIMATE_MODE_COOLING));
this.assertCommand(await this.accessory.context.device.setTargetTemperature(threshold));
}
async setHeatingThresholdTemperature(value) {
this.platform.log.debug(`Accessory: setHeatingThresholdTemperature() for device '${this.accessory.displayName}'`);
const threshold = +value;
this.assertCommand(await this.accessory.context.device.setOperationMode(daikin_local_1.CLIMATE_MODE_HEATING));
this.assertCommand(await this.accessory.context.device.setTargetTemperature(threshold));
}
async setTargetHeaterCoolerState(value) {
this.platform.log.debug(`Accessory: setTargetHeaterCoolerState() for device '${this.accessory.displayName}'`);
let mode = daikin_local_1.CLIMATE_MODE_AUTO;
switch (value) {
case this.platform.Characteristic.TargetHeaterCoolerState.AUTO:
mode = daikin_local_1.CLIMATE_MODE_AUTO;
break;
case this.platform.Characteristic.TargetHeaterCoolerState.COOL:
mode = daikin_local_1.CLIMATE_MODE_COOLING;
break;
case this.platform.Characteristic.TargetHeaterCoolerState.HEAT:
mode = daikin_local_1.CLIMATE_MODE_HEATING;
break;
default:
this.platform.log.error(`Unknown TargetHeaterCoolerState ${value}`);
return;
}
this.assertCommand(await this.accessory.context.device.setOperationMode(mode));
}
async updateDeviceStatus(device) {
try {
this.platform.log.debug(`Accessory: updateDeviceStatus() for device '${this.accessory.displayName}'`);
const active = this.accessory.context.device.getPowerStatus() ? this.platform.Characteristic.Active.ACTIVE
: this.platform.Characteristic.Active.INACTIVE;
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.Active, active);
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.accessory.context.device.getIndoorTemperature());
this.getCurrentHeaterCoolerState();
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature, this.accessory.context.device.getTargetTemperatureWithMode(daikin_local_1.CLIMATE_MODE_HEATING));
this.services['Climate'].updateCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature, this.accessory.context.device.getTargetTemperatureWithMode(daikin_local_1.CLIMATE_MODE_COOLING));
this.services['HumiditySensor'].updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.accessory.context.device.getIndoorHumidity());
const outdoorTemp = this.accessory.context.device.getOutdoorTemperature();
if (Number.isFinite(outdoorTemp)) {
this.services['OutdoorTemperatureSensor']
.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, outdoorTemp);
}
//this.services['MotionSensor'].updateCharacteristic(this.platform.Characteristic.On, this.accessory.context.device.getMotionDetection());
}
catch (e) {
this.platform.log.error(e);
}
}
}
exports.default = ClimateAccessory;
//# sourceMappingURL=climate.js.map