diff --git a/README.md b/README.md index 2be1e24..1c7d888 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,14 @@ The following devices are currently supported: * Button switch * Motion sensor * Power plug (zigbee) +* Power plug (wifi) ## Preperation To receive the gateway json messages on your network you need to enable the developer mode, aka LAN mode in the gateway. A UDP input node is needed to receive the json messages. An UDP output node to send command's to the gateway. +To control the Wifi-Plug, extensive use is made of the miio library created by [Andreas Holstenson](https://github.com/aholstenson/miio). Make sure to check his page for compatible devices. ## Install @@ -27,6 +29,8 @@ npm install node-red-contrib-xiaomi-devices From the Xiaomi configurator screen add your different devices by selecting the type of device and a readable description. The readable discription is used on the different edit screen of the nodes to easily select the device you associate to the node. +Note that the Wifi power plug is not configured through the configurator as it is not connected to the gateway. + The Xiaomi configurator screen with ease of use to configure your different devices. ![Xiaomi configurator in node-red](https://raw.githubusercontent.com/hrietman/node-red-contrib-xiaomi-devices/master/xiaomi-configurator.png) @@ -57,5 +61,6 @@ Here an example of how to use the different nodes. ## Roadmap -* Support for other devices like the smart-socket WiFi +* ~~Support for other devices like the smart-socket WiFi~~ Done! * Import (new) devices directly from the gateway + diff --git a/node-red-contrib-xiaomi-socket-wifi/icons/outlet-wifi-icon.png b/node-red-contrib-xiaomi-socket-wifi/icons/outlet-wifi-icon.png new file mode 100644 index 0000000..4da9524 Binary files /dev/null and b/node-red-contrib-xiaomi-socket-wifi/icons/outlet-wifi-icon.png differ diff --git a/node-red-contrib-xiaomi-socket-wifi/xiaomi-socket-wifi.html b/node-red-contrib-xiaomi-socket-wifi/xiaomi-socket-wifi.html new file mode 100644 index 0000000..fd5ad6b --- /dev/null +++ b/node-red-contrib-xiaomi-socket-wifi/xiaomi-socket-wifi.html @@ -0,0 +1,119 @@ + + + + + diff --git a/node-red-contrib-xiaomi-socket-wifi/xiaomi-socket-wifi.js b/node-red-contrib-xiaomi-socket-wifi/xiaomi-socket-wifi.js new file mode 100644 index 0000000..28b77df --- /dev/null +++ b/node-red-contrib-xiaomi-socket-wifi/xiaomi-socket-wifi.js @@ -0,0 +1,149 @@ +module.exports = function(RED) { + "use strict"; + var mustache = require("mustache"); + var crypto = require("crypto"); + var miio = require("miio"); + + function XiaomiPlugWifiNode(config) { + RED.nodes.createNode(this, config); + this.ip = config.ip; + this.output = config.output; + this.onmsg = config.onmsg; + this.offmsg = config.offmsg; + + var node = this; + var connectionState = "timeout"; + var plug = {}; + var retryTimer; + + node.status({fill:"yellow", shape:"dot", text:"connecting"}); + + miio.device({ address: node.ip }) + .then(function(result) { + if (result.type === "power-plug") { + plug = result; + node.status({fill:"green", shape:"dot", text:"connected"}); + connectionState = "connected"; + + setTimeout(function() { + if (result.power()['0']) { + setState("on"); + } else { + setState("off"); + } + }, 1500); + + watchdog(); + + plug.on('propertyChanged', function(e) { + if (e.property === "power") { + if (e.value['0']) { + setState("on"); + } else { + setState("off"); + } + } + }); + + } + }) + .catch(function(error) { + node.status({fill:"red", shape:"dot", text:"time out"}); + connectionState = "reconnecting"; + watchdog(); + }); + + node.on('input', function(msg) { + var payload = msg.payload; + + if (payload == 'on') { + if (connectionState === "connected") { + plug.setPower(true); + } + } + + if (payload == 'off') { + if (connectionState === "connected") { + plug.setPower(false); + } + } + + }); + + this.on('close', function(done) { + if (retryTimer) { + clearTimeout(retryTimer); + } + if (plug) { + plug.destroy(); + } + done(); + }); + + var setState = function(state) { + var status = null; + var info = {"payload": { + "id": plug.id, + "type": plug.type, + "model": plug.model, + "capabilities": plug.capabilities, + "address": plug.address, + "port": plug.port, + "power": plug.power() + }}; + + if (state === "on") { + node.status({fill:"green", shape:"dot", text:"on"}); + status = {"payload": mustache.render(node.onmsg, info.payload)} + } + if (state === "off") { + node.status({fill:"red", shape:"dot", text:"off"}); + status = {"payload": mustache.render(node.offmsg, info.payload)} + } + + if (node.output == 0) { + status = info; + } else if (node.output == "1") { + status = {"payload": state} + } else if (node.output == "2") { + // do nothing, just send status parsed with mustache + } + node.send([status]); + }; + + var watchdog = function() { + var interval = 10; + retryTimer = setInterval(function() { + if (interval == 0) { + miio.device({address: node.ip}) + .then(function (result) { + if (connectionState === "reconnecting") { + node.status({fill:"green", shape:"dot", text:"connected"}); + connectionState = "connected"; + + setTimeout(function() { + if (result.power()['0']) { + setState("on"); + } else { + setState("off"); + } + }, 1500); + } + }) + .catch(function (error) { + connectionState = "reconnecting"; + }) + interval = 10; + } else { + interval--; + if (connectionState === "reconnecting") { + node.status({fill: "red", shape: "dot", text: "retrying in " + interval + " sec."}); + } + } + }, 1000); + } + } + + RED.nodes.registerType("xiaomi-plug-wifi", XiaomiPlugWifiNode); + +} diff --git a/package.json b/package.json index 94700b0..9098edc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red-contrib-xiaomi-devices", - "version": "1.0.8", + "version": "1.0.9", "description": "A set of nodes to control some of the popular Xiaomi sensors which are connected to the Xiaomi Gateway.", "repository": { "type": "git", @@ -13,8 +13,9 @@ "xiaomi-ht": "node-red-contrib-xiaomi-ht/xiaomi-ht.js", "xiaomi-magnet": "node-red-contrib-xiaomi-magnet/xiaomi-magnet.js", "xiaomi-motion": "node-red-contrib-xiaomi-motion/xiaomi-motion.js", - "xiaomi-socket": "node-red-contrib-xiaomi-socket/xiaomi-socket.js", "xiaomi-switch": "node-red-contrib-xiaomi-switch/xiaomi-switch.js", + "xiaomi-socket": "node-red-contrib-xiaomi-socket/xiaomi-socket.js", + "xiaomi-socket-wifi": "node-red-contrib-xiaomi-socket-wifi/xiaomi-socket-wifi.js", "xiaomi-configurator": "node-red-contrib-xiaomi-configurator/xiaomi-configurator.js" } }, @@ -24,6 +25,7 @@ }, "dependencies": { "cryptojs": "^2.5.3", - "mustache": "^2.3.0" + "mustache": "^2.3.0", + "miio": "0.13.0" } } diff --git a/xiaomi-devices-overview.png b/xiaomi-devices-overview.png index 2c5c952..282abce 100644 Binary files a/xiaomi-devices-overview.png and b/xiaomi-devices-overview.png differ