UNPKG

node-red-contrib-homekit-abc

Version:

HAP-Nodejs based Node-RED nodes to create HomeKit Accessories

434 lines (396 loc) 18.4 kB
const broadlink = require('./broadlink'); 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 accessories = {}; module.exports = function (RED) { //hap.init(path.join(RED.settings.userDir, 'homekit')); RED.httpAdmin.get('/hassbian-abc-homekit-broadlink-mp1', (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 hassbianHomeKitbroadlink { constructor(config) { RED.nodes.createNode(this, config); const that = this; var broadlinkip = config.ip; var broadlinkmac = config.mac; var mac_buff = function(mac) { var mb = new Buffer(6); if (mac) { var values = mac.split(':'); if (!values || values.length !== 6) { throw new Error('Invalid MAC [' + mac + ']; should follow pattern ##:##:##:##:##:##'); } for (var i = 0; i < values.length; ++i) { var tmpByte = parseInt(values[i], 16); mb.writeUInt8(tmpByte, i); } } else { //this.log("MAC address emtpy, using IP: " + this.ip); } return mb; }; var powered = false; var powered1 = false; var powered2 = false; var powered3 = false; var time = true; 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('broadlink-mp1 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 || ('broadlink-mp1 ' + this.id); storage.initSync(); const acc = new Accessory(this.name, uuid.generate(config.id), Accessory.Categories.OUTLET); accessories[this.id] = acc; this.debug('broadlink-mp1 created' + this.name + ' ' + this.id + ' ' + config.username); acc.getService(Service.AccessoryInformation) .setCharacteristic(hap.Characteristic.Manufacturer, 'hassbian-abc') .setCharacteristic(hap.Characteristic.Model, 'broadlink-mp1') .setCharacteristic(hap.Characteristic.SerialNumber, config.username) .setCharacteristic(hap.Characteristic.FirmwareRevision, pkg.version); acc.on('identify', (paired, callback) => { this.log('identify ' + this.id + ' ' + this.username + ' ' + paired); callback(); }); var switchService = acc.addService(hap.Service.Outlet, this.name + "s1", this.name + "s1"); var power0 = switchService.getCharacteristic(Characteristic.On); var use0 = switchService.getCharacteristic(Characteristic.OutletInUse); var switch1Service = acc.addService(hap.Service.Outlet, this.name + "s2", this.name + "s2"); var power1 = switch1Service.getCharacteristic(Characteristic.On); var use1 = switch1Service.getCharacteristic(Characteristic.OutletInUse); var switch2Service = acc.addService(hap.Service.Outlet, this.name + "s3", this.name + "s3"); var power2 = switch2Service.getCharacteristic(Characteristic.On); var use2 = switch2Service.getCharacteristic(Characteristic.OutletInUse); var switch3Service = acc.addService(hap.Service.Outlet, this.name + "s4", this.name + "s4"); var power3 = switch3Service.getCharacteristic(Characteristic.On); var use3 = switch3Service.getCharacteristic(Characteristic.OutletInUse); setInterval(function() { getstate(); }, config.pollingTime * 1000); power0 .updateValue(powered) .on('set', (state, callback) => { var s_index = "1"; var b = new broadlink(); if (state) { if (powered) { return callback(null, true); } else { b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.set_power(s_index, true); dev.exit(); clearInterval(checkAgainSet); powered = true; return callback(null, true); } else { dev.exit(); } }); var checkAgainSet = setInterval(function() { //self.log("Discovering Again for Set Command... " + self.sname); b.discover(); }, 1000) } } else { if (powered) { b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.set_power(s_index, false); dev.exit(); clearInterval(checkAgainSet); powered = false; return callback(null, false); } else { dev.exit(); } }); var checkAgainSet = setInterval(function() { //self.log("Discovering Again for Set Command... " + self.sname); b.discover(); }, 1000) } else { return callback(null, false) } } }) .on('get', (callback) => { callback(null, powered); }); use0 .updateValue(powered) .on('get', (callback) => { callback(null, powered); }); power1 .updateValue(powered1) .on('set', (state, callback) => { var s_index = "2"; var b = new broadlink(); if (state) { if (powered1) { return callback(null, true); } else { b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.set_power(s_index, true); dev.exit(); clearInterval(checkAgainSet); powered1 = true; return callback(null, true); } else { dev.exit(); } }); var checkAgainSet = setInterval(function() { //self.log("Discovering Again for Set Command... " + self.sname); b.discover(); }, 1000) } } else { if (powered1) { b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.set_power(s_index, false); dev.exit(); clearInterval(checkAgainSet); powered1 = false; return callback(null, false); } else { dev.exit(); } }); var checkAgainSet = setInterval(function() { //self.log("Discovering Again for Set Command... " + self.sname); b.discover(); }, 1000) } else { return callback(null, false) } } }) .on('get', (callback) => { callback(null, powered1); }); use1 .updateValue(powered1) .on('get', (callback) => { callback(null, powered1); }); power2 .updateValue(powered2) .on('set', (state, callback) => { var s_index = "3"; var b = new broadlink(); if (state) { if (powered2) { return callback(null, true); } else { b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.set_power(s_index, true); dev.exit(); clearInterval(checkAgainSet); powered2 = true; return callback(null, true); } else { dev.exit(); } }); var checkAgainSet = setInterval(function() { //self.log("Discovering Again for Set Command... " + self.sname); b.discover(); }, 1000) } } else { if (powered2) { b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.set_power(s_index, false); dev.exit(); clearInterval(checkAgainSet); powered2 = false; return callback(null, false); } else { dev.exit(); } }); var checkAgainSet = setInterval(function() { //self.log("Discovering Again for Set Command... " + self.sname); b.discover(); }, 1000) } else { return callback(null, false) } } }) .on('get', (callback) => { callback(null, powered2); }); use2 .updateValue(powered2) .on('get', (callback) => { callback(null, powered2); }); power3 .updateValue(powered3) .on('set', (state, callback) => { var s_index = "2"; var b = new broadlink(); if (state) { if (powered3) { return callback(null, true); } else { b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.set_power(s_index, true); dev.exit(); clearInterval(checkAgainSet); powered3 = true; return callback(null, true); } else { dev.exit(); } }); var checkAgainSet = setInterval(function() { //self.log("Discovering Again for Set Command... " + self.sname); b.discover(); }, 1000) } } else { if (powered3) { b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.set_power(s_index, false); dev.exit(); clearInterval(checkAgainSet); powered3 = false; return callback(null, false); } else { dev.exit(); } }); var checkAgainSet = setInterval(function() { //self.log("Discovering Again for Set Command... " + self.sname); b.discover(); }, 1000) } else { return callback(null, false) } } }) .on('get', (callback) => { callback(null, powered3); }); use3 .updateValue(powered3) .on('get', (callback) => { callback(null, powered3); }); var getstate = (function() { var b = new broadlink(); b.discover(); b.on("deviceReady", (dev) => { if (mac_buff(broadlinkmac).equals(dev.mac) || dev.host.address == broadlinkip) { dev.check_power(); dev.on("mp_power", (status_array) => { dev.exit(); //console.log("status_array", status_array); if (!status_array[0]) { powered = false; } else { powered = true; } if (!status_array[1]) { powered1 = false; } else { powered1 = true; } if (!status_array[2]) { powered2 = false; } else { powered2 = true; } if (!status_array[3]) { powered3 = false; } else { powered3 = true; } power0.updateValue(powered); power1.updateValue(powered1); power2.updateValue(powered2); power3.updateValue(powered3); }); } else { dev.exit(); } }); }); this.log('publishing broadlink-mp1 ' + 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.OUTLET }); acc._server.on('listening', () => { this.log('broadlink-mp1 ' + this.name + ' listening on port ' + config.port); this.status({fill: 'green', shape: 'ring', text: ' '}); }); acc._server.on('pair', username => { this.log('broadlink-mp1 ' + this.name + ' paired', username); }); acc._server.on('unpair', username => { this.log('broadlink-mp1 ' + this.name + ' unpaired', username); }); acc._server.on('verify', () => { this.log('broadlink-mp1 ' + this.name + ' verify'); }); }).close(); }) .listen(config.port); this.on('close', () => { }); } } RED.nodes.registerType('hassbian-abc-homekit-broadlink-mp1', hassbianHomeKitbroadlink); };