UNPKG

@fetchbot/node-red-contrib-ikea-home-smart

Version:
483 lines (432 loc) 23.1 kB
<!-- Config Node --> <script type="text/javascript"> RED.nodes.registerType('ikea-connection',{ category: 'config', defaults: { address: { value:"", required:true }, name: { value:"" } }, credentials: { securityCode: { type:"text" }, identity: { type:"text" }, psk: { type:"text" } }, label: function() { return this.name || "ikea@" + this.address; } }); </script> <script type="text/x-red" data-template-name="ikea-connection"> <div class="form-row"> <label for="node-config-input-address"><i class="fa fa-globe"></i> Address</label> <input type="text" id="node-config-input-address"> </div> <div class="form-row"> <label for="node-config-input-securityCode"><i class="fa fa-gears"></i> Security Code</label> <input type="text" id="node-config-input-securityCode"> </div> <div class="form-row"> <label for="node-config-input-identity"><i class="fa fa-address-card-o"></i> Identity</label> <input type="text" id="node-config-input-identity"> </div> <div class="form-row"> <label for="node-config-input-psk"><i class="fa fa-lock"></i> Pre-shared key</label> <input type="text" id="node-config-input-psk"> </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 type="text/x-red" data-help-name="ikea-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>Identity:</b> The identity 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> <!--- Homesmart Node --> <script type="text/javascript"> var updateDevices = (currentDeviceId) => { let configNodeId = $('#node-input-connection').find(":selected").val(); if (configNodeId == null || configNodeId === '_ADD_') { return; } let deviceType = $('#node-input-deviceType').find(":selected").val(); if (deviceType == null || deviceType === '_ADD_') { $('#node-input-deviceId').find('option').not(':first').remove(); $('#node-input-deviceId-icon').attr('class', 'fa fa-home'); $('#deviceObserve').hide(); $('#sceneId').hide(); return; } $.get('ikea/' + deviceType, {nodeId: configNodeId}, function(resp) { let devices = JSON.parse(resp); $('#node-input-deviceId').find('option').not(':first').remove(); if (!Array.isArray(devices) || devices.length <= 0) { return; } //$('#node-input-deviceId').find('option').not(':first').remove(); $.each(devices, function(i, device) { let opt = {}; opt.value = device.id; opt.text = device.name; if (device.id === currentDeviceId) { opt.selected = "selected"; } $('#node-input-deviceId').append($('<option>', opt)); }); }); if (deviceType === 'ikea-groups') { $.get('ikea/ikea-scenes', {nodeId: configNodeId}, function(resp) { let scenes = JSON.parse(resp); if (!Array.isArray(scenes) || scenes.length <= 0) { return; } $('#node-option-scene').find('tr').not(':first').remove(); $.each(scenes, function(i, scene) { if (scene.group === $('#node-input-deviceId').find(":selected").val()) { $('#node-option-scene').append('<tr><td>' + scene.name + '</td><td><code>{"sceneId": ' + scene.id + '}</code></td></tr>'); } }); }); } switch (deviceType) { case "ikea-blinds": $('#node-input-deviceId-icon').attr('class', 'fa fa-window-maximize'); $('#deviceObserve').show(); $('#sceneId').hide(); break; case "ikea-lights": $('#node-input-deviceId-icon').attr('class', 'fa fa-lightbulb-o'); $('#deviceObserve').show(); $('#sceneId').hide(); break; case "ikea-plugs": $('#node-input-deviceId-icon').attr('class', 'fa fa-plug'); $('#deviceObserve').show(); $('#sceneId').hide(); break; case "ikea-sensors": $('#node-input-deviceId-icon').attr('class', 'fa fa-bullseye'); $('#deviceObserve').hide(); $('#sceneId').hide(); break; case "ikea-remotes": $('#node-input-deviceId-icon').attr('class', 'fa fa-power-off'); $('#deviceObserve').hide(); $('#sceneId').hide(); break; case "ikea-groups": $('#node-input-deviceId-icon').attr('class', 'fa fa-sitemap'); $('#deviceObserve').show(); $('#sceneId').show(); break; default: break; } }; RED.nodes.registerType('ikea-homesmart', { category: 'homesmart', color: '#FFDA1A', defaults: { name: { value: "" }, deviceId: { value: "", required: true, validate: RED.validators.number() }, deviceName: { value: "" }, deviceType: { value: "" }, deviceIcon: { value: "" }, connection: { value: "", type: "ikea-connection" }, observe: { value: false, required: true } }, align: 'left', inputs: 1, outputs: 1, icon: function() { return this.deviceIcon || 'font-awesome/fa-home'; }, label: function() { if (this.name !== "") { return this.name; } else { return this.deviceName || "ikea-homesmart"; } }, oneditprepare: function() { var node = this; $('#deviceObserve').hide(); $('#sceneId').hide(); $('#node-input-connection').change(function(){ updateDevices(node.deviceId); }); $('#node-input-deviceType').change(function(){ updateDevices(node.deviceId); }); $('#ikea-deviceId-refresh-spinner').click(function(){ updateDevices(node.deviceId); }); $(document).ready(function() { $('#node-input-msgPassthrough').prop('checked', node.observe); }); }, oneditsave: function() { this.deviceType = $('#node-input-deviceType').find(":selected").text(); this.deviceName = $('#node-input-deviceId').find(":selected").text(); this.deviceIcon = 'font-awesome/' + $('#node-input-deviceId-icon').attr('class').substring(3); } }); </script> <style> th { text-align: left; } </style> <script type="text/x-red" data-template-name="ikea-homesmart"> <div class="form-row" id="deviceConnection"> <label for="node-input-connection"><i class="fa fa-cog"></i> Connection</label> <input type="text" id="node-input-connection" placeholder="Connection"> </div> <div class="form-row" id="deviceType"> <label for="node-input-deviceType"><i class="fa fa-home"></i> Device Type</label> <div style="display: inline-block; position: relative; width: 70%; height: 20px;"> <div style="position: absolute; left: 0px; right: 40px;"> <select id="node-input-deviceType" style="width: 100%"> <option value="_ADD_" selected>None</option> <option value="ikea-blinds">Blind</option> <option value="ikea-lights">Light</option> <option value="ikea-plugs">Plug</option> <option value="ikea-sensors">Sensor</option> <option value="ikea-remotes">Remote</option> <option value="ikea-groups">Group</option> </select> </div> </div> </div> <div class="form-row" id="deviceId"> <label for="node-input-deviceId"><i id="node-input-deviceId-icon" class="fa fa-home"></i> Device</label> <div style="display: inline-block; position: relative; width: 70%; height: 20px;"> <div style="position: absolute; left: 0px; right: 40px;"> <select id="node-input-deviceId" style="width: 100%"> <option selected>None</option> </select> </div> <a id="node-input-lookup-connection" class="editor-button" style="position: absolute; right: 0px; top: 0px;"><i id="ikea-deviceId-refresh-spinner" class="fa fa-refresh"></i></a> </div> </div> <div class="form-row" id="deviceObserve"> <label>&nbsp;</label> <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> </div> <div class="form-row" id="deviceName"> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="Name"> </div> <div class="form-row" id="sceneId"> <label for="node-option-scene"><i class="fa fa-picture-o"></i> Available Scenes</label> <div style="display: inline-block; position: relative; width: 70%; height: 20px;"> <div style="position: absolute; left: 0px; right: 40px;"> <table id="node-option-scene" style="width:100%"> <tr> <th>Scene</th> <th>command</th> </tr> </table> </div> </div> </div> </script> <script type="text/x-red" data-help-name="ikea-homesmart"> <p>Interface for IKEA smart home devices</p> <h3>Inputs</h3> <dl class="message-properties"> <dt>payload<span class="property-type">string | object</span></dt> <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 blind.</dd> </dl> <h3>Outputs</h3> <dl class="message-properties"> <dt>payload<span class="property-type">object</span></dt> <dd>The status of the node.</dd> <dt>topic<span class="property-type">string</span></dt> </dl> <h3>Details</h3> The ikea-homesmart node can be set to control a blind, light, plug or group. 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 accessory. </ul> <h3>Controlling the blinds</h3> A blind's position can be controled by sending an object with the following property as <code>msg.payload</code> to the node. <ul> <li><code>"position"</code>: number - The position in percent [0..100%].</li> <li><code>"trigger"</code>: number - A trigger event to stop a moving blind [0.0].</li> </ul> <div><pre><code class="language-json">{ "position": number } { "trigger": number }</code></pre></div> <h3>Controlling the lights</h3> A light represents a single lightbulb and has several properties describing its state. The supported properties depend on the spectrum of the lightbulb. <strong>All</strong> of them support the most basic properties, which can be controlled by sending an object with one or more of the following properties as <code>msg.payload</code> to the node. <ul> <li><code>"dimmer"</code>: number - The brightness in percent [0..100%].</li> <li><code>"onOff"</code>: boolean - If the lightbulb is on (true) or off (false)</li> <li><code>"transitionTime"</code>: number - The duration of state changes in seconds. Default 0.5s, not supported for on/off.</li> </ul> <strong>White spectrum</strong> lightbulbs also support <ul> <li><code>"colorTemperature"</code>: number - The color temperature in percent, where 0% equals cold white and 100% equals warm white.</li> </ul> <strong>RGB</strong> lightbulbs have the following properties: <ul> <li><code>"color"</code>: string - The 6 digit hex number representing the lightbulb's color. Don't use any prefixes like "#", only the hex number itself!</li> <li><code>"hue"</code>: number - The color's hue [0..360°].</li> <li><code>"saturation"</code>: number - The color's saturation [0..100%].</li> </ul> <div><pre><code class="language-json">{ "onOff": boolean, "dimmer": number, "transitionTime": number, "colorTemperature": number, "color": string, "hue": number, "saturation": number }</code></pre></div> <h3>Controlling the plugs</h3> A plug represents a single outlet plug and has several properties describing its state. And one property which can control the plugs by sending an object with the following property as <code>msg.payload</code> to the node. <ul> <li><code>"onOff"</code>: boolean - If the plug is on (true) or off (false).</li> </ul> <div><pre><code class="language-json">{ "onOff": boolean }</code></pre></div> <h3>Controlling the groups</h3> A group contains several devices, usually a remote control and either lightbulbs, plugs or blinds. To control the group send the following properties as <code>msg.payload</code> to the node: <br> <strong>For a group of lights</strong> <ul> <li><code>"dimmer"</code>: number - The brightness in percent [0..100%].</li> <li><code>"onOff"</code>: boolean - If the lightbulb is on (true) or off (false)</li> <li><code>"transitionTime"</code>: number - The duration of state changes in seconds. Default 0.5s, not supported for on/off.</li> </ul> Additionally, this property is also supported: <ul> <li><code>"sceneId"</code>: number - Set this to the instanceId of a scene (or "mood" as IKEA calls them), to activate it.</li> </ul> <div><pre><code class="language-json">{ "onOff": boolean, "dimmer": number, "transitionTime": number } { "sceneId": number }</code></pre></div> <strong>For a group of blinds</strong> <ul> <li><code>"position"</code>: number - The position in percent [0..100%].</li> <li><code>"trigger"</code>: number - A trigger event to stop a group of moving blinds [0.0].</li> </ul> Additionally, this property is also supported: <ul> <li><code>"sceneId"</code>: number - Set this to the instanceId of a scene (or "mood" as IKEA calls them), to activate it.</li> </ul> <div><pre><code class="language-json">{ "position": number } { "trigger": number } { "sceneId": number }</code></pre></div> <strong>For a group of plugs</strong> <ul> <li><code>"onOff"</code>: boolean - If the plug is on (true) or off (false)</li> </ul> Additionally, this property is also supported: <ul> <li><code>"sceneId"</code>: number - Set this to the instanceId of a scene (or "mood" as IKEA calls them), to activate it.</li> </ul> <div><pre><code class="language-json">{ "onOff": boolean } { "sceneId": number }</code></pre></div> <h3>Observing</h3> If the node is set to observe it will send a message with the accessories current properties as <code>msg.payload</code> every time the node is updated or a status request <code>"status"</code> is sent. <br><br> <ul> <li><code>"name"</code>: string - The name of this accessory.</li> <li><code>"createdAt"</code>: number - The unix timestamp of the creation of the device.</li> <li><code>"instanceId"</code>: number - The ID under which the accessory is known to the gateway.</li> <li><code>"type"</code>: number - The type of the accessory.</li> <ul> <li>remote (0) - A "normal" remote</li> <li>slaveRemote (1) - A remote which has been paired with another remote. You can find details here on how to achieve this configuration.</li> <li>lightbulb (2) - A lightbulb</li> <li>plug (3) - A smart plug</li> <li>motionSensor (4) - A motion sensor</li> <li>signalRepeater (6) - A signal repeater</li> <li>blind (7) - A blind</li> </ul> <li><code>"alive"</code>: boolean - Whether the gateway considers this device as alive.</li> <li><code>"lastSeen"</code>: number - The unix timestamp of the last communication with the gateway.</li> <li><code>"otaUpdateState"</code>: number - Unknown. Might be a boolean</li> <li><code>"deviceInfo"</code>: object - Some additional information about the device.</li> <ul> <li><code>"firmwareVersion"</code>: string - The firmware version of the device.</li> <li><code>"manufacturer"</code>: string - The device manufacturer.</li> <li><code>"modelNumber"</code>: string - The name/type of the device.</li> <li><code>"power"</code>: number - How the device is powered.</li> <ul> <li>Unknown (0)</li> <li>InternalBattery (1)</li> <li>ExternalBattery (2)</li> <li>Battery (3) - Although not in the specs, this is apparently used by the remote</li> <li>PowerOverEthernet (4)</li> <li>USB (5)</li> <li>AC_Power (6)</li> <li>Solar (7)</li> </ul> <li><code>"serialNumber"</code>: string - Not used currently. Always ""</li> <li><code>"battery"</code>: number - The battery percentage of a device. Only present if the device is battery-powered.</li> </ul> <li><code>"blindList"</code>: array - An array of all blinds belonging to this accessory.</li> <ul> <li><code>"position"</code>: number - The position in percent [0..100%].</li> </ul> <li><code>"lightList"</code>: array - An array of all lights belonging to this accessory.</li> <ul> <li><code>"onOff"</code>: boolean - If the lightbulb is on (true) or off (false)</li> <li><code>"dimmer"</code>: number - The brightness in percent [0..100%].</li> <li><code>"transitionTime"</code>: number - The duration of state changes in seconds. Default 0.5s, not supported for on/off.</li> <li><code>"colorTemperature"</code>: number - The color temperature in percent, where 0% equals cold white and 100% equals warm white.</li> <li><code>"color"</code>: string - The 6 digit hex number representing the lightbulb's color.</li> <li><code>"colorX"</code>: number - The x component of the xy-color</li> <li><code>"colorY"</code>: number - The y component of the xy-color</li> <li><code>"hue"</code>: number - The color's hue [0..360°].</li> <li><code>"saturation"</code>: number - The color's saturation [0..100%].</li> </ul> <li><code>"plugList"</code>: array - An array of all plugs belonging to this accessory.</li> <ul> <li><code>"onOff"</code>: boolean - If the plug is on (true) or off (false).</li> <li><code>"isSwitchable"</code>: boolean - Whether the plug supports on/off (always true).</li> <li><code>"isDimmable"</code>: boolean - Whether the plug supports setting the dimmer value (always false for now).</li> </ul> <li><code>"sensorList"</code>: array - An array of all sensors belonging to this accessory.</li> <ul> <li><code>"name"</code>: string - Currently not supported.</li> <li><code>"createdAt"</code>: number - Currently not supported.</li> <li><code>"instanceId"</code>: number - Currently not supported.</li> <li><code>"appType"</code>: string - Currently not supported.</li> <li><code>"sensorType"</code>: string - Currently not supported.</li> <li><code>"minMeasuredValue"</code>: number - Currently not supported.</li> <li><code>"maxMeasuredValue"</code>: number - Currently not supported.</li> <li><code>"minRangeValue"</code>: number - Currently not supported.</li> <li><code>"maxRangeValue"</code>: number - Currently not supported.</li> <li><code>"resetMinMaxMeasureValue"</code>: boolean - Currently not supported.</li> <li><code>"sensorValue"</code>: number - Currently not supported.</li> <li><code>"unit"</code>: string - Currently not supported.</li> </ul> <li><code>"switchList"</code>: array - An array of all remotes belonging to this accessory.</li> <ul> <li><code>"name"</code>: string - Currently not supported.</li> <li><code>"createdAt"</code>: number - Currently not supported.</li> <li><code>"instanceId"</code>: number - Currently not supported.</li> </ul> </ul> Currently observing the control of a group is not possible, due to the gateway only reporting changes to every single device. If a group is renamed, a device removed or added to it, a scene redefined or manually a status request sent to the node, it will respond with a <code>msg.payload</code> containing the groups current properties. <br><br> <ul> <li><code>"name"</code>: string - The name of this group.</li> <li><code>"createdAt"</code>: number - The unix timestamp of the creation of the group.</li> <li><code>"instanceId"</code>: number - The ID under which the group is known to the gateway.</li> <li><code>"onOff"</code>: boolean - If the group is on (true) or off (false) <li><code>"dimmer</code>: number - The brightness in percent [0..100%]. <li><code>"deviceIDs</code>: object - An array of all instanceIds of the devices in this group.</li> <li><code>"sceneId</code>: number - the instanceId of the current scene (or "mood" as IKEA calls them).</li> <li><code>"groupType"</code>: number - The type of the group.</li> </ul> </script>