UNPKG

homebridge-anavi-infrared-aircon

Version:

Plugin for homebridge that combines LIRC and a temperature sensor into a thermostat accessory: https://github.com/nfarina/homebridge

214 lines (172 loc) 6.64 kB
'use strict' const plugin = require('./package') var Service, Characteristic module.exports = function(homebridge) { Service = homebridge.hap.Service Characteristic = homebridge.hap.Characteristic homebridge.registerAccessory(plugin.name, "aircon-ir-remote", AirConAccessory) } class AirConAccessory { constructor (log, config) { this.log = log this.informationService = this.makeInformationService(config) this.thermostatService = this.makeThermostatService(config) } identify (callback) { this.log('Device identified!') callback() } makeInformationService(config) { const service = new Service.AccessoryInformation() service .setCharacteristic(Characteristic.Manufacturer, config.device && config.device.manufacturer) .setCharacteristic(Characteristic.Model, config.device && config.device.model) .setCharacteristic(Characteristic.SerialNumber, config.device && config.device.serial) .setCharacteristic(Characteristic.FirmwareRevision, (config.device && config.device.revision) || plugin.version) return service } getCurrentTemperature (callback) { this.sensor.readTemperature(function(tempInC) { callback(null, tempInC) }) } getCurrentRelativeHumidity (callback) { this.sensor.readHumidity(function(relativeHumidity) { callback(null, relativeHumidity) }) } getCurrentHeatingCoolingState (callback) { callback(null, this.heatingCoolingState) } setTargetHeatingCoolingState (value, callback) { this.log('Power state to %s.', value) if ((value !== Characteristic.TargetHeatingCoolingState.OFF) && (this.heatingCoolingState === Characteristic.TargetHeatingCoolingState.OFF)) { this.heatingCoolingState = Characteristic.TargetHeatingCoolingState.COOL this.remoteSend('KEY_POWER', function() { callback(null, Characteristic.TargetHeatingCoolingState.COOL) }) } else if ((value === Characteristic.TargetHeatingCoolingState.OFF) && (this.heatingCoolingState !== Characteristic.TargetHeatingCoolingState.OFF)) { this.heatingCoolingState = Characteristic.TargetHeatingCoolingState.OFF this.remoteSend('KEY_POWER', function() { callback(null, Characteristic.TargetHeatingCoolingState.OFF) }) } else { callback() } } getTargetTemperature (callback) { callback(null, this.currentSetpoint) } recursiveRemoteSend(command, stepsRemaining, callback) { if (stepsRemaining <= 0) { callback() return } this.remoteSend(command, (function() { this.recursiveRemoteSend(command, stepsRemaining - 1, callback) }).bind(this)) } setTargetTemperature (_newValue, callback) { const oldValue = this.celsiusToDevice(this.currentSetpoint), newValue = this.celsiusToDevice(_newValue) this.currentSetpoint = _newValue this.log('Set temperature to %s (from %s).', newValue, oldValue) this.setTargetHeatingCoolingState(Characteristic.TargetHeatingCoolingState.COOL, function(error) { if (error) { callback(error) return } const turnOffIfNeeded = (typeof error !== 'undefined') ? function(error) { if (error) { callback(error) return } this.setTargetHeatingCoolingState(Characteristic.TargetHeatingCoolingState.OFF, callback) }.bind(this) : callback if (oldValue < newValue) { this.recursiveRemoteSend('BTN_GEAR_UP', newValue - oldValue, turnOffIfNeeded) } else if (oldValue > newValue) { this.recursiveRemoteSend('BTN_GEAR_DOWN', oldValue - newValue, turnOffIfNeeded) } else { turnOffIfNeeded() } }.bind(this)) } makeThermostatService(config) { const service = new Service.Thermostat(config.name) switch (config.unit) { case "fahrenheit": service .getCharacteristic(Characteristic.TemperatureDisplayUnits) .setValue(Characteristic.TemperatureDisplayUnits.FAHRENHEIT) .on('set', function(value, callback){ callback(null, Characteristic.TemperatureDisplayUnits.FAHRENHEIT) }) this.celsiusToDevice = function (temperature) { return Math.round((temperature * 1.8) + 32) } break default: service .getCharacteristic(Characteristic.TemperatureDisplayUnits) .setValue(Characteristic.TemperatureDisplayUnits.CELSIUS) .on('set', function(value, callback){ callback(null, Characteristic.TemperatureDisplayUnits.CELSIUS) }) this.celsiusToDevice = Math.round break } switch (config.i2c && config.i2c.kind) { case "htu21d": const i2c_htu21d = require('htu21d-i2c') this.sensor = new i2c_htu21d(config.sensor) service .getCharacteristic(Characteristic.CurrentRelativeHumidity) .on('get', this.getCurrentRelativeHumidity.bind(this)) break case "dht22": const i2c_bmp085 = require('bmp085') this.sensor = new i2c_bmp085(config.sensor) break default: throw new Error('Must specify I2C sensor configuration with known sensor kind "htu21d" or "dht22"') } service .getCharacteristic(Characteristic.CurrentTemperature) .on('get', this.getCurrentTemperature.bind(this)) if (config.ir && config.ir.name) { const lirc = require('lirc_node') this.remoteSend = function(button, callback) { lirc.irsend.send_once(config.ir.name, button, callback) } } else { throw new Error('Need device name for LIRC.') } this.heatingCoolingState = Characteristic.TargetHeatingCoolingState.OFF service .getCharacteristic(Characteristic.CurrentHeatingCoolingState) .on('get', this.getCurrentHeatingCoolingState.bind(this)) service .getCharacteristic(Characteristic.TargetHeatingCoolingState) .setProps({ validValues: [ Characteristic.TargetHeatingCoolingState.OFF, Characteristic.TargetHeatingCoolingState.COOL ] }) .updateValue(this.heatingCoolingState) .on('set', this.setTargetHeatingCoolingState.bind(this)) this.currentSetpoint = config.defaultSetpoint || 20 service .getCharacteristic(Characteristic.TargetTemperature) .setProps({ minValue: config.minSetpoint || 10, maxValue: config.maxSetpoint || 30, minStep: 0.5 }) .on('get', this.getTargetTemperature.bind(this)) .on('set', this.setTargetTemperature.bind(this)) return service } getServices () { return [ this.informationService, this.thermostatService ] } }