UNPKG

utra-bridge

Version:

Bridge Zwave device into Apple HomeKit protocol.

846 lines (734 loc) 34.6 kB
'use strict'; const ct = require('color-temperature'); const debug = require('debug')('Operater'); const hap_nodejs = require('hap-nodejs'); const Accessory = hap_nodejs.Accessory; const Service = hap_nodejs.Service; const Characteristic = hap_nodejs.Characteristic; const uuid = hap_nodejs.uuid; const child_process = require('child_process'); const parser = require('xml2json').toJson; module.exports = Operater; function Operater (gateway, accessory) { this.gateway = gateway; this.accessory = accessory; return this; } Operater.prototype.LightSensor = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let name = accessory.displayName; return { CurrentAmbientLightLevel: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.LightSensor, name, value.instance); service.getCharacteristic(Characteristic.CurrentAmbientLightLevel) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout) => { let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value) => { return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; callback(err, parseFloat(result)*1000); }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout) => { let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value) => { return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; service.updateCharacteristic(Characteristic.CurrentAmbientLightLevel, parseFloat(result)*1000); service.getCharacteristic(Characteristic.CurrentAmbientLightLevel).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.CurrentAmbientLightLevel).emit('update'); }, 3000); debug('update light sensor'); }); } service.getCharacteristic(Characteristic.CurrentAmbientLightLevel).once('update', update); service.getCharacteristic(Characteristic.CurrentAmbientLightLevel).emit('update'); }, StatusActive: function (value) { }, StatusFault: function (value) { }, StatusTampered: function (value) { }, StatusLowBattery: function (Value) { } }; } Operater.prototype.Switch = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let name = accessory.displayName; return { On: function (value, preprocess) { let service = accessory.getService(name+value.instance, value.instance) || accessory.addService(Service.Switch, name+value.instance, value.instance); service.getCharacteristic(Characteristic.On) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', function (err, stdout) { let result = parser(stdout, {object: true}).node_detail.node.value.filter(function(_value) { return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; preprocess(result, callback); //callback(err, result==='True'); }); }) .on('set', function (On, callback) { let state = On ? 'True':'False'; child_process.exec(cmd+'valuepost.html -d "'+ nodeId+'-'+ value.class.replace(/\s/,'+') + '-' + value.genre + '-' + value.type + '-' + value.instance + '-' + value.index + '=' + state + '"', function (err, stdout) { callback(err); }); }); let update = function(next){ child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; service.updateCharacteristic(Characteristic.On, result === 'True'); service.getCharacteristic(Characteristic.On).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.On).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.On).once('update', update); service.getCharacteristic(Characteristic.On).emit('update'); } } } Operater.prototype.LockMechanism = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let name = accessory.displayName; return { LockCurrentState: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.LockMechanism, name, value.instance); service.getCharacteristic(Characteristic.LockCurrentState) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout) => { let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].current; callback(err, result === 'Secured' ? Characteristic.LockCurrentState.SECURED : Characteristic.LockCurrentState.UNSECURED); }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].current; service.updateCharacteristic(Characteristic.LockCurrentState, result === 'Secured' ? Characteristic.LockCurrentState.SECURED : Characteristic.LockCurrentState.UNSECURED); service.updateCharacteristic(Characteristic.LockTargetState, result === 'Secured' ? Characteristic.LockCurrentState.SECURED : Characteristic.LockCurrentState.UNSECURED); service.getCharacteristic(Characteristic.LockCurrentState).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.LockCurrentState).emit('update'); }, 3000); debug('Update current lock state: ' + result); }); } service.getCharacteristic(Characteristic.LockCurrentState).once('update', update); service.getCharacteristic(Characteristic.LockCurrentState).emit('update'); }, LockTargetState: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.LockMechanism, name, value.instance); service.getCharacteristic(Characteristic.LockTargetState) .on('set', function (onLock, callback) { let _onLock = onLock === Characteristic.LockTargetState.SECURED ? 'Secured' : 'Unsecured'; child_process.exec(cmd+'valuepost.html -d "'+ nodeId+'-'+ value.class.replace(/\s/,'+') + '-' + value.genre + '-' + value.type + '-' + value.instance + '-' + value.index + '=' + _onLock + '"', function (err, stdout) { // Should I force state checking? let timeout = setTimeout(() => { clearInterval(check); let currentState = service.getCharacteristic(Characteristic.LockCurrentState).value; service.updateCharacteristic(Characteristic.LockTargetState, currentState); callback(err); }, 10000); let check = setInterval(() => { debug('Lock wait for response'); if (service.getCharacteristic(Characteristic.LockCurrentState).value === onLock) { clearInterval(check); clearTimeout(timeout); callback(err); } }, 1500); }); }); } } } Operater.prototype.Battery = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let name = accessory.display; return { BatteryLevel: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.BatteryService, name, value.instance); service.getCharacteristic(Characteristic.BatteryLevel) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; callback(err, parseInt(result, 10)); }); }) let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let level = parseInt(result, 10); service.updateCharacteristic(Characteristic.BatteryLevel, level); service.getCharacteristic(Characteristic.BatteryLevel).once('update', update); setTimeout(function (){ service.getCharacteristic(Characteristic.BatteryLevel).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.BatteryLevel).once('update', update); service.getCharacteristic(Characteristic.BatteryLevel).emit('update'); }, ChargingState: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.BatteryService, name, value.instance); // No zwave instance }, StatusLowBattery: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.BatteryService, name, value.instance); let lowPower = 10 service.getCharacteristic(Characteristic.StatusLowBattery) .on('get', function (callback) { callback(null, service.getCharacteristic(Characteristic.BatteryLevel).value <= LowPower); }); let update = function () { service.updateCharacteristic(Characteristic.StatusLowBattery, service.getCharacteristic(Characteristic.BatteryLevel).value <= LowPower); service.getCharacteristic(Characteristic.StatusLowBattery).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.StatusLowBattery).emit('update'); }, 30000); // check if low battery every 30 min. }; service.getCharacteristic(Characteristic.StatusLowBattery).once('update', update); service.getCharacteristic(Characteristic.StatusLowBattery).emit('update'); } } } Operater.prototype.Door = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let door = accessory.getService(Service.Door) || accessory.addService(Service.Door); return { CurrentPosition: function (value) { }, PositionState: function (value) { }, TargetPosition: function (value) { }, HoldPosition: function (value) { }, ObstructionDetected: function (value) { } } } Operater.prototype.ContactSensor = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let contactSensor = accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor); return { ContactSensorState: function (value) { }, StatusActive: function (value) { }, StatusTampered: function (value) { }, StatusLowBattery: function (value) { } } } Operater.prototype.LeakSensor = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let leakSensor = accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor); return { LeakDetected: function (value) { }, StatusActive: function (value) { }, StatusTampered: function (value) { }, StatusLowBattery: function (value) { } } } Operater.prototype.HumiditySensor = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let name = accessory.displayName; return { CurrentRelativeHumidity: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.HumiditySensor, name, value.instance); service.getCharacteristic(Characteristic.CurrentRelativeHumidity) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; callback(err, parseFloat(result)); }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let hum = parseFloat(result); service.updateCharacteristic(Characteristic.CurrentRelativeHumidity, hum); service.getCharacteristic(Characteristic.CurrentRelativeHumidity).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.CurrentRelativeHumidity).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.CurrentRelativeHumidity).once('update', update); service.getCharacteristic(Characteristic.CurrentRelativeHumidity).emit('update'); }, StatusActive: function (value) { }, StatusFault: function (value) { }, StatusTampered: function (value) { }, StatusLowBattery: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.HumiditySensor, name, value.instance); let lowPower = 10; service.getCharacteristic(Characteristic.StatusLowBattery) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; callback(err, result <= LowPower); }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; service.updateCharacteristic(Characteristic.StatusLowBattery, result <= lowPower); service.getCharacteristic(Characteristic.StatusLowBattery).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.StatusLowBattery).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.StatusLowBattery).once('update', update); service.getCharacteristic(Characteristic.StatusLowBattery).emit('update'); } } } Operater.prototype.TemperatureSensor = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let name = accessory.displayName; return { CurrentTemperature: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.TemperatureSensor, name, value.instance); service.getCharacteristic(Characteristic.CurrentTemperature) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; callback(err, parseFloat(result)); }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let temp = parseFloat(result); service.updateCharacteristic(Characteristic.CurrentTemperature, temp); service.getCharacteristic(Characteristic.CurrentTemperature).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.CurrentTemperature).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.CurrentTemperature).once('update', update); service.getCharacteristic(Characteristic.CurrentTemperature).emit('update'); }, StatusActive: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.TemperatureSensor, name, value.instance); service.getCharacteristic(Characteristic.StatusActive) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.status; callback(err, result === 'Awake'); }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.status; service.updateCharacteristic(Characteristic.StatusActive, result === 'Awake'); service.getCharacteristic(Characteristic.StatusActive).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.StatusActive).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.StatusActive).once('update', update); service.getCharacteristic(Characteristic.StatusActive).emit('update'); }, StatusFault: function (value) { }, StatusLowBattery: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.TemperatureSensor, name, value.instance); let lowPower = 10; service.getCharacteristic(Characteristic.StatusLowBattery) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; callback(err, result <= LowPower); }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; service.updateCharacteristic(Characteristic.StatusLowBattery, result <= lowPower); servic.getCharacteristic(Characteristic.StatusLowBattery).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.StatusLowBattery).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.StatusLowBattery).once('update', update); service.getCharacteristic(Characteristic.StatusLowBattery).emit('update'); }, StatusTampered: function (value) { } } } Operater.prototype.Lightbulb = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let name = accessory.displayName; var brightnessLog = 0; return { Brightness: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.Lightbulb, name, value.instance); service.addCharacteristic(Characteristic.Brightness) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; callback(err, parseInt(result, 10)); }); }) .on('set', function (brightness, callback) { child_process.exec(cmd+'valuepost.html -d "'+ nodeId+'-'+ value.class.replace(/\s/,'+') + '-' + value.genre + '-' + value.type + '-' + value.instance + '-' + value.index + '=' + brightness + '"', function (err, stdout) { callback(err); brightnessLog = brightness; }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let brightness = parseInt(result, 10); service.updateCharacteristic(Characteristic.Brightness, brightness); service.getCharacteristic(Characteristic.Brightness).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.Brightness).emit('update'); }, 3000); service.setCharacteristic(Characteristic.Brightness, service.getCharacteristic(Characteristic.On).value ? brightnessLog : 0); service.updateCharacteristic(Characteristic.Brightness, service.getCharacteristic(Characteristic.On).value ? brightnessLog : 0); debug('update brightness: '+brightness); }); } service.once('update', update); service.emit('update'); }, On: function (value) { let service = accessory.getService(name+value.instance, value.instance) || accessory.addService(Service.Lightbulb, name+value.instance, value.instance); service.getCharacteristic(Characteristic.On) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', function (err, stdout) { let result = parser(stdout, {object: true}).node_detail.node.value.filter(function(_value) { return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; // preprocess(result, callback); callback(err, result==='True'); }); }) .on('set', function (On, callback) { let state = On ? 'True':'False'; child_process.exec(cmd+'valuepost.html -d "'+ nodeId+'-'+ value.class.replace(/\s/,'+') + '-' + value.genre + '-' + value.type + '-' + value.instance + '-' + value.index + '=' + state + '"', function (err, stdout) { callback(err); }); }); let update = function(next){ child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; service.updateCharacteristic(Characteristic.On, result === 'True'); service.getCharacteristic(Characteristic.On).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.On).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.On).once('update', update); service.getCharacteristic(Characteristic.On).emit('update'); }, Hue: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.Lightbulb, name, value.instance); service.addCharacteristic(Characteristic.Hue) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let [r, g, b] = result.split(/\s/).map(function (v) { return parseInt(v, 16); }); let hsv = rgb2hsv(r, g, b); service.updateCharacteristic(Characteristic.Saturation, hsv.saturation); service.updateCharacteristic(Characteristic.Brightness, hsv.value); callback(err, hsv.hue); }); }) .on('set', function (hue, callback) { let h = hue; // Get Saturation let s = service.getCharacteristic(Characteristic.Saturation).value; // Value (Brightness) let v = service.getCharacteristic(Characteristic.Brightness).value; var {r, g, b} = HSVtoRGB(h, s, v); let RGB = r.toString(16) + ' ' + g.toString(16) + ' ' + b.toString(16); child_process.exec(cmd+'valuepost.html -d "'+ nodeId+'-'+ value.class.replace(/\s/,'+') + '-' + value.genre + '-' + value.type + '-' + value.instance + '-' + value.index + '=' + RGB + '"', function (err, stdout) { callback(err); }); }); }, Saturation: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.Lightbulb, name, value.instance); service.addCharacteristic(Characteristic.Saturation) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let [r, g, b] = result.split(/\s/).map(function (v) { return parseInt(v, 16); }); let hsv = rgb2hsv(r, g, b); service.updateCharacteristic(Characteristic.Hue, hsv.hue); service.updateCharacteristic(Characteristic.Brightness, hsv.value); callback(err, hsv.saturation); }); }) .on('set', function (saturation, callback) { let s = saturation; // Hue let h = service.getCharacteristic(Characteristic.Hue).value; // Value (Brightness) let v = service.getCharacteristic(Characteristic.Brightness).value; let {r, g, b} = HSVtoRGB(h, s, v); let RGB = r.toString(16) + ' ' + g.toString(16) + ' ' + b.toString(16); child_process.exec(cmd+'valuepost.html -d "'+ nodeId+'-'+ value.class.replace(/\s/,'+') + '-' + value.genre + '-' + value.type + '-' + value.instance + '-' + value.index + '=' + RGB + '"', function (err, stdout) { callback(err); }); }); }, ColorTemperature: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.Lightbulb, name, value.instance); service.addCharacteristic(Characteristic.ColorTemperature) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout)=>{ let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let [r, g, b] = result.split(/\s/).map(function (v) { return parseInt(v, 16); }); let cTemp = ct.rgb2colorTemperature({red: r, green: g, blue: b}); callback(err, cTemp); }); }) .on('set', function (cTemp, callback) { let rgb = ct.colorTemperature2rgb(cTemp); let RGB = rgb.red.toString(16) + ' ' + rgb.green.toString(16) + ' ' + rgb.blue.toString(16); child_process.exec(cmd+'valuepost.html -d "'+ nodeId+'-'+ value.class.replace(/\s/,'+') + '-' + value.genre + '-' + value.type + '-' + value.instance + '-' + value.index + '=' + RGB + '"', function (err, stdout) { callback(err); }); }); } }; } Operater.prototype.WindowCovering = function (node) { let accessory = this.accessory; let nodeId = node.id; var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/'; let name = accessory.displayName; return { CurrentPosition: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.WindowCovering, name, value.instance); service.getCharacteristic(Characteristic.CurrentPosition) .on('get', function (callback) { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout) => { let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value)=>{ return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let level = parseInt(result, 10); callback(err, level); }); }); let update = function () { child_process.exec(cmd+'node_detail.cgi -d "fun=load&id='+nodeId+'"', (err, stdout) => { let result = parser(stdout, {object: true}).node_detail.node.value.filter((_value) => { return _value.index===value.index.toString() && _value.instance === value.instance.toString() && _value.label === value.label; })[0].$t; let level = parseInt(result, 10); service.updateCharacteristic(Characteristic.CurrentPosition, level); service.updateCharacteristic(Characteristic.TargetPosition, level); service.getCharacteristic(Characteristic.CurrentPosition).once('update', update); setTimeout(()=>{ service.getCharacteristic(Characteristic.CurrentPosition).emit('update'); }, 3000); }); } service.getCharacteristic(Characteristic.CurrentPosition).once('update', update); service.getCharacteristic(Characteristic.CurrentPosition).emit('update'); }, TargetPosition: function (value) { let service = accessory.getService(name, value.instance) || accessory.addService(Service.WindowCovering, name, value.instance); service.getCharacteristic(Characteristic.TargetPosition) .on('set', function (level, callback) { child_process.exec(cmd+'valuepost.html -d "'+ nodeId+'-'+ value.class.replace(/\s/,'+') + '-' + value.genre + '-' + value.type + '-' + value.instance + '-' + value.index + '=' + level + '"', function (err, stdout) { // Should I force state checking? let timeout = setTimeout(() => { clearInterval(check); let current = service.getCharacteristic(Characteristic.CurrentPosition).value; service.updateCharacteristic(Characteristic.TargetPosition, current); callback(err); }, 10000); let check = setInterval(() => { if (service.getCharacteristic(Characteristic.CurrentPosition).value === level) { clearInterval(check); clearTimeout(timeout); callback(err); } }, 1500); }); }); }, PositionState: function (value) { }, HoldPosition: function (value) { }, TargetHorizontalTiltAngle: function (value) { }, TargetVerticalTiltAngle: function (value) { }, CurrentHorizontalTiltAngle: function (value) { }, CurrentVerticalTiltAngle: function (value) { }, ObstructionDetected: function (value) { } } } /* * * */ function rgb2hsv () { var rr, gg, bb, r = arguments[0] / 255, g = arguments[1] / 255, b = arguments[2] / 255, h, s, v = Math.max(r, g, b), diff = v - Math.min(r, g, b), diffc = function(c){ return (v - c) / 6 / diff + 1 / 2; }; if (diff == 0) { h = s = 0; } else { s = diff / v; rr = diffc(r); gg = diffc(g); bb = diffc(b); if (r === v) { h = bb - gg; }else if (g === v) { h = (1 / 3) + rr - bb; }else if (b === v) { h = (2 / 3) + gg - rr; } if (h < 0) { h += 1; }else if (h > 1) { h -= 1; } } return { hue: Math.round(h * 360), saturation: Math.round(s * 100), value: Math.round(v * 100) }; } function HSVtoRGB(h, s, v) { h = h/360; s = s/100; v = v/100; var r, g, b, i, f, p, q, t; if (arguments.length === 1) { s = h.s, v = h.v, h = h.h; } i = Math.floor(h * 6); f = h * 6 - i; p = v * (1 - s); q = v * (1 - f * s); t = v * (1 - (1 - f) * s); switch (i % 6) { case 0: r = v, g = t, b = p; break; case 1: r = q, g = v, b = p; break; case 2: r = p, g = v, b = t; break; case 3: r = p, g = q, b = v; break; case 4: r = t, g = p, b = v; break; case 5: r = v, g = p, b = q; break; } return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) }; } /* * * */ function getNodeDetail (gateway, nodeId, callback) { var cmd = 'curl --digest ' + '-u ' + this.gateway.setting.acc + ':' + this.gateway.setting.pwd + ' ' + this.gateway.setting.ip + ':5000/node_detail.cgi -d "' + 'fun=load&id=' + nodeId + '"'; child_process.exec(cmd, function (err, stdout) { let node_detail = parser(stdout, {object: true}).node_detail; callback(err, node_detail); }); }