diff --git a/README.md b/README.md index df5e196..cc76257 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,14 @@ If you change here something, you lose your password! - [ ] Integrate Yeelight - [ ] Handle Xiaomi Cube -- [ ] Add device SID in output -- [ ] Code cleanup +- [ ] Add filter on "all" node +- [ ] Set action status when no token available +- [ ] Add gateway status +- [ ] Update icons +- [ ] Refactor socket and set on/off actions +- [X] Add device SID in output +- [X] Remove different output styles +- [X] Code cleanup ## Sources diff --git a/node-red-contrib-xiaomi-actions/xiaomi-actions.js b/node-red-contrib-xiaomi-actions/xiaomi-actions.js index a00d02b..1c6d9e8 100644 --- a/node-red-contrib-xiaomi-actions/xiaomi-actions.js +++ b/node-red-contrib-xiaomi-actions/xiaomi-actions.js @@ -1,154 +1,106 @@ -module.exports = function(RED) { - "use strict"; - var miDevicesUtils = require('../utils'); +const miDevicesUtils = require('../src/utils'); +module.exports = (RED) => { + /********************************************* + Read data from Gateway + *********************************************/ function XiaomiActionRead(config) { RED.nodes.createNode(this, config); - var node = this; - node.on('input', function(msg) { + this.on('input', (msg) => { if(msg.sid) { - msg.payload = { - cmd: "read", - sid: msg.sid - }; - node.send(msg); + msg.payload = { cmd: "read", sid: msg.sid }; + this.send(msg); } }); } RED.nodes.registerType("xiaomi-actions read", XiaomiActionRead); - + /********************************************* + Get registred ids of devices on gateway + *********************************************/ function XiaomiActionGetIdList(config) { RED.nodes.createNode(this, config); - var node = this; - node.on('input', function(msg) { - msg.payload = { - cmd: "get_id_list" - }; + this.on('input', (msg) => { + msg.payload = { cmd: "get_id_list" }; node.send(msg); }); } RED.nodes.registerType("xiaomi-actions get_id_list", XiaomiActionGetIdList); - + /********************************************* + Virtual single click on a button + *********************************************/ function XiaomiActionSingleClick(config) { RED.nodes.createNode(this, config); - var node = this; - node.on('input', function(msg) { - if(msg.gateway && msg.sid && msg.gateway.key && msg.gateway.lastToken) { - msg.payload = { - cmd: "write", - data: { - status: "click", - sid: msg.sid, - key: miDevicesUtils.getGatewayKey(msg.gateway.key, msg.gateway.lastToken) - } - }; - node.send(msg); - } + this.on('input', (msg) => { + this.gateway = msg.gateway; + miDevicesUtils.sendWritePayloadToGateway(this, msg, {status: "click", sid: msg.sid}); }); } RED.nodes.registerType("xiaomi-actions click", XiaomiActionSingleClick); - + /********************************************* + Virtual Double click on a button + *********************************************/ function XiaomiActionDoubleClick(config) { RED.nodes.createNode(this, config); - var node = this; - node.on('input', function(msg) { - if(msg.gateway && msg.sid && msg.gateway.key && msg.gateway.lastToken) { - msg.payload = { - cmd: "write", - data: { - status: "double_click", - sid: msg.sid, - key: miDevicesUtils.getGatewayKey(msg.gateway.key, msg.gateway.lastToken) - } - }; - node.send(msg); - } + this.on('input', (msg) => { + miDevicesUtils.sendWritePayloadToGateway(this, msg, {status: "double_click", sid: msg.sid}); }); } RED.nodes.registerType("xiaomi-actions double_click", XiaomiActionDoubleClick); - - - + /********************************************* + Set the gateway light + *********************************************/ function XiaomiActionGatewayLight(config) { RED.nodes.createNode(this, config); this.gateway = RED.nodes.getNode(config.gateway); this.color = RED.nodes.getNode(config.color); this.brightness = RED.nodes.getNode(config.brightness); - var node = this; - node.on('input', function(msg) { - if(node.gateway && node.gateway.sid && node.gateway.key && node.gateway.lastToken) { - var color = msg.color || node.color; - var brightness = msg.brightness || node.brightness; - var rgb = miDevicesUtils.computeColorValue(brightness, color.red, color.green, color.blue); - msg.payload = { - cmd: "write", - data: { - rgb: rgb, - sid: node.gateway.sid, - key: miDevicesUtils.getGatewayKey(node.gateway.key, node.gateway.lastToken) - } - }; - node.send(msg); - } + this.on('input', (msg) => { + let color = msg.color || this.color; + let brightness = msg.brightness || this.brightness; + let rgb = miDevicesUtils.computeColorValue(brightness, color.red, color.green, color.blue); + miDevicesUtils.sendWritePayloadToGateway(this, msg, {rgb: rgb}); }); } RED.nodes.registerType("xiaomi-actions gateway_light", XiaomiActionGatewayLight); - - - + /********************************************* + Play a sound on the gateway + *********************************************/ function XiaomiActionGatewaySound(config) { RED.nodes.createNode(this, config); this.gateway = RED.nodes.getNode(config.gateway); this.mid = config.mid; this.volume = config.volume; - var node = this; - node.on('input', function(msg) { - if(node.gateway && node.gateway.sid && node.gateway.key && node.gateway.lastToken) { - msg.payload = { - cmd: "write", - data: { - mid: parseInt(msg.mid || node.mid), - volume: parseInt(msg.volume || node.volume), - sid: node.gateway.sid, - key: miDevicesUtils.getGatewayKey(node.gateway.key, node.gateway.lastToken) - } - }; - node.send(msg); - } + this.on('input', (msg) => { + miDevicesUtils.sendWritePayloadToGateway(this, msg, { + mid: parseInt(msg.mid || this.mid), + volume: parseInt(msg.volume || this.volume) + }); }); } RED.nodes.registerType("xiaomi-actions gateway_sound", XiaomiActionGatewaySound); - - + /********************************************* + Stop playing a sound on the gateway + *********************************************/ function XiaomiActionGatewayStopSound(config) { RED.nodes.createNode(this, config); this.gateway = RED.nodes.getNode(config.gateway); - var node = this; - node.on('input', function(msg) { - if(node.gateway && node.gateway.sid && node.gateway.key && node.gateway.lastToken) { - msg.payload = { - cmd: "write", - data: { - mid: 1000, - sid: node.gateway.sid, - key: miDevicesUtils.getGatewayKey(node.gateway.key, node.gateway.lastToken) - } - }; - node.send(msg); - } + this.on('input', function(msg) { + miDevicesUtils.sendWritePayloadToGateway(this, msg, { + mid: 1000 + }); }); } RED.nodes.registerType("xiaomi-actions gateway_stop_sound", XiaomiActionGatewayStopSound); diff --git a/node-red-contrib-xiaomi-all/xiaomi-all.html b/node-red-contrib-xiaomi-all/xiaomi-all.html index ec815d6..a9cf956 100644 --- a/node-red-contrib-xiaomi-all/xiaomi-all.html +++ b/node-red-contrib-xiaomi-all/xiaomi-all.html @@ -40,4 +40,13 @@ + +
Sample payload:
+[
+ {sid: "128d0901db1fa8", desc: "Door sensor" model: "magnet"},
+ {sid: "151d0401ab2491", desc: "Heat sensor", model: "sensor_ht"},
+ {sid: "658d030171427c", desc: "Button", model: "switch"}
+]
+
diff --git a/node-red-contrib-xiaomi-all/xiaomi-all.js b/node-red-contrib-xiaomi-all/xiaomi-all.js
index 39174f8..9c21337 100644
--- a/node-red-contrib-xiaomi-all/xiaomi-all.js
+++ b/node-red-contrib-xiaomi-all/xiaomi-all.js
@@ -1,18 +1,12 @@
-module.exports = function(RED) {
- "use strict";
- var mustache = require("mustache");
- var miDevicesUtils = require('../utils');
-
+module.exports = (RED) => {
function XiaomiAllNode(config) {
RED.nodes.createNode(this, config);
this.gateway = RED.nodes.getNode(config.gateway);
- var node = this;
-
if (this.gateway) {
- node.on('input', function(msg) {
- msg.payload = node.gateway.deviceList;
- node.send(msg);
+ this.on('input', (msg) => {
+ msg.payload = this.gateway.deviceList;
+ this.send(msg);
});
}
}
diff --git a/node-red-contrib-xiaomi-configurator/xiaomi-configurator.html b/node-red-contrib-xiaomi-configurator/xiaomi-configurator.html
index 18dd598..a37f99f 100644
--- a/node-red-contrib-xiaomi-configurator/xiaomi-configurator.html
+++ b/node-red-contrib-xiaomi-configurator/xiaomi-configurator.html
@@ -3,7 +3,7 @@
category: 'config',
defaults: {
name: {value: ""},
- ip: {value: ""},
+ ip: {value: "", required: true},
sid: {value: ""},
deviceList: {value:[{ sid:"", desc:"", model:"plug"}]},
key: {value: ""}
diff --git a/node-red-contrib-xiaomi-configurator/xiaomi-configurator.js b/node-red-contrib-xiaomi-configurator/xiaomi-configurator.js
index 3cd08d7..efb0c53 100644
--- a/node-red-contrib-xiaomi-configurator/xiaomi-configurator.js
+++ b/node-red-contrib-xiaomi-configurator/xiaomi-configurator.js
@@ -1,5 +1,4 @@
-module.exports = function(RED) {
-
+module.exports = (RED) => {
function XiaomiConfiguratorNode(n) {
RED.nodes.createNode(this, n);
this.name = n.name;
@@ -12,5 +11,4 @@ module.exports = function(RED) {
}
RED.nodes.registerType("xiaomi-configurator", XiaomiConfiguratorNode);
-
}
diff --git a/node-red-contrib-xiaomi-gateway/icons/gateway-icon.png b/node-red-contrib-xiaomi-gateway/icons/gateway-icon.png
deleted file mode 100644
index 802a2c3..0000000
Binary files a/node-red-contrib-xiaomi-gateway/icons/gateway-icon.png and /dev/null differ
diff --git a/node-red-contrib-xiaomi-gateway/icons/mijia.png b/node-red-contrib-xiaomi-gateway/icons/mijia.png
new file mode 100644
index 0000000..7f73eae
Binary files /dev/null and b/node-red-contrib-xiaomi-gateway/icons/mijia.png differ
diff --git a/node-red-contrib-xiaomi-gateway/xiaomi-gateway.html b/node-red-contrib-xiaomi-gateway/xiaomi-gateway.html
index 4b84869..04dbcd0 100644
--- a/node-red-contrib-xiaomi-gateway/xiaomi-gateway.html
+++ b/node-red-contrib-xiaomi-gateway/xiaomi-gateway.html
@@ -11,7 +11,7 @@
outputs: 1,
outputLabels: ["Gateway"],
paletteLabel: "gateway",
- icon: "gateway-icon.png",
+ icon: "mijia.png",
label: function () {
return this.name || "xiaomi-gateway";
}
diff --git a/node-red-contrib-xiaomi-gateway/xiaomi-gateway.js b/node-red-contrib-xiaomi-gateway/xiaomi-gateway.js
index 75dc238..5a5d3e9 100644
--- a/node-red-contrib-xiaomi-gateway/xiaomi-gateway.js
+++ b/node-red-contrib-xiaomi-gateway/xiaomi-gateway.js
@@ -1,42 +1,39 @@
-module.exports = function(RED) {
- "use strict";
- var dgram = require('dgram');
- var miDevicesUtils = require('../utils');
+const dgram = require('dgram'); // Given by udp node
+const miDevicesUtils = require('../src/utils');
+
+// UDP node copy/paste...
+
+module.exports = (RED) => {
var udpInputPortsInUse = {};
function XiaomiGatewayNode(config) {
RED.nodes.createNode(this, config);
this.gateway = RED.nodes.getNode(config.gateway);
- var node = this;
-
if (this.gateway) {
- node.on('input', function(msg) {
+ this.on('input', (msg) => {
// var payload = JSON.parse(msg);
var payload = msg.payload;
- node.log("Received message from: " + payload.model + " sid: " + payload.sid + " payload: " + payload.data);
+ //this.log("Received message from: " + payload.model + " sid: " + payload.sid + " payload: " + payload.data);
// Input from gateway
if(payload.sid) {
- if (payload.sid == node.gateway.sid && ["gateway"].indexOf(payload.model) >= 0) {
+ if (payload.sid == this.gateway.sid) {
if(payload.data.rgb) {
var decomposed = miDevicesUtils.computeColor(payload.data.rgb);
payload.data.brightness = decomposed.brightness;
payload.data.color = decomposed.color;
}
- node.send([msg]);
+ this.send([msg]);
}
}
// Prepare for request
else {
- msg.gateway = node.gateway;
- msg.sid = node.gateway.sid;
- node.send(msg);
+ msg.gateway = this.gateway;
+ msg.sid = this.gateway.sid;
+ this.send(msg);
}
});
-
- node.on("close", function() {
- });
}
}
RED.nodes.registerType("xiaomi-gateway", XiaomiGatewayNode);
@@ -50,10 +47,9 @@ module.exports = function(RED) {
this.iface = null;
this.addr = n.ip;
this.ipv = this.ip && this.ip.indexOf(":") >= 0 ? "udp6" : "udp4";
- var node = this;
- var opts = {type:node.ipv, reuseAddr:true};
- if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
+ var opts = {type:this.ipv, reuseAddr:true};
+ if (process.version.indexOf("v0.10") === 0) { opts = this.ipv; }
var server;
if (!udpInputPortsInUse.hasOwnProperty(this.port)) {
@@ -61,24 +57,24 @@ module.exports = function(RED) {
udpInputPortsInUse[this.port] = server;
}
else {
- node.warn(RED._("udp.errors.alreadyused",node.port));
+ this.warn(RED._("udp.errors.alreadyused",this.port));
server = udpInputPortsInUse[this.port]; // re-use existing
}
- if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
+ if (process.version.indexOf("v0.10") === 0) { opts = this.ipv; }
- server.on("error", function (err) {
- if ((err.code == "EACCES") && (node.port < 1024)) {
- node.error(RED._("udp.errors.access-error"));
+ server.on("error", (err) => {
+ if ((err.code == "EACCES") && (this.port < 1024)) {
+ this.error(RED._("udp.errors.access-error"));
} else {
- node.error(RED._("udp.errors.error",{error:err.code}));
+ this.error(RED._("udp.errors.error",{error:err.code}));
}
server.close();
});
- server.on('message', function (message, remote) {
+ server.on('message', (message, remote) => {
var msg;
- if(remote.address == node.addr) {
+ if(remote.address == this.addr) {
var msg = message.toString('utf8');
var jsonMsg = JSON.parse(msg);
if(jsonMsg.data) {
@@ -88,51 +84,51 @@ module.exports = function(RED) {
}
}
msg = { payload: jsonMsg };
- if(jsonMsg.token && node.gateway && jsonMsg.data.ip && jsonMsg.data.ip === node.gateway.ip) {
- node.gateway.lastToken = jsonMsg.token;
- if(!node.gateway.sid) {
- node.gateway.sid = jsonMsg.sid;
+ if(jsonMsg.token && this.gateway && jsonMsg.data.ip && jsonMsg.data.ip === this.gateway.ip) {
+ this.gateway.lastToken = jsonMsg.token;
+ if(!this.gateway.sid) {
+ this.gateway.sid = jsonMsg.sid;
}
}
- node.send(msg);
+ this.send(msg);
}
});
- server.on('listening', function () {
+ server.on('listening', () => {
var address = server.address();
- node.log(RED._("udp.status.listener-at",{host:address.address,port:address.port}));
+ this.log(RED._("udp.status.listener-at",{host:address.address,port:address.port}));
server.setBroadcast(true);
try {
server.setMulticastTTL(128);
- server.addMembership(node.group,node.iface);
- node.log(RED._("udp.status.mc-group",{group:node.group}));
+ server.addMembership(this.group,this.iface);
+ this.log(RED._("udp.status.mc-group",{group:this.group}));
} catch (e) {
if (e.errno == "EINVAL") {
- node.error(RED._("udp.errors.bad-mcaddress"));
+ this.error(RED._("udp.errors.bad-mcaddress"));
} else if (e.errno == "ENODEV") {
- node.error(RED._("udp.errors.interface"));
+ this.error(RED._("udp.errors.interface"));
} else {
- node.error(RED._("udp.errors.error",{error:e.errno}));
+ this.error(RED._("udp.errors.error",{error:e.errno}));
}
}
});
- node.on("close", function() {
- if (udpInputPortsInUse.hasOwnProperty(node.port)) {
- delete udpInputPortsInUse[node.port];
+ this.on("close", () => {
+ if (udpInputPortsInUse.hasOwnProperty(this.port)) {
+ delete udpInputPortsInUse[this.port];
}
try {
server.close();
- node.log(RED._("udp.status.listener-stopped"));
+ this.log(RED._("udp.status.listener-stopped"));
} catch (err) {
- //node.error(err);
+ //this.error(err);
}
});
- try { server.bind(node.port,node.iface); }
+ try { server.bind(this.port, this.iface); }
catch(e) { } // Don't worry if already bound
}
- RED.httpAdmin.get('/udp-ports/:id', RED.auth.needsPermission('udp-ports.read'), function(req,res) {
+ RED.httpAdmin.get('/udp-ports/:id', RED.auth.needsPermission('udp-ports.read'), (req,res) => {
res.json(Object.keys(udpInputPortsInUse));
});
RED.nodes.registerType("xiaomi-gateway in",GatewayIn);
@@ -147,10 +143,9 @@ module.exports = function(RED) {
this.addr = n.ip;
this.ipv = this.ip && this.ip.indexOf(":") >= 0 ? "udp6" : "udp4";
this.multicast = false;
- var node = this;
- var opts = {type:node.ipv, reuseAddr:true};
- if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
+ var opts = {type:this.ipv, reuseAddr:true};
+ if (process.version.indexOf("v0.10") === 0) { opts = this.ipv; }
var sock;
if (udpInputPortsInUse[this.outport]) {
@@ -158,7 +153,7 @@ module.exports = function(RED) {
}
else {
sock = dgram.createSocket(opts); // default to udp4
- sock.on("error", function(err) {
+ sock.on("error", (err) => {
// Any async error will also get reported in the sock.send call.
// This handler is needed to ensure the error marked as handled to
// prevent it going to the global error handler and shutting node-red
@@ -168,27 +163,27 @@ module.exports = function(RED) {
}
if (!udpInputPortsInUse[this.outport]) {
- sock.bind(node.outport);
- node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
+ sock.bind(this.outport);
+ this.log(RED._("udp.status.ready",{outport:this.outport,host:this.addr,port:this.port}));
} else {
- node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
+ this.log(RED._("udp.status.ready-nolocal",{host:this.addr,port:this.port}));
}
- node.on("input", function(msg) {
+ this.on("input", (msg) => {
if (msg.hasOwnProperty("payload")) {
- var add = node.addr || msg.ip || "";
- var por = node.port || msg.port || 0;
+ var add = this.addr || msg.ip || "";
+ var por = this.port || msg.port || 0;
if (add === "") {
- node.warn(RED._("udp.errors.ip-notset"));
+ this.warn(RED._("udp.errors.ip-notset"));
} else if (por === 0) {
- node.warn(RED._("udp.errors.port-notset"));
+ this.warn(RED._("udp.errors.port-notset"));
} else if (isNaN(por) || (por < 1) || (por > 65535)) {
- node.warn(RED._("udp.errors.port-invalid"));
+ this.warn(RED._("udp.errors.port-invalid"));
} else {
var message = Buffer.from(JSON.stringify(msg.payload));
- sock.send(message, 0, message.length, por, add, function(err, bytes) {
+ sock.send(message, 0, message.length, por, add, (err, bytes) => {
if (err) {
- node.error("udp : "+err,msg);
+ this.error("udp : "+err,msg);
}
message = null;
});
@@ -196,15 +191,15 @@ module.exports = function(RED) {
}
});
- node.on("close", function() {
- if (udpInputPortsInUse.hasOwnProperty(node.outport)) {
- delete udpInputPortsInUse[node.outport];
+ this.on("close", () => {
+ if (udpInputPortsInUse.hasOwnProperty(this.outport)) {
+ delete udpInputPortsInUse[this.outport];
}
try {
sock.close();
- node.log(RED._("udp.status.output-stopped"));
+ this.log(RED._("udp.status.output-stopped"));
} catch (err) {
- //node.error(err);
+ //this.error(err);
}
});
}
diff --git a/node-red-contrib-xiaomi-ht/xiaomi-ht.html b/node-red-contrib-xiaomi-ht/xiaomi-ht.html
index 8ec2204..f06ed98 100644
--- a/node-red-contrib-xiaomi-ht/xiaomi-ht.html
+++ b/node-red-contrib-xiaomi-ht/xiaomi-ht.html
@@ -5,16 +5,10 @@
defaults: {
gateway: {value:"", type:"xiaomi-configurator"},
name: {value: ""},
- sid: {value: "", required: true},
- temperature: {value: "{{temperature}}"},
- humidity: {value: "{{humidity}}"},
- pressure: {value: "{{pressure}}"},
- divide: {value: true},
- output: {value: "0"}
+ sid: {value: "", required: true}
},
inputs: 1,
- outputs: 3,
- outputLabels: ["Temperature","Humidity","Pressure"],
+ outputs: 1,
paletteLabel: "sensor HT",
icon: "thermometer-icon.png",
label: function () {
@@ -55,16 +49,7 @@
changeGateway("sensor_ht");
});
- $("#node-input-output").change(function () {
- if ($(this).val() == "2") {
- $(".node-input-msg").show();
- } else {
- $(".node-input-msg").hide();
- }
- });
-
$(".node-input-msg").hide();
- $("#node-input-output").val(node.output);
},
oneditsave: function() {
var node = this;
@@ -86,31 +71,6 @@
-