node-red-contrib-huemagic
Version:
Philips Hue node to control bridges, lights, groups, scenes, rules, taps, switches, buttons, motion sensors, temperature sensors and Lux sensors using Node-RED.
204 lines (178 loc) • 5.25 kB
JavaScript
module.exports = function(RED)
{
"use strict";
function HueBrightness(config)
{
RED.nodes.createNode(this, config);
const scope = this;
const bridge = RED.nodes.getNode(config.bridge);
const async = require('async');
// SAVE LAST COMMAND
this.lastCommand = null;
//
// CHECK CONFIG
if(bridge == null)
{
this.status({fill: "red", shape: "ring", text: "hue-brightness.node.not-configured"});
return false;
}
//
// UNIVERSAL MODE?
if(!config.sensorid)
{
this.status({fill: "grey", shape: "dot", text: "hue-brightness.node.universal"});
}
//
// UPDATE STATE
if(typeof bridge.disableupdates != 'undefined' || bridge.disableupdates == false)
{
this.status({fill: "grey", shape: "dot", text: "hue-brightness.node.init"});
}
//
// SUBSCRIBE TO UPDATES FROM THE BRIDGE
bridge.subscribe("light_level", config.sensorid, function(info)
{
let currentState = bridge.get("light_level", info.id);
// RESOURCE FOUND?
if(currentState !== false)
{
// SEND MESSAGE
if(!config.skipevents && (config.initevents || info.suppressMessage == false))
{
// SET LAST COMMAND
if(scope.lastCommand !== null)
{
currentState.command = scope.lastCommand;
}
scope.send(currentState);
// RESET LAST COMMAND
scope.lastCommand = null;
}
// NOT IN UNIVERAL MODE? -> CHANGE UI STATES
if(config.sensorid)
{
if(currentState.payload.reachable == false)
{
scope.status({fill: "red", shape: "ring", text: "hue-brightness.node.not-reachable"});
}
else if(currentState.payload.active == true)
{
if(currentState.payload.dark)
{
var statusMessage = RED._("hue-brightness.node.lux-dark", { lux: currentState.payload.lux });
scope.status({fill: "blue", shape: "dot", text: statusMessage });
}
else if(currentState.payload.daylight)
{
var statusMessage = RED._("hue-brightness.node.lux-daylight", { lux: currentState.payload.lux });
scope.status({fill: "yellow", shape: "dot", text: statusMessage });
}
else
{
var statusMessage = RED._("hue-brightness.node.lux", { lux: currentState.payload.lux });
scope.status({fill: "grey", shape: "dot", text: statusMessage });
}
}
else if(currentState.payload.active == false)
{
scope.status({fill: "red", shape: "ring", text: "hue-brightness.node.deactivated"});
}
}
}
});
//
// ON COMMAND
this.on('input', function(msg, send, done)
{
// REDEFINE SEND AND DONE IF NOT AVAILABLE
send = send || function() { scope.send.apply(scope,arguments); }
done = done || function() { scope.done.apply(scope,arguments); }
// SET LAST COMMAND
scope.lastCommand = RED.util.cloneMessage(msg);
// CREATE PATCH
let patchObject = {};
// DEFINE SENSOR ID & CURRENT STATE
const tempSensorID = (!config.sensorid && typeof msg.topic != 'undefined' && bridge.validResourceID.test(msg.topic) === true) ? msg.topic : config.sensorid;
if(!tempSensorID)
{
scope.error("Please submit a valid sensor ID.");
return false;
}
let currentState = bridge.get("light_level", tempSensorID);
if(!currentState)
{
scope.error("The sensor in not yet available. Please wait until HueMagic has established a connection with the bridge or check whether the resource ID in the configuration is valid.");
return false;
}
// GET CURRENT STATE
if( (typeof msg.payload != 'undefined' && typeof msg.payload.status != 'undefined') || (typeof msg.__user_inject_props__ != 'undefined' && msg.__user_inject_props__ == "status") )
{
// SET LAST COMMAND
if(scope.lastCommand !== null)
{
currentState.command = scope.lastCommand;
}
// SEND STATE
scope.send(currentState);
// RESET LAST COMMAND
scope.lastCommand = null;
if(done) { done(); }
return true;
}
// TURN ON / OFF
if((msg.payload === true || msg.payload === false) && (msg.payload != currentState.payload.active))
{
// PREPARE PATCH
patchObject["enabled"] = (msg.payload == true);
}
//
// SHOULD PATCH?
if(Object.values(patchObject).length > 0)
{
// CHANGE NODE UI STATE
if(config.sensorid)
{
scope.status({fill: "grey", shape: "ring", text: "hue-brightness.node.command"});
}
// PATCH!
async.retry({
times: 3,
errorFilter: function(err) {
return (err.status == 503);
},
interval: function(retryCount) { return retryCount*2000; }
},
function(callback, results)
{
bridge.patch("light_level", tempSensorID, patchObject)
.then(function() { callback(null, true); })
.catch(function(errors) { callback(errors, null); });
},
function(errors, success)
{
if(errors)
{
scope.error(errors);
}
else if(done)
{
done();
}
});
}
else
{
// SET LAST COMMAND
if(scope.lastCommand !== null)
{
currentState.command = scope.lastCommand;
}
// SEND STATE
scope.send(currentState);
// RESET LAST COMMAND
scope.lastCommand = null;
}
});
}
RED.nodes.registerType("hue-brightness", HueBrightness);
}