0.1.2
This commit is contained in:
parent
6e37268879
commit
c0c97aed87
12
README.md
12
README.md
|
@ -23,7 +23,7 @@ Lights can be controlled by sending an objet with one or more of the following p
|
||||||
* `saturation` `number` `[0,100]` Sets the saturation of the light. Only for CWS. (UNTESTED)
|
* `saturation` `number` `[0,100]` Sets the saturation of the light. Only for CWS. (UNTESTED)
|
||||||
|
|
||||||
### Output
|
### Output
|
||||||
If the node is set to observe and the target light is updated or if triggered manually by sending a `"status"` request as `msg.payload` to the node, the node will send a `msg.payload` for which the `light` property is the current status of the light.
|
If the node is set to observe and the target light is updated or if triggered manually by sending a `"status"` request as `msg.payload` to the node, the node will send a `msg.payload` with the current status of the light.
|
||||||
* `id` `number` The id of the light.
|
* `id` `number` The id of the light.
|
||||||
* `name` `string` The given name of the light.
|
* `name` `string` The given name of the light.
|
||||||
* `model` `string` The model of the light.
|
* `model` `string` The model of the light.
|
||||||
|
@ -40,3 +40,13 @@ If the node is set to observe and the target light is updated or if triggered ma
|
||||||
* `seen` `number` When the light was last interacted with by the gateway (or similar), measured in epoch time.
|
* `seen` `number` When the light was last interacted with by the gateway (or similar), measured in epoch time.
|
||||||
* `type` `number` The type of device where 2 is light.
|
* `type` `number` The type of device where 2 is light.
|
||||||
* `power` `number` The type of power source powering the light. Will most likely always be 1.
|
* `power` `number` The type of power source powering the light. Will most likely always be 1.
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
### 0.1.2
|
||||||
|
* Moved output status object from `msg.payload.light` to `msg.payload`.
|
||||||
|
* Updated security code, identity and PSK to be saved as credentials in config.
|
||||||
|
* Updated info panels and tweaked node appearance.
|
||||||
|
|
||||||
|
### 0.1.1
|
||||||
|
* Published to NPM
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
<!-- ======= CONNECTION ========= -->
|
<!-- Config Node -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
RED.nodes.registerType('tradfri-connection',{
|
RED.nodes.registerType('tradfri-connection',{
|
||||||
category: 'config',
|
category: 'config',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: { value:"" },
|
|
||||||
address: { value:"", required:true },
|
address: { value:"", required:true },
|
||||||
securityCode: { value:"" },
|
name: { value:"" }
|
||||||
identity: { value:"" },
|
},
|
||||||
psk: { value:"" },
|
credentials: {
|
||||||
|
securityCode: { type:"text" },
|
||||||
|
identity: { type:"text" },
|
||||||
|
psk: { type:"text" }
|
||||||
},
|
},
|
||||||
label: function() {
|
label: function() {
|
||||||
return this.name || "tradfri@" + this.address;
|
return this.name || "tradfri@" + this.address;
|
||||||
|
@ -17,28 +19,37 @@
|
||||||
|
|
||||||
<script type="text/x-red" data-template-name="tradfri-connection">
|
<script type="text/x-red" data-template-name="tradfri-connection">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-name"><i class="icon-bookmark"></i> Name</label>
|
<label for="node-config-input-address"><i class="fa fa-globe"></i> Address</label>
|
||||||
<input type="text" id="node-config-input-name">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-config-input-address"><i class="icon-bookmark"></i> Address</label>
|
|
||||||
<input type="text" id="node-config-input-address">
|
<input type="text" id="node-config-input-address">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-securityCode"><i class="icon-bookmark"></i> Security Code</label>
|
<label for="node-config-input-securityCode"><i class="fa fa-gears"></i> Security Code</label>
|
||||||
<input type="text" id="node-config-input-securityCode">
|
<input type="text" id="node-config-input-securityCode">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-identity"><i class="icon-bookmark"></i> Identity</label>
|
<label for="node-config-input-identity"><i class="fa fa-address-card-o"></i> Identity</label>
|
||||||
<input type="text" id="node-config-input-identity">
|
<input type="text" id="node-config-input-identity">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-psk"><i class="icon-bookmark"></i> Pre-shared key</label>
|
<label for="node-config-input-psk"><i class="fa fa-lock"></i> Pre-shared key</label>
|
||||||
<input type="text" id="node-config-input-psk">
|
<input type="text" id="node-config-input-psk">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-config-input-name">
|
||||||
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- ======= THREADFREE ========= -->
|
<script type="text/x-red" data-help-name="tradfri-connection">
|
||||||
|
<ul>
|
||||||
|
<li><i class="fa fa-globe"></i> <b>Address:</b> The address to your gateway.</li>
|
||||||
|
<li><i class="fa fa-gears"></i> <b>Security code:</b> The security code on the backside of your gateway. You only need to enter this if you <em>don't</em> have an identiy and PSK. In that case identity and PSK will be generated for you using the security key.</li>
|
||||||
|
<li><i class="fa fa-address-card-o"></i> <b>Address:</b> The identiy used to access the gateway. Used together with a PSK.</li>
|
||||||
|
<li><i class="fa fa-lock"></i> <b>Pre-shared key:</b> The passkey used to access the gateway. Used together with an identity.</li>
|
||||||
|
</ul>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--- I/O Node -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var updateDevices = (currentDeviceId) => {
|
var updateDevices = (currentDeviceId) => {
|
||||||
let configNodeId = $('#node-input-connection').find(":selected").val();
|
let configNodeId = $('#node-input-connection').find(":selected").val();
|
||||||
|
@ -61,7 +72,7 @@
|
||||||
|
|
||||||
RED.nodes.registerType('tradfri',{
|
RED.nodes.registerType('tradfri',{
|
||||||
category: 'function',
|
category: 'function',
|
||||||
color: '#84E87A',
|
color: '#9FE597',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
deviceId: {value: "", required:true, validate:RED.validators.number()},
|
deviceId: {value: "", required:true, validate:RED.validators.number()},
|
||||||
|
@ -69,9 +80,10 @@
|
||||||
connection: {value:"", type:"tradfri-connection"},
|
connection: {value:"", type:"tradfri-connection"},
|
||||||
observe: { value:true, required: true },
|
observe: { value:true, required: true },
|
||||||
},
|
},
|
||||||
|
align: 'right',
|
||||||
inputs:1,
|
inputs:1,
|
||||||
outputs:1,
|
outputs:1,
|
||||||
icon: "light.png",
|
icon: 'light.png',
|
||||||
label: function() {
|
label: function() {
|
||||||
return this.deviceName || "tradfri";
|
return this.deviceName || "tradfri";
|
||||||
},
|
},
|
||||||
|
@ -96,11 +108,7 @@
|
||||||
|
|
||||||
<script type="text/x-red" data-template-name="tradfri">
|
<script type="text/x-red" data-template-name="tradfri">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
<label for="node-input-connection"><i class="fa fa-cog"></i> Connection</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-connection"><i class="fa fa-bookmark"></i> Connection</label>
|
|
||||||
<input type="text" id="node-input-connection" placeholder="Connection">
|
<input type="text" id="node-input-connection" placeholder="Connection">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
|
@ -120,27 +128,50 @@
|
||||||
<input type="checkbox" id="node-input-observe" style="display: inline-block; width: auto; vertical-align: top;">
|
<input type="checkbox" id="node-input-observe" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
<label for="node-input-observe" style="width: 70%;" >Observe device?</label>
|
<label for="node-input-observe" style="width: 70%;" >Observe device?</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="tradfri">
|
<script type="text/x-red" data-help-name="tradfri">
|
||||||
<p>Interface for IKEA Tradfri devices</p>
|
<p>Interface for IKEA Tradfri devices</p>
|
||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt> payload <span class="property-type"> string </span> </dt>
|
<dt> payload <span class="property-type"> string | object</span> </dt>
|
||||||
<dd> A single command can be sent as a string to the node. <dd>
|
<dd> The payload can either be a single command to the node (such as a status update request) sent as a string or an object with one or more commands targeting the light.</dd>
|
||||||
<dt> payload <span class="property-type"> object </span> </dt>
|
|
||||||
<dd> An object with one or more commands targeting the light. </dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Outputs</h3>
|
<h3>Outputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt> payload.light <span class="property-type"> object </span></dt>
|
<dt> payload <span class="property-type"> object </span></dt>
|
||||||
<dd> The status of the light. </dd>
|
<dd> The status of the light. </dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h3>Details</h3>
|
<h3>Details</h3>
|
||||||
The tradfri node acts as both input and output for a IKEA Tradfri lighbulb.
|
The tradfri node acts as both input and output for a IKEA Tradfri lighbulb.
|
||||||
|
|
||||||
If the node is set to observe it will send a message with the lights current properties as payload every time the light is updated:
|
<h2>Controlling the node</h2>
|
||||||
|
Nodes can be programmatically controlled by sending a message with <code>msg.payload</code> set to one of the following strings:
|
||||||
|
<ul>
|
||||||
|
<li><code>"status"</code> The node will output the current status of its target light.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Controlling the lights</h2>
|
||||||
|
Lights can be controlled by sending an objet with one or more of the following properties as <code>msg.payload</code> to the node.
|
||||||
|
<ul>
|
||||||
|
<!-- <li><code>id</code><code>number</code> The id of the light <li>
|
||||||
|
<li><code>name</code><code>string</code> The given name of the light <li> -->
|
||||||
|
<li><code>on</code><code>boolean</code><li> Turn the light on or off.</li>
|
||||||
|
<li><code>brightness</code><code>number</code> The brightness of the light [0,100]</li>
|
||||||
|
<li><code>colorTemperature</code><code>number</code> The color temperature of the light [0,100]</li>
|
||||||
|
<li><code>color</code><code>string</code> Sets the color of the light. For WS-bulbs, <code>F5FAF6</code>, <code>F1E0B5</code> and <code>EFD275</code> will set the light to the default cold, normal and warm temperatures respectively.</li>
|
||||||
|
<li><code>transition</code><code>number</code> The default transition time for operations. Will only work for single operation commands and not for on/off. Defaults to 0. </li>
|
||||||
|
<li><code>hue</code><code>number</code> Sets the hue of the light. Only for CWS. [0,365] (UNTESTED)</li>
|
||||||
|
<li><code>saturation</code><code>number</code> Sets the saturation of the light. Only for CWS. [0,100] (UNTESTED)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Observing</h2>
|
||||||
|
If the node is set to observe it will send a message with the lights current properties as payload every time the light is updated:
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>id</code><code>number</code> The id of the light </li>
|
<li><code>id</code><code>number</code> The id of the light </li>
|
||||||
<li><code>name</code><code>string</code> The given name of the light </li>
|
<li><code>name</code><code>string</code> The given name of the light </li>
|
||||||
|
@ -160,24 +191,4 @@
|
||||||
<li><code>power</code><code>number</code> The type of power source powering the light. Will most likely always be 1.</li>
|
<li><code>power</code><code>number</code> The type of power source powering the light. Will most likely always be 1.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Controlling the node</h2>
|
|
||||||
The can be programmatically controlled by sending a message with <code>msg.payload</code> set to one of the following:
|
|
||||||
<ul>
|
|
||||||
<li><code>status</code> The node will output the current status of its target light.
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>Controlling the lights</h2>
|
|
||||||
Lights can be controlled by sending an objet with one or more of the following properties as <code>msg.payload</code> to the node.
|
|
||||||
<ul>
|
|
||||||
<!-- <li><code>id</code><code>number</code> The id of the light <li>
|
|
||||||
<li><code>name</code><code>string</code> The given name of the light <li> -->
|
|
||||||
<li><code>on</code><code>boolean</code><li> Turn the light on or off.</li>
|
|
||||||
<li><code>brightness</code><code>number</code> The brightness of the light [0,100]</li>
|
|
||||||
<li><code>colorTemperature</code><code>number</code> The color temperature of the light [0,100]</li>
|
|
||||||
<li><code>color</code><code>string</code> Sets the color of the light. For WS-bulbs, <code>F5FAF6</code>, <code>F1E0B5</code> and <code>EFD275</code> will set the light to the default cold, normal and warm temperatures respectively.</li>
|
|
||||||
<li><code>transition</code><code>number</code> The default transition time for operations. Will only work for single operation commands and not for on/off. Defaults to 0. </li>
|
|
||||||
<li><code>hue</code><code>number</code> Sets the hue of the light. Only for CWS. [0,365] (UNTESTED)</li>
|
|
||||||
<li><code>saturation</code><code>number</code> Sets the saturation of the light. Only for CWS. [0,100] (UNTESTED)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -60,9 +60,9 @@ module.exports = function (RED) {
|
||||||
RED.nodes.createNode(node, config);
|
RED.nodes.createNode(node, config);
|
||||||
node.name = config.name;
|
node.name = config.name;
|
||||||
node.address = config.address;
|
node.address = config.address;
|
||||||
node.securityCode = config.securityCode;
|
node.securityCode = node.credentials.securityCode;
|
||||||
node.identity = config.identity;
|
node.identity = node.credentials.identity;
|
||||||
node.psk = config.psk;
|
node.psk = node.credentials.psk;
|
||||||
if ((node.identity == null && node.psk != null) || (node.identity != null && node.psk == null)) {
|
if ((node.identity == null && node.psk != null) || (node.identity != null && node.psk == null)) {
|
||||||
RED.log.error("Must provide both identity and PSK or leave both blank to generate new credentials from security code.");
|
RED.log.error("Must provide both identity and PSK or leave both blank to generate new credentials from security code.");
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ module.exports = function (RED) {
|
||||||
for (let instanceId in _listeners) {
|
for (let instanceId in _listeners) {
|
||||||
if (_listeners[instanceId].hasOwnProperty(nodeId)) {
|
if (_listeners[instanceId].hasOwnProperty(nodeId)) {
|
||||||
delete _listeners[instanceId][nodeId];
|
delete _listeners[instanceId][nodeId];
|
||||||
RED.log.debug(`[Tradfri: ${nodeId}] unregistered event listeners`);
|
RED.log.info(`[Tradfri: ${nodeId}] unregistered event listeners`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -179,7 +179,13 @@ module.exports = function (RED) {
|
||||||
RED.log.debug(`[Tradfri: ${node.id}] Config was closed`);
|
RED.log.debug(`[Tradfri: ${node.id}] Config was closed`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
RED.nodes.registerType("tradfri-connection", TradfriConnectionNode);
|
RED.nodes.registerType("tradfri-connection", TradfriConnectionNode, {
|
||||||
|
credentials: {
|
||||||
|
securityCode: { type: "text" },
|
||||||
|
identity: { type: "text" },
|
||||||
|
psk: { type: "text" }
|
||||||
|
}
|
||||||
|
});
|
||||||
function TradfriNode(config) {
|
function TradfriNode(config) {
|
||||||
var node = this;
|
var node = this;
|
||||||
RED.nodes.createNode(node, config);
|
RED.nodes.createNode(node, config);
|
||||||
|
@ -189,6 +195,9 @@ module.exports = function (RED) {
|
||||||
node.observe = config.observe;
|
node.observe = config.observe;
|
||||||
var _config = RED.nodes.getNode(config.connection);
|
var _config = RED.nodes.getNode(config.connection);
|
||||||
var _prev = {};
|
var _prev = {};
|
||||||
|
var _send = (payload) => {
|
||||||
|
node.send({ topic: "tradfri", payload: payload });
|
||||||
|
};
|
||||||
var _getPayload = (accessory) => {
|
var _getPayload = (accessory) => {
|
||||||
let light = lightFromAccessory(accessory);
|
let light = lightFromAccessory(accessory);
|
||||||
light['prev'] = Object.assign({}, _prev);
|
light['prev'] = Object.assign({}, _prev);
|
||||||
|
@ -197,7 +206,7 @@ module.exports = function (RED) {
|
||||||
var _deviceUpdated = (accessory) => {
|
var _deviceUpdated = (accessory) => {
|
||||||
let ret = _getPayload(accessory);
|
let ret = _getPayload(accessory);
|
||||||
_prev = lightFromAccessory(accessory);
|
_prev = lightFromAccessory(accessory);
|
||||||
node.send({ payload: { light: ret } });
|
_send(ret);
|
||||||
RED.log.trace(`[Tradfri: ${node.id}] recieved update for '${accessory.name}' (${accessory.instanceId})`);
|
RED.log.trace(`[Tradfri: ${node.id}] recieved update for '${accessory.name}' (${accessory.instanceId})`);
|
||||||
};
|
};
|
||||||
var _getTargetId = (msg) => {
|
var _getTargetId = (msg) => {
|
||||||
|
@ -215,24 +224,20 @@ module.exports = function (RED) {
|
||||||
throw new Error('No valid target device');
|
throw new Error('No valid target device');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var _handleDirectStatus = (msg) => __awaiter(this, void 0, void 0, function* () {
|
var _handleDirectStatus = () => __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
let client = yield _config.getClient();
|
let client = yield _config.getClient();
|
||||||
let res = yield client.request('15001/' + node.deviceId, 'get');
|
let res = yield client.request('15001/' + node.deviceId, 'get');
|
||||||
msg.payload = res;
|
_send(res);
|
||||||
node.send(msg);
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
msg.payload = e;
|
_send(e);
|
||||||
node.send(msg);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var _handleStatus = (msg) => __awaiter(this, void 0, void 0, function* () {
|
var _handleStatus = () => __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
let accessory = yield _config.getLight(node.deviceId);
|
let accessory = yield _config.getLight(node.deviceId);
|
||||||
msg.payload.light = _getPayload(accessory);
|
_send(_getPayload(accessory));
|
||||||
delete msg.payload.status;
|
|
||||||
node.send(msg);
|
|
||||||
RED.log.trace(`[Tradfri: ${node.id}] Status request successful`);
|
RED.log.trace(`[Tradfri: ${node.id}] Status request successful`);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
@ -290,10 +295,10 @@ module.exports = function (RED) {
|
||||||
let isDirect = msg.payload.hasOwnProperty('direct');
|
let isDirect = msg.payload.hasOwnProperty('direct');
|
||||||
let isStatus = msg.payload.hasOwnProperty('status');
|
let isStatus = msg.payload.hasOwnProperty('status');
|
||||||
if (isDirect && isStatus) {
|
if (isDirect && isStatus) {
|
||||||
_handleDirectStatus(msg);
|
_handleDirectStatus();
|
||||||
}
|
}
|
||||||
else if (isStatus) {
|
else if (isStatus) {
|
||||||
_handleStatus(msg);
|
_handleStatus();
|
||||||
}
|
}
|
||||||
else if (isDirect) {
|
else if (isDirect) {
|
||||||
_handleDirectLightOp(msg.payload);
|
_handleDirectLightOp(msg.payload);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "node-red-contrib-node-tradfri",
|
"name": "node-red-contrib-node-tradfri",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"description": "Node-RED node to utilize IKEA Trådfri devices. Fully implemented in Node.js.",
|
"description": "Node-RED node to utilize IKEA Trådfri devices. Fully implemented in Node.js.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
<!-- ======= CONNECTION ========= -->
|
<!-- Config Node -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
RED.nodes.registerType('tradfri-connection',{
|
RED.nodes.registerType('tradfri-connection',{
|
||||||
category: 'config',
|
category: 'config',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: { value:"" },
|
|
||||||
address: { value:"", required:true },
|
address: { value:"", required:true },
|
||||||
securityCode: { value:"" },
|
name: { value:"" }
|
||||||
identity: { value:"" },
|
},
|
||||||
psk: { value:"" },
|
credentials: {
|
||||||
|
securityCode: { type:"text" },
|
||||||
|
identity: { type:"text" },
|
||||||
|
psk: { type:"text" }
|
||||||
},
|
},
|
||||||
label: function() {
|
label: function() {
|
||||||
return this.name || "tradfri@" + this.address;
|
return this.name || "tradfri@" + this.address;
|
||||||
|
@ -17,28 +19,37 @@
|
||||||
|
|
||||||
<script type="text/x-red" data-template-name="tradfri-connection">
|
<script type="text/x-red" data-template-name="tradfri-connection">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-name"><i class="icon-bookmark"></i> Name</label>
|
<label for="node-config-input-address"><i class="fa fa-globe"></i> Address</label>
|
||||||
<input type="text" id="node-config-input-name">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-config-input-address"><i class="icon-bookmark"></i> Address</label>
|
|
||||||
<input type="text" id="node-config-input-address">
|
<input type="text" id="node-config-input-address">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-securityCode"><i class="icon-bookmark"></i> Security Code</label>
|
<label for="node-config-input-securityCode"><i class="fa fa-gears"></i> Security Code</label>
|
||||||
<input type="text" id="node-config-input-securityCode">
|
<input type="text" id="node-config-input-securityCode">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-identity"><i class="icon-bookmark"></i> Identity</label>
|
<label for="node-config-input-identity"><i class="fa fa-address-card-o"></i> Identity</label>
|
||||||
<input type="text" id="node-config-input-identity">
|
<input type="text" id="node-config-input-identity">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-psk"><i class="icon-bookmark"></i> Pre-shared key</label>
|
<label for="node-config-input-psk"><i class="fa fa-lock"></i> Pre-shared key</label>
|
||||||
<input type="text" id="node-config-input-psk">
|
<input type="text" id="node-config-input-psk">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-config-input-name">
|
||||||
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- ======= THREADFREE ========= -->
|
<script type="text/x-red" data-help-name="tradfri-connection">
|
||||||
|
<ul>
|
||||||
|
<li><i class="fa fa-globe"></i> <b>Address:</b> The address to your gateway.</li>
|
||||||
|
<li><i class="fa fa-gears"></i> <b>Security code:</b> The security code on the backside of your gateway. You only need to enter this if you <em>don't</em> have an identiy and PSK. In that case identity and PSK will be generated for you using the security key.</li>
|
||||||
|
<li><i class="fa fa-address-card-o"></i> <b>Address:</b> The identiy used to access the gateway. Used together with a PSK.</li>
|
||||||
|
<li><i class="fa fa-lock"></i> <b>Pre-shared key:</b> The passkey used to access the gateway. Used together with an identity.</li>
|
||||||
|
</ul>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--- I/O Node -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var updateDevices = (currentDeviceId) => {
|
var updateDevices = (currentDeviceId) => {
|
||||||
let configNodeId = $('#node-input-connection').find(":selected").val();
|
let configNodeId = $('#node-input-connection').find(":selected").val();
|
||||||
|
@ -61,7 +72,7 @@
|
||||||
|
|
||||||
RED.nodes.registerType('tradfri',{
|
RED.nodes.registerType('tradfri',{
|
||||||
category: 'function',
|
category: 'function',
|
||||||
color: '#84E87A',
|
color: '#9FE597',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
deviceId: {value: "", required:true, validate:RED.validators.number()},
|
deviceId: {value: "", required:true, validate:RED.validators.number()},
|
||||||
|
@ -69,9 +80,10 @@
|
||||||
connection: {value:"", type:"tradfri-connection"},
|
connection: {value:"", type:"tradfri-connection"},
|
||||||
observe: { value:true, required: true },
|
observe: { value:true, required: true },
|
||||||
},
|
},
|
||||||
|
align: 'right',
|
||||||
inputs:1,
|
inputs:1,
|
||||||
outputs:1,
|
outputs:1,
|
||||||
icon: "light.png",
|
icon: 'light.png',
|
||||||
label: function() {
|
label: function() {
|
||||||
return this.deviceName || "tradfri";
|
return this.deviceName || "tradfri";
|
||||||
},
|
},
|
||||||
|
@ -96,11 +108,7 @@
|
||||||
|
|
||||||
<script type="text/x-red" data-template-name="tradfri">
|
<script type="text/x-red" data-template-name="tradfri">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
<label for="node-input-connection"><i class="fa fa-cog"></i> Connection</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-connection"><i class="fa fa-bookmark"></i> Connection</label>
|
|
||||||
<input type="text" id="node-input-connection" placeholder="Connection">
|
<input type="text" id="node-input-connection" placeholder="Connection">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
|
@ -120,27 +128,50 @@
|
||||||
<input type="checkbox" id="node-input-observe" style="display: inline-block; width: auto; vertical-align: top;">
|
<input type="checkbox" id="node-input-observe" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
<label for="node-input-observe" style="width: 70%;" >Observe device?</label>
|
<label for="node-input-observe" style="width: 70%;" >Observe device?</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="tradfri">
|
<script type="text/x-red" data-help-name="tradfri">
|
||||||
<p>Interface for IKEA Tradfri devices</p>
|
<p>Interface for IKEA Tradfri devices</p>
|
||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt> payload <span class="property-type"> string </span> </dt>
|
<dt> payload <span class="property-type"> string | object</span> </dt>
|
||||||
<dd> A single command can be sent as a string to the node. <dd>
|
<dd> The payload can either be a single command to the node (such as a status update request) sent as a string or an object with one or more commands targeting the light.</dd>
|
||||||
<dt> payload <span class="property-type"> object </span> </dt>
|
|
||||||
<dd> An object with one or more commands targeting the light. </dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Outputs</h3>
|
<h3>Outputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt> payload.light <span class="property-type"> object </span></dt>
|
<dt> payload <span class="property-type"> object </span></dt>
|
||||||
<dd> The status of the light. </dd>
|
<dd> The status of the light. </dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h3>Details</h3>
|
<h3>Details</h3>
|
||||||
The tradfri node acts as both input and output for a IKEA Tradfri lighbulb.
|
The tradfri node acts as both input and output for a IKEA Tradfri lighbulb.
|
||||||
|
|
||||||
If the node is set to observe it will send a message with the lights current properties as payload every time the light is updated:
|
<h2>Controlling the node</h2>
|
||||||
|
Nodes can be programmatically controlled by sending a message with <code>msg.payload</code> set to one of the following strings:
|
||||||
|
<ul>
|
||||||
|
<li><code>"status"</code> The node will output the current status of its target light.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Controlling the lights</h2>
|
||||||
|
Lights can be controlled by sending an objet with one or more of the following properties as <code>msg.payload</code> to the node.
|
||||||
|
<ul>
|
||||||
|
<!-- <li><code>id</code><code>number</code> The id of the light <li>
|
||||||
|
<li><code>name</code><code>string</code> The given name of the light <li> -->
|
||||||
|
<li><code>on</code><code>boolean</code><li> Turn the light on or off.</li>
|
||||||
|
<li><code>brightness</code><code>number</code> The brightness of the light [0,100]</li>
|
||||||
|
<li><code>colorTemperature</code><code>number</code> The color temperature of the light [0,100]</li>
|
||||||
|
<li><code>color</code><code>string</code> Sets the color of the light. For WS-bulbs, <code>F5FAF6</code>, <code>F1E0B5</code> and <code>EFD275</code> will set the light to the default cold, normal and warm temperatures respectively.</li>
|
||||||
|
<li><code>transition</code><code>number</code> The default transition time for operations. Will only work for single operation commands and not for on/off. Defaults to 0. </li>
|
||||||
|
<li><code>hue</code><code>number</code> Sets the hue of the light. Only for CWS. [0,365] (UNTESTED)</li>
|
||||||
|
<li><code>saturation</code><code>number</code> Sets the saturation of the light. Only for CWS. [0,100] (UNTESTED)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Observing</h2>
|
||||||
|
If the node is set to observe it will send a message with the lights current properties as payload every time the light is updated:
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>id</code><code>number</code> The id of the light </li>
|
<li><code>id</code><code>number</code> The id of the light </li>
|
||||||
<li><code>name</code><code>string</code> The given name of the light </li>
|
<li><code>name</code><code>string</code> The given name of the light </li>
|
||||||
|
@ -160,24 +191,4 @@
|
||||||
<li><code>power</code><code>number</code> The type of power source powering the light. Will most likely always be 1.</li>
|
<li><code>power</code><code>number</code> The type of power source powering the light. Will most likely always be 1.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Controlling the node</h2>
|
|
||||||
The can be programmatically controlled by sending a message with <code>msg.payload</code> set to one of the following:
|
|
||||||
<ul>
|
|
||||||
<li><code>status</code> The node will output the current status of its target light.
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>Controlling the lights</h2>
|
|
||||||
Lights can be controlled by sending an objet with one or more of the following properties as <code>msg.payload</code> to the node.
|
|
||||||
<ul>
|
|
||||||
<!-- <li><code>id</code><code>number</code> The id of the light <li>
|
|
||||||
<li><code>name</code><code>string</code> The given name of the light <li> -->
|
|
||||||
<li><code>on</code><code>boolean</code><li> Turn the light on or off.</li>
|
|
||||||
<li><code>brightness</code><code>number</code> The brightness of the light [0,100]</li>
|
|
||||||
<li><code>colorTemperature</code><code>number</code> The color temperature of the light [0,100]</li>
|
|
||||||
<li><code>color</code><code>string</code> Sets the color of the light. For WS-bulbs, <code>F5FAF6</code>, <code>F1E0B5</code> and <code>EFD275</code> will set the light to the default cold, normal and warm temperatures respectively.</li>
|
|
||||||
<li><code>transition</code><code>number</code> The default transition time for operations. Will only work for single operation commands and not for on/off. Defaults to 0. </li>
|
|
||||||
<li><code>hue</code><code>number</code> Sets the hue of the light. Only for CWS. [0,365] (UNTESTED)</li>
|
|
||||||
<li><code>saturation</code><code>number</code> Sets the saturation of the light. Only for CWS. [0,100] (UNTESTED)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -55,9 +55,9 @@ module.exports = function(RED) {
|
||||||
RED.nodes.createNode(node, config);
|
RED.nodes.createNode(node, config);
|
||||||
node.name = config.name;
|
node.name = config.name;
|
||||||
node.address = config.address;
|
node.address = config.address;
|
||||||
node.securityCode = config.securityCode;
|
node.securityCode = node.credentials.securityCode;
|
||||||
node.identity = config.identity;
|
node.identity = node.credentials.identity;
|
||||||
node.psk = config.psk;
|
node.psk = node.credentials.psk;
|
||||||
|
|
||||||
if ((node.identity == null && node.psk != null) || (node.identity != null && node.psk == null)) {
|
if ((node.identity == null && node.psk != null) || (node.identity != null && node.psk == null)) {
|
||||||
RED.log.error("Must provide both identity and PSK or leave both blank to generate new credentials from security code.");
|
RED.log.error("Must provide both identity and PSK or leave both blank to generate new credentials from security code.");
|
||||||
|
@ -171,7 +171,7 @@ module.exports = function(RED) {
|
||||||
for (let instanceId in _listeners) {
|
for (let instanceId in _listeners) {
|
||||||
if (_listeners[instanceId].hasOwnProperty(nodeId)) {
|
if (_listeners[instanceId].hasOwnProperty(nodeId)) {
|
||||||
delete _listeners[instanceId][nodeId];
|
delete _listeners[instanceId][nodeId];
|
||||||
RED.log.debug(`[Tradfri: ${nodeId}] unregistered event listeners`);
|
RED.log.info(`[Tradfri: ${nodeId}] unregistered event listeners`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,13 @@ module.exports = function(RED) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RED.nodes.registerType("tradfri-connection", TradfriConnectionNode);
|
RED.nodes.registerType("tradfri-connection", TradfriConnectionNode, {
|
||||||
|
credentials: {
|
||||||
|
securityCode: {type:"text"},
|
||||||
|
identity: {type:"text"},
|
||||||
|
psk: {type:"text"}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function TradfriNode(config) {
|
function TradfriNode(config) {
|
||||||
var node = this;
|
var node = this;
|
||||||
|
@ -196,6 +202,10 @@ module.exports = function(RED) {
|
||||||
var _config = RED.nodes.getNode(config.connection);
|
var _config = RED.nodes.getNode(config.connection);
|
||||||
var _prev = {};
|
var _prev = {};
|
||||||
|
|
||||||
|
var _send = (payload: any) => {
|
||||||
|
node.send({topic:"tradfri", payload:payload});
|
||||||
|
}
|
||||||
|
|
||||||
var _getPayload = (accessory: tradfri.Accessory) => {
|
var _getPayload = (accessory: tradfri.Accessory) => {
|
||||||
let light = lightFromAccessory(accessory);
|
let light = lightFromAccessory(accessory);
|
||||||
light['prev'] = Object.assign({}, _prev);
|
light['prev'] = Object.assign({}, _prev);
|
||||||
|
@ -205,7 +215,7 @@ module.exports = function(RED) {
|
||||||
var _deviceUpdated = (accessory: tradfri.Accessory) => {
|
var _deviceUpdated = (accessory: tradfri.Accessory) => {
|
||||||
let ret = _getPayload(accessory);
|
let ret = _getPayload(accessory);
|
||||||
_prev = lightFromAccessory(accessory);
|
_prev = lightFromAccessory(accessory);
|
||||||
node.send({payload: {light: ret}});
|
_send(ret);
|
||||||
RED.log.trace(`[Tradfri: ${node.id}] recieved update for '${accessory.name}' (${accessory.instanceId})`);
|
RED.log.trace(`[Tradfri: ${node.id}] recieved update for '${accessory.name}' (${accessory.instanceId})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,24 +232,20 @@ module.exports = function(RED) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _handleDirectStatus = async (msg: any) => {
|
var _handleDirectStatus = async () => {
|
||||||
try {
|
try {
|
||||||
let client = await _config.getClient();
|
let client = await _config.getClient();
|
||||||
let res = await client.request('15001/' + node.deviceId, 'get');
|
let res = await client.request('15001/' + node.deviceId, 'get');
|
||||||
msg.payload = res;
|
_send(res);
|
||||||
node.send(msg);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
msg.payload = e;
|
_send(e);
|
||||||
node.send(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _handleStatus = async (msg: any) => {
|
var _handleStatus = async () => {
|
||||||
try {
|
try {
|
||||||
let accessory = await _config.getLight(node.deviceId);
|
let accessory = await _config.getLight(node.deviceId);
|
||||||
msg.payload.light = _getPayload(accessory);
|
_send(_getPayload(accessory));
|
||||||
delete msg.payload.status;
|
|
||||||
node.send(msg);
|
|
||||||
RED.log.trace(`[Tradfri: ${node.id}] Status request successful`);
|
RED.log.trace(`[Tradfri: ${node.id}] Status request successful`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
RED.log.info(`[Tradfri: ${node.id}] Status request unsuccessful, '${e.toString()}'`);
|
RED.log.info(`[Tradfri: ${node.id}] Status request unsuccessful, '${e.toString()}'`);
|
||||||
|
@ -304,9 +310,9 @@ module.exports = function(RED) {
|
||||||
let isStatus = msg.payload.hasOwnProperty('status');
|
let isStatus = msg.payload.hasOwnProperty('status');
|
||||||
|
|
||||||
if (isDirect && isStatus) {
|
if (isDirect && isStatus) {
|
||||||
_handleDirectStatus(msg);
|
_handleDirectStatus();
|
||||||
} else if (isStatus) {
|
} else if (isStatus) {
|
||||||
_handleStatus(msg);
|
_handleStatus();
|
||||||
} else if (isDirect) {
|
} else if (isDirect) {
|
||||||
_handleDirectLightOp(msg.payload);
|
_handleDirectLightOp(msg.payload);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue