node-red-contrib-deconz
Advanced tools
Comparing version 0.8.3 to 0.9.1
981
deconz.js
@@ -5,10 +5,4 @@ var request = require('request'); | ||
module.exports = function (RED) { | ||
var devices = {}; | ||
/** | ||
* httpAdmin.get | ||
* | ||
* Enable http route to static files | ||
* | ||
*/ | ||
@@ -25,6 +19,3 @@ RED.httpAdmin.get(NODE_PATH + 'static/*', function (req, res) { | ||
/** | ||
* httpAdmin.get | ||
* | ||
* Enable http route to JSON itemlist for each controller (controller id passed as GET query parameter) | ||
* | ||
*/ | ||
@@ -36,3 +27,3 @@ RED.httpAdmin.get(NODE_PATH + 'itemlist', function (req, res) { | ||
if (controller && controller instanceof deConzServerNode) { | ||
if (controller && controller.constructor.name === "ServerNode") { | ||
controller.getItemsList(function (items, groups) { | ||
@@ -53,5 +44,3 @@ if (items) { | ||
var controller = RED.nodes.getNode(config.controllerID); | ||
var forceRefresh = config.forceRefresh ? ['1', 'yes', 'true'].includes(config.forceRefresh.toLowerCase()) : false; | ||
if (controller && controller instanceof deConzServerNode) { | ||
if (controller && controller.constructor.name === "ServerNode") { | ||
controller.getDeviceMeta(function (items) { | ||
@@ -68,955 +57,15 @@ if (items) { | ||
}); | ||
RED.httpAdmin.get(NODE_PATH + 'gwscanner', function (req, res) { | ||
// var ip = require("ip"); | ||
// console.log ( ip.address() ); | ||
var portscanner = require('portscanner'); | ||
// 127.0.0.1 is the default hostname; not required to provide | ||
portscanner.findAPortNotInUse([80], '127.0.0.1').then(port => { | ||
console.log(`Port ${port} is available!`); | ||
// Now start your service on this port... | ||
}); | ||
}); | ||
//*************** Input Node *************** | ||
function deConzItemIn(config) { | ||
RED.nodes.createNode(this, config); | ||
var node = this; | ||
node.config = config; | ||
node.sendState = function (device) { | ||
if (device.state === undefined) { | ||
console.log("CODE: #66"); | ||
console.log(device); | ||
} else { | ||
//status | ||
if ("state" in device && "reachable" in device.state && device.state.reachable === false) { | ||
node.status({ | ||
fill: "red", | ||
shape: "ring", | ||
text: "not reachable" | ||
}); | ||
} else if ("config" in device && "reachable" in device.config && device.config.reachable === false) { | ||
node.status({ | ||
fill: "red", | ||
shape: "ring", | ||
text: "not reachable" | ||
}); | ||
} else { | ||
node.status({ | ||
fill: "green", | ||
shape: "dot", | ||
text: (node.config.state in device.state) ? device.state[node.config.state] : "connected" | ||
}); | ||
} | ||
//outputs | ||
node.send([ | ||
{ | ||
payload: (node.config.state in device.state) ? device.state[node.config.state] : device.state, | ||
payload_raw: device | ||
}, | ||
format_to_homekit(device) | ||
]); | ||
} | ||
}; | ||
node.sendLastState = function () { | ||
if (typeof (config.device) == 'string' && config.device.length) { | ||
node.server.getDeviceMeta(function (deviceMeta) { | ||
if (deviceMeta) { | ||
devices[node.id] = deviceMeta.uniqueid; | ||
node.meta = deviceMeta; | ||
if (node.config.outputAtStartup) { | ||
setTimeout(function(){ | ||
node.sendState(deviceMeta); | ||
}, 1500); //we need this timeout after restart of node-red (homekit delays) | ||
} | ||
} else { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Device not found' | ||
}); | ||
} | ||
}, config.device); | ||
} else { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Device not set' | ||
}); | ||
} | ||
} | ||
//get server node | ||
node.server = RED.nodes.getNode(config.server); | ||
if (!node.server) return status_no_server(node); | ||
node.sendLastState(); | ||
} | ||
RED.nodes.registerType("deconz-input", deConzItemIn); | ||
//*************** GET Node *************** | ||
function deConzItemGet(config) { | ||
RED.nodes.createNode(this, config); | ||
var node = this; | ||
node.config = config; | ||
node.cleanTimer = null; | ||
//get server node | ||
node.server = RED.nodes.getNode(config.server); | ||
if (!node.server) return status_no_server(node); | ||
if (typeof(config.device) == 'string' && config.device.length) { | ||
node.status({}); //clean | ||
this.on('input', function (message) { | ||
clearTimeout(node.cleanTimer); | ||
node.server.getDeviceMeta(function(deviceMeta){ | ||
if (deviceMeta) { | ||
devices[node.id] = deviceMeta.uniqueid; | ||
node.meta = deviceMeta; | ||
//status | ||
if ("state" in deviceMeta && "reachable" in deviceMeta.state && deviceMeta.state.reachable === false) { | ||
node.status({ | ||
fill: "red", | ||
shape: "ring", | ||
text: "not reachable" | ||
}); | ||
} else if ("config" in deviceMeta && "reachable" in deviceMeta.config && deviceMeta.config.reachable === false) { | ||
node.status({ | ||
fill: "red", | ||
shape: "ring", | ||
text: "not reachable" | ||
}); | ||
} else { | ||
node.status({ | ||
fill: "green", | ||
shape: "dot", | ||
text: (config.state in node.meta.state)?(node.meta.state[config.state]?node.meta.state[config.state]:'false'):"received", | ||
}); | ||
node.send({ | ||
payload:(config.state in node.meta.state)?node.meta.state[config.state]:node.meta.state, | ||
meta:deviceMeta, | ||
}); | ||
} | ||
node.cleanTimer = setTimeout(function(){ | ||
node.status({}); //clean | ||
}, 3000); | ||
} else { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Device not found' | ||
}); | ||
} | ||
}, config.device); | ||
}); | ||
} else { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Device not set' | ||
}); | ||
} | ||
} | ||
RED.nodes.registerType("deconz-get", deConzItemGet); | ||
//*************** State Output Node *************** | ||
function deConzOut(config) { | ||
RED.nodes.createNode(this, config); | ||
var node = this; | ||
node.device = config.device; | ||
//get server node | ||
node.server = RED.nodes.getNode(config.server); | ||
if (!node.server) return status_no_server(node); | ||
node.payload = config.payload; | ||
node.payloadType = config.payloadType; | ||
node.command = config.command; | ||
node.commandType = config.commandType; | ||
node.cleanTimer = null; | ||
if (typeof(config.device) == 'string' && config.device.length) { | ||
node.status({}); //clean | ||
this.on('input', function (message) { | ||
clearTimeout(node.cleanTimer); | ||
var payload; | ||
switch (node.payloadType) { | ||
case 'flow': | ||
case 'global': { | ||
RED.util.evaluateNodeProperty(node.payload, node.payloadType, this, message, function (error, result) { | ||
if (error) { | ||
node.error(error, message); | ||
} else { | ||
payload = result; | ||
} | ||
}); | ||
break; | ||
} | ||
case 'date': { | ||
payload = Date.now(); | ||
break; | ||
} | ||
case 'object': | ||
case 'homekit': | ||
case 'msg': | ||
case 'num': | ||
case 'str': | ||
default: { | ||
payload = message[node.payload]; | ||
break; | ||
} | ||
} | ||
var command; | ||
switch (node.commandType) { | ||
case 'msg': { | ||
command = message[node.command]; | ||
break; | ||
} | ||
case 'deconz_cmd': | ||
command = node.command; | ||
switch (command) { | ||
case 'on': | ||
payload = payload && payload != '0'?true:false; | ||
break; | ||
case 'bri': | ||
case 'hue': | ||
case 'sat': | ||
case 'ct': | ||
case 'colorloopspeed': | ||
case 'transitiontime': | ||
payload = parseInt(payload); | ||
break; | ||
case 'json': | ||
case 'alert': | ||
case 'effect': | ||
default: { | ||
break; | ||
} | ||
} | ||
break; | ||
case 'homekit': | ||
payload = format_from_homekit(message, payload); | ||
break; | ||
case 'str': | ||
default: { | ||
command = node.command; | ||
break; | ||
} | ||
} | ||
//empty payload, stop | ||
if (payload === null) { | ||
return false; | ||
} | ||
//send data to API | ||
if ((/group_/g).test(node.device)) { | ||
var url = 'http://' + node.server.ip + ':' + node.server.port + '/api/' + node.server.apikey + '/groups/' + ((node.device).split('group_').join('')) + '/action'; | ||
var post = {}; | ||
if (node.commandType == 'object' || node.commandType == 'homekit') { | ||
post = payload; | ||
} else { | ||
if (command != 'on') post['on'] = true; | ||
if (command == 'bri') post['on'] = payload > 0 ? true : false; | ||
post[command] = payload; | ||
} | ||
node.postData(url, post); | ||
} else { | ||
node.server.getDeviceMeta(function (deviceMeta) { | ||
if (deviceMeta) { | ||
var url = 'http://' + node.server.ip + ':' + node.server.port + '/api/' + node.server.apikey + '/lights/' + deviceMeta.device_id + '/state'; | ||
var post = {}; | ||
if (node.commandType == 'object' || node.commandType == 'homekit') { | ||
post = payload; | ||
} else { | ||
if (command != 'on') post['on'] = true; | ||
if (command == 'bri') post['on'] = payload > 0 ? true : false; | ||
post[command] = payload; | ||
} | ||
node.postData(url, post); | ||
} else { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Device not found' | ||
}); | ||
} | ||
}, config.device); | ||
} | ||
// /api/<apikey>/groups/<id>/action | ||
// /api/<apikey>/lights/<id>/state | ||
}); | ||
} else { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Device not set' | ||
}); | ||
} | ||
node.postData = function(url, post) { | ||
node.log('Requesting url: '+url); | ||
console.log(post); | ||
request.put({ | ||
url: url, | ||
form: JSON.stringify(post) | ||
}, function(error, response, body){ | ||
if (body) { | ||
var response = JSON.parse(body)[0]; | ||
if ('success' in response) { | ||
node.status({ | ||
fill: "green", | ||
shape: "dot", | ||
text: "ok", | ||
}); | ||
} else if ('error' in response) { | ||
response.error.post = post; //add post data | ||
node.warn('deconz-out ERROR: '+response.error.description); | ||
node.warn(response.error); | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: "error", | ||
}); | ||
} | ||
node.cleanTimer = setTimeout(function(){ | ||
node.status({}); //clean | ||
}, 3000); | ||
} | ||
}); | ||
} | ||
} | ||
RED.nodes.registerType("deconz-output", deConzOut); | ||
//*************** Event Node *************** | ||
function deConzItemEvent(config) { | ||
RED.nodes.createNode(this, config); | ||
var node = this; | ||
node.config = config; | ||
node.cleanTimer = null; | ||
node.status({}); //clean | ||
//get server node | ||
node.server = RED.nodes.getNode(config.server); | ||
if (!node.server) return status_no_server(node); | ||
devices[node.id] = 'event'; | ||
node.sendLastState = function() { | ||
node.status({}); | ||
} | ||
} | ||
RED.nodes.registerType("deconz-event", deConzItemEvent); | ||
//*************** Server Node *************** | ||
function deConzServerNode(n) { | ||
RED.nodes.createNode(this, n); | ||
var node = this; | ||
node.items = undefined; | ||
node.groups = undefined; | ||
node.items_list = undefined; | ||
node.discoverProcess = false; | ||
node.name = n.name; | ||
node.ip = n.ip; | ||
node.port = n.port; | ||
node.ws_port = n.ws_port; | ||
node.apikey = n.apikey; | ||
node.pingTimeout = undefined; | ||
node.discoverDevices = function (callback, forceRefresh = false) { | ||
if (forceRefresh || node.items === undefined) { | ||
node.discoverProcess = true; | ||
node.log('discoverDevices: Refreshing devices list'); | ||
var url = "http://" + node.ip + ":" + node.port + "/api/" + node.apikey; | ||
node.log('discoverDevices: Requesting: ' + url); | ||
request.get(url, function (error, result, data) { | ||
if (error) { | ||
callback(error); | ||
return; | ||
} | ||
try { | ||
var dataParsed = JSON.parse(data); | ||
} catch (e) { | ||
callback(RED._("deconz.error.invalid-json")); | ||
return; | ||
} | ||
node.items = []; | ||
if (dataParsed) { | ||
for (var index in dataParsed.sensors) { | ||
var prop = dataParsed.sensors[index]; | ||
prop.device_type = 'sensors'; | ||
prop.device_id = parseInt(index); | ||
node.items[prop.uniqueid] = prop; | ||
} | ||
for (var index in dataParsed.lights) { | ||
var prop = dataParsed.lights[index]; | ||
prop.device_type = 'lights'; | ||
prop.device_id = parseInt(index); | ||
node.items[prop.uniqueid] = prop; | ||
} | ||
if ("groups" in dataParsed) { | ||
node.groups = dataParsed.groups; | ||
// console.log(node.groups); | ||
} | ||
} | ||
// console.log('discoverProcess = false'); | ||
node.discoverProcess = false; | ||
callback(node.items); | ||
return node.items; | ||
}); | ||
} else { | ||
node.log('discoverDevices: Using cached devices'); | ||
callback(node.items); | ||
return node.items; | ||
} | ||
} | ||
node.getDeviceMeta = function (callback, uniqueid) { | ||
var result = null; | ||
if (node.items === undefined && !node.discoverProcess) { | ||
node.discoverDevices(function (items) { | ||
if (items) { | ||
for (var index in items) { | ||
var item = items[index]; | ||
if (index === uniqueid) { | ||
result = item; | ||
break; | ||
} | ||
} | ||
} | ||
callback(result); | ||
return result; | ||
}, false); | ||
} else { | ||
if (node.getDiscoverProcess()) { | ||
var refreshIntervalId = setInterval(function(){ | ||
if (!node.getDiscoverProcess()) { | ||
clearInterval(refreshIntervalId); | ||
result = []; | ||
if ((node.items)) { | ||
for (var index in (node.items)) { | ||
var item = (node.items)[index]; | ||
if (index === uniqueid) { | ||
result = item; | ||
break; | ||
} | ||
} | ||
} | ||
callback(result); | ||
return result; | ||
} | ||
}, 100); | ||
} else { | ||
result = []; | ||
if ((node.items)) { | ||
for (var index in (node.items)) { | ||
var item = (node.items)[index]; | ||
if (index === uniqueid) { | ||
result = item; | ||
break; | ||
} | ||
} | ||
} | ||
callback(result); | ||
return result; | ||
} | ||
} | ||
} | ||
node.getItemsList = function (callback, forceRefresh = false) { | ||
node.discoverDevices(function(items){ | ||
node.items_list = []; | ||
for (var index in items) { | ||
var prop = items[index]; | ||
node.items_list.push({ | ||
device_name: prop.name + ' : ' + prop.type, | ||
uniqueid: prop.uniqueid, | ||
meta: prop | ||
}); | ||
} | ||
callback(node.items_list, node.groups); | ||
return node.items_list; | ||
}, forceRefresh); | ||
} | ||
node.getDiscoverProcess = function() { | ||
return node.discoverProcess; | ||
} | ||
node.connect = function () { | ||
connect(node, {host:node.ip, port:node.ws_port}); | ||
} | ||
// this.heartbeat = function() { | ||
// clearTimeout(node.pingTimeout); | ||
// | ||
// // Use `WebSocket#terminate()` and not `WebSocket#close()`. Delay should be | ||
// // equal to the interval at which your server sends out pings plus a | ||
// // conservative assumption of the latency. | ||
// node.pingTimeout = setTimeout(() => { | ||
// this.terminate(); | ||
// }, 15000 + 1000); | ||
// } | ||
// this.discoverDevices(node); | ||
connect(node, {host:node.ip, port:node.ws_port}); | ||
} | ||
RED.nodes.registerType("deconz-server", deConzServerNode); | ||
//*************** Input Node *************** | ||
function deConzItemBattery(config) { | ||
RED.nodes.createNode(this, config); | ||
var node = this; | ||
node.config = config; | ||
node.sendState = function (device) { | ||
if (device.state === undefined) { | ||
// console.log("CODE: #66"); | ||
// console.log(device); | ||
} else { | ||
var battery = null; | ||
if ("config" in device && "battery" in device.config && device.config.battery !== undefined && device.config.battery != null) { | ||
battery = device.config.battery; | ||
} | ||
//status | ||
if (battery) { | ||
//status | ||
if ("state" in device && "reachable" in device.state && device.state.reachable === false) { | ||
node.status({ | ||
fill: "red", | ||
shape: "ring", | ||
text: "not reachable" | ||
}); | ||
} else if ("config" in device && "reachable" in device.config && device.config.reachable === false) { | ||
node.status({ | ||
fill: "red", | ||
shape: "ring", | ||
text: "not reachable" | ||
}); | ||
} else { | ||
node.status({ | ||
fill: (battery >= 20)?((battery >= 50)?"green":"yellow"):"red", | ||
shape: "dot", | ||
text: battery+'%' | ||
}); | ||
} | ||
//outputs | ||
node.send([ | ||
device.config, | ||
format_to_homekit_battery(device) | ||
]); | ||
} | ||
} | ||
}; | ||
node.sendLastState = function() { | ||
if (typeof (config.device) == 'string' && config.device.length) { | ||
node.server.getDeviceMeta(function (deviceMeta) { | ||
if (deviceMeta) { | ||
devices[node.id] = deviceMeta.uniqueid; | ||
node.meta = deviceMeta; | ||
if (node.config.outputAtStartup) { | ||
setTimeout(function(){ | ||
node.sendState(deviceMeta); | ||
}, 1500); //we need this timeout after restart of node-red (homekit delays) | ||
} | ||
} else { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Device not found' | ||
}); | ||
} | ||
}, config.device); | ||
} else { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Device not set' | ||
}); | ||
} | ||
} | ||
//get server node | ||
node.server = RED.nodes.getNode(config.server); | ||
if (!node.server) return status_no_server(node); | ||
node.sendLastState(); | ||
} | ||
RED.nodes.registerType("deconz-battery", deConzItemBattery); | ||
function connect(serverNode, config) { | ||
const WebSocket = require('ws'); | ||
const ws = new WebSocket('ws://' + config.host + ':' + config.port); | ||
ws.on('open', function open() { | ||
serverNode.log('Connected to WebSocket'); | ||
for (var nodeId in devices) { | ||
var node = RED.nodes.getNode(nodeId); | ||
if (typeof(node.sendLastState) == 'function') { | ||
node.sendLastState(); | ||
} | ||
} | ||
}); | ||
ws.on('error', function(err) { | ||
serverNode.warn('deCONZ error: '+err); | ||
}); | ||
ws.on('message', function(data) { | ||
if (data) { | ||
var dataParsed = JSON.parse(data); | ||
for (var nodeId in devices) { | ||
var item = devices[nodeId]; | ||
if ("event" == item && "t" in dataParsed && dataParsed.t == "event") { | ||
var node = RED.nodes.getNode(nodeId); | ||
if (node && "type" in node && node.type === "deconz-event") { | ||
var serverNode = RED.nodes.getNode(node.server.id); | ||
node.send({'payload': dataParsed, 'device': serverNode.items[dataParsed.uniqueid]}); | ||
clearTimeout(node.cleanTimer); | ||
node.status({ | ||
fill: "green", | ||
shape: "dot", | ||
text: 'event' | ||
}); | ||
node.cleanTimer = setTimeout(function () { | ||
node.status({}); //clean | ||
}, 3000); | ||
} | ||
} | ||
if (dataParsed.uniqueid === item) { | ||
var node = RED.nodes.getNode(nodeId); | ||
if (node && "server" in node) { | ||
//update server items db | ||
var serverNode = RED.nodes.getNode(node.server.id); | ||
if ("items" in serverNode && dataParsed.uniqueid in serverNode.items) { | ||
serverNode.items[dataParsed.uniqueid].state = dataParsed.state; | ||
if (node.type === "deconz-input") { | ||
console.log(dataParsed); | ||
node.sendState(dataParsed); | ||
} | ||
} | ||
} else { | ||
console.log('ERROR: cant get '+nodeId+' node, removed from list'); | ||
delete devices[nodeId]; | ||
if ("server" in node) { | ||
var serverNode = RED.nodes.getNode(node.server.id); | ||
delete serverNode.items[dataParsed.uniqueid]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
ws.on('close', function close() { | ||
clearTimeout(serverNode.pingTimeout); | ||
// setTimeout(connect(serverNode, config), 15000); | ||
serverNode.warn('deCONZ WebSocket closed'); | ||
for (var nodeId in devices) { | ||
var node = RED.nodes.getNode(nodeId); | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'disconnected' | ||
}); | ||
} | ||
setTimeout(function(){ | ||
serverNode.connect(); | ||
}, 10000); | ||
}); | ||
// ws.on('open', serverNode.heartbeat); | ||
// ws.on('ping', serverNode.heartbeat); | ||
} | ||
function format_to_homekit(device) { | ||
var state = device.state; | ||
var config = device.config; | ||
var no_reponse = false; | ||
if (state !== undefined && state['reachable'] !== undefined && state['reachable'] != null && state['reachable'] === false) { | ||
no_reponse = true; | ||
} | ||
if (config !== undefined && config['reachable'] !== undefined && config['reachable'] != null && config['reachable'] === false) { | ||
no_reponse = true; | ||
} | ||
var msg = {}; | ||
var characteristic = {}; | ||
if (state !== undefined){ | ||
// if (device.device_type === 'sensors') { | ||
// switch (device.type) { | ||
// case "ZHATemperature": | ||
// characteristic.CurrentTemperature = state.temperature/100; | ||
// break; | ||
// case "ZHAHumidity": | ||
// characteristic.CurrentRelativeHumidity = state.humidity/100; | ||
// break; | ||
// } | ||
// } | ||
if (state['temperature'] !== undefined){ | ||
characteristic.CurrentTemperature = state['temperature']/100; | ||
if (no_reponse) characteristic.CurrentTemperature = "NO_RESPONSE"; | ||
} | ||
if (state['humidity'] !== undefined){ | ||
characteristic.CurrentRelativeHumidity = state['humidity']/100; | ||
if (no_reponse) characteristic.CurrentRelativeHumidity = "NO_RESPONSE"; | ||
} | ||
if (state['lux'] !== undefined){ | ||
characteristic.CurrentAmbientLightLevel = state['lux']; | ||
if (no_reponse) characteristic.CurrentAmbientLightLevel = "NO_RESPONSE"; | ||
} | ||
if (state['fire'] !== undefined){ | ||
characteristic.SmokeDetected = state['fire']; | ||
if (no_reponse) characteristic.SmokeDetected = "NO_RESPONSE"; | ||
} | ||
if (state['buttonevent'] !== undefined){ | ||
//https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/Xiaomi-WXKG01LM | ||
// Event Button Action | ||
// 1000 One initial press | ||
// 1001 One single hold | ||
// 1002 One single short release | ||
// 1003 One single hold release | ||
// 1004 One double short press | ||
// 1005 One triple short press | ||
// 1006 One quad short press | ||
// 1010 One five+ short press | ||
if ([1002,2002,3002,4002,5002].indexOf(state['buttonevent']) >= 0) characteristic.ProgrammableSwitchEvent = 0; | ||
else if ([1004,2004,3004,4004,5004].indexOf(state['buttonevent']) >= 0) characteristic.ProgrammableSwitchEvent = 1; | ||
else if ([1001,2001,3001,4001,5001].indexOf(state['buttonevent']) >= 0) characteristic.ProgrammableSwitchEvent = 2; | ||
else if ([1005,2005,3005,4005,5005].indexOf(state['buttonevent']) >= 0) characteristic.ProgrammableSwitchEvent = 3; | ||
else if ([1006,2006,3006,4006,5006].indexOf(state['buttonevent']) >= 0) characteristic.ProgrammableSwitchEvent = 4; | ||
else if ([1010,2010,3010,4010,5010].indexOf(state['buttonevent']) >= 0) characteristic.ProgrammableSwitchEvent = 5; | ||
if (no_reponse) characteristic.ProgrammableSwitchEvent = "NO_RESPONSE"; | ||
//index of btn | ||
if ([1001,1002,1004,1005,1006,1010].indexOf(state['buttonevent']) >= 0) characteristic.ServiceLabelIndex = 1; | ||
else if ([2001,2002,2004,2005,2006,2010].indexOf(state['buttonevent']) >= 0) characteristic.ServiceLabelIndex = 2; | ||
else if ([3001,3002,3004,3005,3006,3010].indexOf(state['buttonevent']) >= 0) characteristic.ServiceLabelIndex = 3; | ||
else if ([4001,4002,4004,4005,4006,4010].indexOf(state['buttonevent']) >= 0) characteristic.ServiceLabelIndex = 4; | ||
else if ([5001,5002,5004,5005,5006,5010].indexOf(state['buttonevent']) >= 0) characteristic.ServiceLabelIndex = 5; | ||
} | ||
// if (state['consumption'] !== null){ | ||
// characteristic.OutletInUse = state['consumption']; | ||
// } | ||
if (state['power'] !== undefined){ | ||
characteristic.OutletInUse = state['power']>0?true:false; | ||
if (no_reponse) characteristic.OutletInUse = "NO_RESPONSE"; | ||
} | ||
if (state['water'] !== undefined){ | ||
characteristic.LeakDetected = state['water']?1:0; | ||
if (no_reponse) characteristic.LeakDetected = "NO_RESPONSE"; | ||
} | ||
if (state['presence'] !== undefined){ | ||
characteristic.MotionDetected = state['presence']; | ||
if (no_reponse) characteristic.MotionDetected = "NO_RESPONSE"; | ||
} | ||
if (state['open'] !== undefined){ | ||
characteristic.ContactSensorState = state['open']; | ||
if (no_reponse) characteristic.ContactSensorState = "NO_RESPONSE"; | ||
} | ||
if (state['vibration'] !== undefined){ | ||
characteristic.ContactSensorState = state['vibration']; | ||
if (no_reponse) characteristic.ContactSensorState = "NO_RESPONSE"; | ||
} | ||
if (state['on'] !== undefined){ | ||
characteristic.On = state['on']; | ||
if (no_reponse) characteristic.On = "NO_RESPONSE"; | ||
} | ||
if (state['bri'] !== undefined){ | ||
characteristic.Brightness = state['bri']/2.55; | ||
if (no_reponse) characteristic.Brightness = "NO_RESPONSE"; | ||
} | ||
if (state['hue'] !== undefined){ | ||
characteristic.Hue = state['hue']/182; | ||
if (no_reponse) characteristic.Hue = "NO_RESPONSE"; | ||
} | ||
if (state['sat'] !== undefined){ | ||
characteristic.Saturation = state['sat']/2.55; | ||
if (no_reponse) characteristic.Saturation = "NO_RESPONSE"; | ||
} | ||
if (state['ct'] !== undefined){ | ||
characteristic.ColorTemperature = state['ct']; | ||
if (state['ct'] < 140) characteristic.ColorTemperature = 140; | ||
else if (state['ct'] > 500) characteristic.ColorTemperature = 500; | ||
if (no_reponse) characteristic.ColorTemperature = "NO_RESPONSE"; | ||
} | ||
} | ||
//battery status | ||
if (config !== undefined) { | ||
if (config['battery'] !== undefined && config['battery'] != null){ | ||
if (device.type !== 'ZHASwitch') { //exclude | ||
characteristic.StatusLowBattery = parseInt(device.config['battery']) <= 15 ? 1 : 0; | ||
if (no_reponse) characteristic.StatusLowBattery = "NO_RESPONSE"; | ||
} | ||
} | ||
} | ||
if (Object.keys(characteristic).length === 0) return null; //empty response | ||
msg.payload = characteristic; | ||
return msg; | ||
} | ||
function format_to_homekit_battery(device) { | ||
var msg = {}; | ||
var characteristic = {}; | ||
//battery status | ||
if ("config" in device) { | ||
if (device.config['battery'] !== undefined && device.config['battery'] != null){ | ||
characteristic.BatteryLevel = parseInt(device.config['battery']); | ||
characteristic.StatusLowBattery = parseInt(device.config['battery'])<=15?1:0; | ||
msg.payload = characteristic; | ||
// msg.topic = "battery"; | ||
return msg; | ||
} | ||
} | ||
return null; | ||
} | ||
function format_from_homekit(message, payload) { | ||
if (message.hap.context === undefined) { | ||
return null; | ||
} | ||
var msg = {}; | ||
if (payload.On !== undefined) { | ||
msg['on'] = payload.On; | ||
} else if (payload.Brightness !== undefined) { | ||
msg['bri'] = payload.Brightness*2.55; | ||
msg['on'] = payload.Brightness>0?true:false; | ||
} else if (payload.Hue !== undefined) { | ||
msg['hue'] = payload.Hue*182; | ||
msg['on'] = true; | ||
} else if (payload.Saturation !== undefined) { | ||
msg['sat'] = payload.Saturation*2.55; | ||
msg['on'] = true; | ||
} else if (payload.ColorTemperature !== undefined) { | ||
msg['ct'] = payload.ColorTemperature; | ||
msg['on'] = true; | ||
} | ||
return msg; | ||
} | ||
function status_no_server(node) { | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'Server node error' | ||
}); | ||
return false; | ||
} | ||
// RED.httpAdmin.get(NODE_PATH + 'gwscanner', function (req, res) { | ||
// // var ip = require("ip"); | ||
// // console.log ( ip.address() ); | ||
// | ||
// var portscanner = require('portscanner'); | ||
// | ||
// // 127.0.0.1 is the default hostname; not required to provide | ||
// portscanner.findAPortNotInUse([80], '127.0.0.1').then(port => { | ||
// console.log(`Port ${port} is available!`); | ||
// | ||
// // Now start your service on this port... | ||
// }); | ||
// }); | ||
} |
@@ -13,3 +13,4 @@ { | ||
"portscanner": "latest", | ||
"ws": "latest" | ||
"ws": "latest", | ||
"events": "latest" | ||
}, | ||
@@ -28,3 +29,9 @@ "description": "deCONZ connectivity nodes for node-red", | ||
"nodes": { | ||
"server": "deconz.js" | ||
"in": "nodes/in.js", | ||
"get": "nodes/get.js", | ||
"out": "nodes/out.js", | ||
"event": "nodes/event.js", | ||
"battery": "nodes/battery.js", | ||
"server": "nodes/server.js", | ||
"api": "deconz.js" | ||
} | ||
@@ -36,3 +43,3 @@ }, | ||
}, | ||
"version": "0.8.3" | ||
"version": "0.9.1" | ||
} |
function deconz_gatewayScanner(nodeItem, selectedItemElementName, options = {}) { | ||
$.getJSON('/deconz/gwscanner', {}) | ||
$.getJSON('deconz/gwscanner', {}) | ||
.done(function (data, textStatus, jqXHR) { | ||
@@ -26,3 +26,3 @@ console.log(data); | ||
if (controller) { | ||
$.getJSON('/deconz/itemlist', { | ||
$.getJSON('deconz/itemlist', { | ||
controllerID: controller.id, | ||
@@ -187,3 +187,3 @@ forceRefresh: refresh | ||
if (controller) { | ||
$.getJSON('/deconz/statelist', { | ||
$.getJSON('deconz/statelist', { | ||
controllerID: controller.id, | ||
@@ -190,0 +190,0 @@ uniqueid:$('#node-input-device').val() |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
759468
45
5
2603
+ Addedevents@latest
+ Addedevents@3.3.0(transitive)