node-red-contrib-homekit-abc
Version:
HAP-Nodejs based Node-RED nodes to create HomeKit Accessories
307 lines (258 loc) • 12.4 kB
JavaScript
const miio = require('miio');
const path = require('path');
const net = require('net');
const hap = require('hap-nodejs');
const storage = require('node-persist');
const {uuid, Accessory, Service, Characteristic} = hap;
const pkg = require('../package.json');
const fs = require('fs');
const accessories = {};
module.exports = function (RED) {
//hap.init(path.join(RED.settings.userDir, 'homekit'));
RED.httpAdmin.get('/hassbian-abc-homekit-midehumidifier', (req, res) => {
if (req.query.config) {
const acc = accessories[req.query.config];
if (acc) {
res.status(200).send(JSON.stringify({setupURI: acc.setupURI()}));
} else {
res.status(500).send(JSON.stringify({}));
}
} else {
res.status(404).send(JSON.stringify({}));
}
});
class hassbianHomeKitmidehumidifier {
constructor(config) {
RED.nodes.createNode(this, config);
const that = this;
this.device = new miio.Device({
address: config.ip,
token: config.token
});
this.model = config.model
function logger(...args) {
let str = args.join(' ');
if (str.match(/^(error: )/i)) {
str = str.replace(/^error: (.*)/i, '$1');
that.error(str);
} else if (config.debug) {
that.debug(str);
}
}
if (accessories[this.id]) {
this.debug('midehumidifier already configured ' + this.name + ' ' + this.id + ' ' + this.username);
return;
}
const [firstLogger] = Object.keys(RED.settings.logging);
config.debug = config.debug && (RED.settings.logging[firstLogger].level === 'debug' || RED.settings.logging[firstLogger].level === 'trace');
this.name = config.name || ('midehumidifier ' + this.id);
storage.initSync();
const acc = new Accessory(this.name, uuid.generate(config.id), Accessory.Categories.AIR_HUMIDIFIER);
accessories[this.id] = acc;
this.debug('midehumidifier created' + this.name + ' ' + this.id + ' ' + config.username);
acc.getService(Service.AccessoryInformation)
.setCharacteristic(Characteristic.Manufacturer, 'hassbian-abc')
.setCharacteristic(Characteristic.Model, 'midehumidifier')
.setCharacteristic(Characteristic.SerialNumber, config.username)
.setCharacteristic(Characteristic.FirmwareRevision, pkg.version);
acc.on('identify', (paired, callback) => {
this.log('identify ' + this.id + ' ' + this.username + ' ' + paired);
callback();
});
var dehumidifierService = acc.addService(Service.HumidifierDehumidifier, this.name, this.name);
var currentHumidityCharacteristic = dehumidifierService.getCharacteristic(Characteristic.CurrentRelativeHumidity);
var currentHumidifierDehumidifierStateCharacteristic = dehumidifierService.getCharacteristic(Characteristic.CurrentHumidifierDehumidifierState);
currentHumidifierDehumidifierStateCharacteristic.setProps({
validValues: [0,3]
});
var targetHumidifierDehumidifierStateCharacteristic = dehumidifierService.getCharacteristic(Characteristic.TargetHumidifierDehumidifierState);
targetHumidifierDehumidifierStateCharacteristic.setProps({
validValues: [2]
});
var activeCharacteristic = dehumidifierService.getCharacteristic(Characteristic.Active);
var lockPhysicalControlsCharacteristic = dehumidifierService.addCharacteristic(Characteristic.LockPhysicalControls);
var rotationSpeedCharacteristic = dehumidifierService.getCharacteristic(Characteristic.RotationSpeed);
rotationSpeedCharacteristic.setProps({
minValue: 0,
maxValue: 3,
minStep: 1,
});
var swingModeControlsCharacteristic = dehumidifierService.addCharacteristic(Characteristic.SwingMode);
dehumidifierService
.getCharacteristic(Characteristic.RelativeHumidityDehumidifierThreshold)
.setProps({
minValue: 0,
maxValue: 100,
minStep: 10,
})
.on('get', function(callback) {
that.device.call("get_prop", ["on_off", "humidity", "child_lock", "mode", "auto"]).then(result => {
that.debug("[midehumidifier][DEBUG] - get: " + result);
callback(null, result[4]);
if (result[0] === "on") {
activeCharacteristic.updateValue(Characteristic.Active.ACTIVE);
currentHumidifierDehumidifierStateCharacteristic.updateValue(Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING);
} else if (result[0] === "off") {
activeCharacteristic.updateValue(Characteristic.Active.INACTIVE);
currentHumidifierDehumidifierStateCharacteristic.updateValue(Characteristic.CurrentHumidifierDehumidifierState.INACTIVE);
}
currentHumidityCharacteristic.updateValue(result[1]);
if (result[2] === "on") {
lockPhysicalControlsCharacteristic.updateValue(Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED);
} else if (result[2] === "off") {
lockPhysicalControlsCharacteristic.updateValue(Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED);
}
if (result[3] === "auto") {
swingModeControlsCharacteristic.updateValue(Characteristic.SwingMode.SWING_ENABLED);
} else if (result[3] === "on" || result[3] === "dry_cloth") {
swingModeControlsCharacteristic.updateValue(Characteristic.SwingMode.SWING_DISABLED);
}
}).catch(function(err) {
that.debug("[midehumidifier][DEBUG] - get Error: " + err);
callback(err);
});
}.bind(this))
.on('set', function(value, callback) {
if(value > 0 && value <= 40) {
value = 40;
} else if(value > 60 && value <= 100) {
value = 60;
}
that.device.call("set_auto", [value]).then(result => {
if(result[0] === "ok") {
callback(null);
} else {
callback(new Error(result[0]));
}
}).catch(function(err) {
that.debug("[midehumidifier][DEBUG] - setRelativeHumidityDehumidifierThreshold Error: " + err);
callback(err);
});
}.bind(this));
activeCharacteristic
.on('set', function(value, callback) {
that.debug("[midehumidifier][DEBUG] - Active - setActive: " + value);
that.device.call("set_power", [value ? "on" : "off"]).then(result => {
if(result[0] === "ok") {
callback(null);
} else {
callback(new Error(result[0]));
}
}).catch(function(err) {
that.debug("[midehumidifier][DEBUG] - Active - setActive Error: " + err);
callback(err);
});
}.bind(this));
targetHumidifierDehumidifierStateCharacteristic.setValue(Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER);
swingModeControlsCharacteristic
.on('set', function(value, callback) {
that.device.call("set_mode", [value ? "auto" : "dry_cloth"]).then(result => {
if(result[0] === "ok") {
callback(null);
} else {
callback(new Error(result[0]));
}
}).catch(function(err) {
callback(err);
});
}.bind(this));
lockPhysicalControlsCharacteristic
.on('set', function(value, callback) {
that.debug("[midehumidifier][DEBUG] - Child Lock - setchildlock: " + value);
that.device.call("set_child_lock", [value ? "on" : "off"]).then(result => {
if(result[0] === "ok") {
callback(null);
} else {
callback(new Error(result[0]));
}
}).catch(function(err) {
that.debug("[midehumidifier][DEBUG] - Child Lock - setchildlock: " + err);
callback(err);
});
}.bind(this));
rotationSpeedCharacteristic
.on('get', function(callback) {
that.device.call('get_prop',['fan_st']).then(result => {
that.debug("[midehumidifier][DEBUG] - getrotationSpeedCharacteristic: " + result);
callback(null, result[0]);
}).catch(function(err) {
that.debug("[Demidehumidifier][DEBUG] - getrotationSpeedCharacteristic Error: " + err);
callback(err);
});
}.bind(this))
.on('set', function(value, callback) {
that.debug("[midehumidifier][DEBUG] - setrotationSpeedCharacteristic: " + value);
if (value == 0) {
that.device.call("set_power", ["off"]).then(result => {
if(result[0] === "ok") {
callback(null);
} else {
callback(new Error(result[0]));
}
}).catch(function(err) {
that.debug("[midehumidifier][DEBUG] - setrotationSpeedCharacteristic Error: " + err);
callback(err);
});
} else {
that.device.call("set_fan_level", [value]).then(result => {
if(result[0] === "ok") {
callback(null);
} else {
callback(new Error(result[0]));
}
}).catch(function(err) {
that.debug("[midehumidifier][DEBUG] - setrotationSpeedCharacteristic Error: " + err);
callback(err);
});
}
}.bind(this));
if(!this.config['showTemperature']) {
var temperatureSensorService = new Service.TemperatureSensor(this.config['showTemperatureSensorName']);
temperatureSensorService
.getCharacteristic(Characteristic.CurrentTemperature)
.on('get', function(callback) {
that.device.call("get_prop", ["temp"]).then(result => {
that.debug("[midehumidifier][DEBUG] - getTemperature: " + result);
callback(null, result[0]);
}).catch(function(err) {
that.debug("[midehumidifier][DEBUG] - getTemperature Error: " + err);
callback(err);
});
}.bind(this));
}
this.log('publishing midehumidifier ' + this.name + ' ' + config.username);
const testPort = net.createServer()
.once('error', err => {
this.error(err);
this.status({fill: 'red', shape: 'dot', text: err.message});
})
.once('listening', () => {
testPort.once('close', () => {
acc.publish({
username: config.username,
port: config.port,
pincode: config.pincode,
category: Accessory.Categories.AIR_HUMIDIFIER
});
acc._server.on('listening', () => {
this.log('midehumidifier ' + this.name + ' listening on port ' + config.port);
this.status({fill: 'green', shape: 'ring', text: ' '});
});
acc._server.on('pair', username => {
this.log('midehumidifier ' + this.name + ' paired', username);
});
acc._server.on('unpair', username => {
this.log('midehumidifier ' + this.name + ' unpaired', username);
});
acc._server.on('verify', () => {
this.log('midehumidifier ' + this.name + ' verify');
});
}).close();
})
.listen(config.port);
this.on('close', () => {
});
}
}
RED.nodes.registerType('hassbian-abc-homekit-midehumidifier', hassbianHomeKitmidehumidifier);
};