refactor: code clean up
This commit is contained in:
10
README.md
10
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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -40,4 +40,13 @@
|
||||
</dl>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h4>Details</h4>
|
||||
<p>Sample payload:</p>
|
||||
<p><pre>[
|
||||
{sid: "128d0901db1fa8", desc: "Door sensor" model: "magnet"},
|
||||
{sid: "151d0401ab2491", desc: "Heat sensor", model: "sensor_ht"},
|
||||
{sid: "658d030171427c", desc: "Button", model: "switch"}
|
||||
]</pre>
|
||||
</p>
|
||||
</script>
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: ""}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 653 B |
BIN
node-red-contrib-xiaomi-gateway/icons/mijia.png
Normal file
BIN
node-red-contrib-xiaomi-gateway/icons/mijia.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -11,7 +11,7 @@
|
||||
outputs: 1,
|
||||
outputLabels: ["Gateway"],
|
||||
paletteLabel: "gateway",
|
||||
icon: "gateway-icon.png",
|
||||
icon: "mijia.png",
|
||||
label: function () {
|
||||
return this.name || "xiaomi-gateway";
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 @@
|
||||
<label for="node-input-sid"><i class="icon-tag"></i> Device</label>
|
||||
<select id="node-input-sid" placeholder="xiaomi gateway"></select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-output"><i class="icon-tag"></i> Output</label>
|
||||
<select id="node-input-output" style="width:70%;">
|
||||
<option value="0">Full data</option>
|
||||
<option value="1">Just values</option>
|
||||
<option value="2">Template</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-temperature"><i class="fa fa-thermometer-three-quarters"></i> Temperature</label>
|
||||
<input type="text" id="node-input-temperature">
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-humidity"><i class="fa fa-mixcloud"></i> Humidity</label>
|
||||
<input type="text" id="node-input-humidity"/>
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-pressure"><i class="fa fa-tachometer"></i> Pressure</label>
|
||||
<input type="text" id="node-input-pressure"/>
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label> </label>
|
||||
<i></i> <input type="checkbox" id="node-input-divide" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-divide" style="width: 70%;">Divide values by 100</label>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xiaomi-ht">
|
||||
@@ -126,59 +86,29 @@
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<ol class="node-ports">
|
||||
<li>Temperature output
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string | json</span></dt>
|
||||
<dd>raw data, value or template.</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>Humidity output
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string | json</span></dt>
|
||||
<dd>raw data, value or template.</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">object</span></dt>
|
||||
<dd>Data from gateway, see below.</dd>
|
||||
</dl>
|
||||
</ol>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>The incoming json message is parsed if the type model is <code>sensor_ht</code> or <code>weather.v1</code> and
|
||||
the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>Three output types are supported:
|
||||
<ul>
|
||||
<li>Full data</li>
|
||||
<li>Just values</li>
|
||||
<li>Template</li>
|
||||
</ul>
|
||||
<h4>Details</h4>
|
||||
<p>The incoming message is processed if the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>Sample payload from Aqara (which brings pressure):</p>
|
||||
<p><pre>{
|
||||
cmd: "read_ack"
|
||||
model: "weather.v1"
|
||||
sid: "158d00010b7f1b"
|
||||
short_id: 8451
|
||||
data: {
|
||||
voltage:3005,
|
||||
temperature:23.25,
|
||||
humidity:56.99,
|
||||
pressure:981.26,
|
||||
batteryLevel: 34
|
||||
}
|
||||
}</pre>
|
||||
Where <code>humidy</code> is in percents, <code>pressure</code> in hPa, <code>batteryLevel</code> is a computed percentage of remaining battery.
|
||||
</p>
|
||||
|
||||
<h4>Full data</h4>
|
||||
<p>Passes the complete json object received from the gateway on output 1. Use this if you need the raw data.</p>
|
||||
<h4>Just values</h4>
|
||||
<p>Only passes the string values for temperature on output 1 and humidity on output 2.</p>
|
||||
<h4>Template</h4>
|
||||
<p>Use your own template to pass the values on. The template can contain <a href="http://mustache.github.io/mustache.5.html">mustache-style</a> tags.
|
||||
Any property from the data section of the full object can be used. As the HT sensor is sending data in thousends, you can check this box to have it in hundreds.
|
||||
Here an template example to send the temperature to homebridge-mqtt:
|
||||
<pre>
|
||||
{
|
||||
"name":"Temperatuur woonkamer",
|
||||
"characteristic":"CurrentTemperature",
|
||||
"value":{{temperature}}
|
||||
}</pre></p>
|
||||
|
||||
<p>Sample message:</p>
|
||||
<p><pre>
|
||||
{
|
||||
cmd: "read_ack"
|
||||
model: "sensor_ht"
|
||||
sid: "158d00010b7f1b"
|
||||
short_id: 8451
|
||||
data: "{
|
||||
"voltage":3005,
|
||||
"temperature":"2325",
|
||||
"humidity":"5699",
|
||||
"pressure":"98126"
|
||||
}"
|
||||
}</pre></p>
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,97 +1,39 @@
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
var dgram = require('dgram');
|
||||
var miDevicesUtils = require('../utils');
|
||||
const miDevicesUtils = require('../src/utils');
|
||||
|
||||
module.exports = (RED) => {
|
||||
function XiaomiHtNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.gateway = RED.nodes.getNode(config.gateway);
|
||||
this.sid = config.sid;
|
||||
this.output = config.output;
|
||||
this.temperature = config.temperature;
|
||||
this.humidity = config.humidity;
|
||||
this.divide = config.divide;
|
||||
|
||||
var node = this;
|
||||
node.status({fill:"grey", shape:"ring", text:"battery - na"});
|
||||
this.status({fill:"grey", shape:"ring", text:"battery - na"});
|
||||
|
||||
if (this.gateway) {
|
||||
node.on('input', function(msg) {
|
||||
// var payload = JSON.parse(msg);
|
||||
var payload = msg.payload;
|
||||
node.log("Received message from: " + payload.model + " sid: " + payload.sid + " payload: " + payload.data);
|
||||
this.on('input', (msg) => {
|
||||
let payload = msg.payload;
|
||||
|
||||
// Input from gateway
|
||||
if(payload.sid) {
|
||||
if (payload.sid == node.sid && ["sensor_ht", "weather.v1"].indexOf(payload.model) >= 0) {
|
||||
var data = payload.data;
|
||||
miDevicesUtils.setStatus(node, data);
|
||||
|
||||
if (node.output == "0") {
|
||||
node.send([msg]);
|
||||
} else if (node.output == "1") {
|
||||
var temp = null;
|
||||
var humidity = null;
|
||||
var pressure = null;
|
||||
|
||||
if (data.temperature) {
|
||||
temp = {"payload": data.temperature};
|
||||
if (payload.sid) {
|
||||
if (payload.sid == this.sid) {
|
||||
miDevicesUtils.setStatus(this, payload.data);
|
||||
["temperature", "humidity", "pressure"].forEach((dataType) => {
|
||||
if(payload.data[dataType]) {
|
||||
payload.data[dataType] = parseInt(payload.data[dataType])/100;
|
||||
}
|
||||
|
||||
if (data.humidity) {
|
||||
humidity = {"payload": data.humidity};
|
||||
}
|
||||
|
||||
if (data.pressure) {
|
||||
pressure = {"payload": data.pressure};
|
||||
}
|
||||
node.send([temp, humidity, pressure]);
|
||||
} else if (node.output == "2") {
|
||||
var temp = null;
|
||||
var humidity = null;
|
||||
var pressure = null;
|
||||
|
||||
if (data.temperature) {
|
||||
if (this.divide) {
|
||||
data.temperature = String(data.temperature / 100);
|
||||
}
|
||||
temp = {"payload": mustache.render(node.temperature, data)}
|
||||
}
|
||||
|
||||
if (data.humidity) {
|
||||
if (this.divide) {
|
||||
data.humidity = String(data.humidity / 100);
|
||||
}
|
||||
humidity = {"payload": mustache.render(node.humidity, data)}
|
||||
}
|
||||
|
||||
if (data.pressure) {
|
||||
if (this.divide) {
|
||||
data.pressure = String(data.pressure / 100);
|
||||
}
|
||||
pressure = {"payload": mustache.render(node.pressure, data)}
|
||||
}
|
||||
node.send([temp, humidity, pressure]);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
msg = null;
|
||||
}
|
||||
}
|
||||
// Prepare for request
|
||||
else {
|
||||
miDevicesUtils.prepareForGatewayRequest(node, msg);
|
||||
node.send(msg);
|
||||
miDevicesUtils.prepareForGatewayRequest(this, msg);
|
||||
}
|
||||
this.send(msg);
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
});
|
||||
|
||||
} else {
|
||||
// no gateway configured
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RED.nodes.registerType("xiaomi-ht", XiaomiHtNode);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,14 +5,10 @@
|
||||
defaults: {
|
||||
gateway: {value:"", type:"xiaomi-configurator"},
|
||||
name: {value: ""},
|
||||
sid: {value: "", required: true},
|
||||
openmsg: {value: ""},
|
||||
closemsg: {value: ""},
|
||||
output: {value: "0"}
|
||||
sid: {value: "", required: true}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
outputLabels: ["Status"],
|
||||
paletteLabel: "contact",
|
||||
icon: "door-icon.png",
|
||||
label: function () {
|
||||
@@ -52,14 +48,6 @@
|
||||
$("#node-input-gateway").change(function () {
|
||||
changeGateway("magnet");
|
||||
});
|
||||
|
||||
$("#node-input-output").change(function () {
|
||||
if ($(this).val() == "2") {
|
||||
$(".node-input-msg").show();
|
||||
} else {
|
||||
$(".node-input-msg").hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
var node = this;
|
||||
@@ -81,22 +69,6 @@
|
||||
<label for="node-input-sid"><i class="icon-tag"></i> Device</label>
|
||||
<select id="node-input-sid" placeholder="xiaomi gateway"></select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-output"><i class="icon-tag"></i> Output</label>
|
||||
<select id="node-input-output" style="width:70%;">
|
||||
<option value="0">Full data</option>
|
||||
<option value="1">Just values</option>
|
||||
<option value="2">Template</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-openmsg"><i class="fa fa-circle-o-notch"></i> Open msg</label>
|
||||
<input type="text" id="node-input-openmsg">
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-closemsg"><i class="fa fa-circle-o"></i> Close msg</label>
|
||||
<input type="text" id="node-input-closemsg">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xiaomi-magnet">
|
||||
@@ -112,44 +84,27 @@
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<ol class="node-ports">
|
||||
<li>State output
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string | json</span></dt>
|
||||
<dd>raw data, value or template.</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">object</span></dt>
|
||||
<dd>Data from gateway, see below.</dd>
|
||||
</dl>
|
||||
</ol>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>The incoming json message is parsed if the type model is <code>magnet</code> or <code>sensor_magnet.aq2</code> and
|
||||
the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>Three output types are supported:
|
||||
<ul>
|
||||
<li>Full data</li>
|
||||
<li>Just values</li>
|
||||
<li>Template</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h4>Full data</h4>
|
||||
<p>Passes the complete json object received from the gateway. Use this if you need the raw data.</p>
|
||||
<h4>Just values</h4>
|
||||
<p>Only passes the sting values <code>open</code> or <code>close</code>.</p>
|
||||
<h4>Template</h4>
|
||||
<p>Use your own template to pass the values on. The template can contain <a href="http://mustache.github.io/mustache.5.html">mustache-style</a> tags.
|
||||
Any property from the data section of the full object can be used.</p>
|
||||
|
||||
<p>The incoming message is processed if the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>Sample message:</p>
|
||||
<p><pre>
|
||||
{
|
||||
cmd: "read_ack"
|
||||
model: "magnet"
|
||||
sid: "158d000112fb5d"
|
||||
short_id: 50301
|
||||
data: "{
|
||||
"voltage":3015,
|
||||
"status":"close"
|
||||
}"
|
||||
}</pre></p>
|
||||
<p><pre>{
|
||||
cmd: "read_ack"
|
||||
model: "sensor_magnet.aq2"
|
||||
sid: "158d000112fb5d"
|
||||
short_id: 50301
|
||||
data: {
|
||||
voltage: 3015,
|
||||
status: "close",
|
||||
batteryLevel: 23
|
||||
}
|
||||
}</pre>
|
||||
Where <code>status</code> can be <code>"open"</code> or <code>"close"</code>, <code>batteryLevel</code> is a computed percentage of remaining battery.
|
||||
</p>
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,78 +1,8 @@
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
var miDevicesUtils = require('../utils');
|
||||
const miDevicesUtils = require('../src/utils');
|
||||
|
||||
module.exports = (RED) => {
|
||||
function XiaomiMagnetNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.gateway = RED.nodes.getNode(config.gateway);
|
||||
this.sid = config.sid;
|
||||
this.output = config.output;
|
||||
this.openmsg = config.openmsg;
|
||||
this.closemsg = config.closemsg;
|
||||
|
||||
var node = this;
|
||||
var state = "";
|
||||
|
||||
// node.status({fill:"yellow", shape:"dot", text:"unknown state"});
|
||||
node.status({fill:"grey", shape:"ring", text:"battery - na"});
|
||||
|
||||
if (this.gateway) {
|
||||
node.on('input', function(msg) {
|
||||
// var payload = JSON.parse(msg);
|
||||
var payload = msg.payload;
|
||||
|
||||
if(payload.sid) {
|
||||
if (payload.sid == node.sid && ["magnet", "sensor_magnet.aq2"].indexOf(payload.model) >= 0) {
|
||||
var data = payload.data;
|
||||
|
||||
// if (data.status && data.status == "open") {
|
||||
// node.status({fill:"green", shape:"dot", text:"open"});
|
||||
// state = "open";
|
||||
// } else if (data.status && data.status == "close") {
|
||||
// node.status({fill:"red", shape:"dot", text:"closed"});
|
||||
// state = "closed";
|
||||
// }
|
||||
miDevicesUtils.setStatus(node, data);
|
||||
|
||||
|
||||
if (node.output == "0") {
|
||||
node.send([msg]);
|
||||
} else if (node.output == "1") {
|
||||
var status = null;
|
||||
|
||||
if (data.status) {
|
||||
status = {"payload": data.status};
|
||||
}
|
||||
node.send([status]);
|
||||
} else if (node.output == "2") {
|
||||
var status = null;
|
||||
|
||||
if (data.status === 'open') {
|
||||
status = {"payload": mustache.render(node.openmsg, data)}
|
||||
} else {
|
||||
status = {"payload": mustache.render(node.closemsg, data)}
|
||||
}
|
||||
node.send([status]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Prepare for request
|
||||
else {
|
||||
miDevicesUtils.prepareForGatewayRequest(node, msg);
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
});
|
||||
|
||||
} else {
|
||||
// no gateway configured
|
||||
}
|
||||
|
||||
miDevicesUtils.defaultNode(RED, config, this);
|
||||
}
|
||||
|
||||
RED.nodes.registerType("xiaomi-magnet", XiaomiMagnetNode);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
output: {value: "0"}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 2,
|
||||
outputLabels: ["Status"],
|
||||
outputs: 1,
|
||||
paletteLabel: "motion",
|
||||
icon: "motion-icon.png",
|
||||
label: function () {
|
||||
@@ -52,14 +51,6 @@
|
||||
$("#node-input-gateway").change(function () {
|
||||
changeGateway("magnet");
|
||||
});
|
||||
|
||||
$("#node-input-output").change(function () {
|
||||
if ($(this).val() == "2") {
|
||||
$(".node-input-msg").show();
|
||||
} else {
|
||||
$(".node-input-msg").hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
var node = this;
|
||||
@@ -81,22 +72,6 @@
|
||||
<label for="node-input-sid"><i class="icon-tag"></i> Device</label>
|
||||
<select id="node-input-sid" placeholder="xiaomi gateway"></select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-output"><i class="icon-tag"></i> Output</label>
|
||||
<select id="node-input-output" style="width:70%;">
|
||||
<option value="0">Full data</option>
|
||||
<option value="1">Just values</option>
|
||||
<option value="2">Template</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-motionmsg"><i class="fa fa-rss"></i> Motion msg</label>
|
||||
<input type="text" id="node-input-motionmsg">
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-nomotionmsg"><i class="fa fa-circle"></i> No motion msg</label>
|
||||
<input type="text" id="node-input-nomotionmsg">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xiaomi-motion">
|
||||
@@ -112,49 +87,26 @@
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<ol class="node-ports">
|
||||
<li>Motion output
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string | json</span></dt>
|
||||
<dd>raw data, value or template.</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>Duration output
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">json</span></dt>
|
||||
<dd>raw data</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">object</span></dt>
|
||||
<dd>Data from gateway, see below.</dd>
|
||||
</dl>
|
||||
</ol>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>The incoming json message is parsed if the type model is <code>motion</code> and
|
||||
the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>Three output types are supported for output 1:
|
||||
<ul>
|
||||
<li>Full data</li>
|
||||
<li>Just values</li>
|
||||
<li>Template</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h4>Full data</h4>
|
||||
<p>Passes the complete json object received from the gateway. Use this if you need the raw data.</p>
|
||||
<h4>Just values</h4>
|
||||
<p>Only passes the values <code>motion</code> or <code>no_motion</code>. In case of <code>no_motion</code> also the duration object is passed on output 2.</p>
|
||||
<h4>Template</h4>
|
||||
<p>Use your own template to pass the values on. The template can contain <a href="http://mustache.github.io/mustache.5.html">mustache-style</a> tags.
|
||||
Any property from the data section of the full object can be used.</p>
|
||||
|
||||
<h4>Details</h4>
|
||||
<p>The incoming message is processed if the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>Sample message:</p>
|
||||
<p><pre>
|
||||
{
|
||||
cmd: "read_ack"
|
||||
model: "motion"
|
||||
sid: "158d00015ef56c"
|
||||
short_id: 21672
|
||||
data: "{
|
||||
"voltage":3035,
|
||||
"status":"motion"
|
||||
}"
|
||||
}</pre></p>
|
||||
<p><pre>{
|
||||
cmd: "read_ack"
|
||||
model: "motion"
|
||||
sid: "158d00015ef56c"
|
||||
short_id: 21672
|
||||
data: {
|
||||
voltage: 3035,
|
||||
status: "motion",
|
||||
batteryLevel: 45
|
||||
}
|
||||
}</pre>
|
||||
Where <code>batteryLevel</code> is a computed percentage of remaining battery.
|
||||
</p>
|
||||
</script>
|
||||
|
||||
@@ -1,84 +1,8 @@
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
var miDevicesUtils = require('../utils');
|
||||
const miDevicesUtils = require('../src/utils');
|
||||
|
||||
module.exports = (RED) => {
|
||||
function XiaomiMotionNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.gateway = RED.nodes.getNode(config.gateway);
|
||||
this.sid = config.sid;
|
||||
this.output = config.output;
|
||||
this.motionmsg = config.motionmsg;
|
||||
this.nomotionmsg = config.nomotionmsg;
|
||||
|
||||
var node = this;
|
||||
var state = "";
|
||||
|
||||
// node.status({fill:"yellow", shape:"dot", text:"unknown state"});
|
||||
node.status({fill:"grey", shape:"ring", text:"battery - na"});
|
||||
|
||||
if (this.gateway) {
|
||||
node.on('input', function(msg) {
|
||||
// var payload = JSON.parse(msg);
|
||||
var payload = msg.payload;
|
||||
|
||||
if (payload.sid) {
|
||||
if (payload.sid == node.sid && payload.model == "motion") {
|
||||
var data = payload.data;
|
||||
|
||||
// if (data.status && data.status == "open") {
|
||||
// node.status({fill:"green", shape:"dot", text:"open"});
|
||||
// state = "open";
|
||||
// } else if (data.status && data.status == "close") {
|
||||
// node.status({fill:"red", shape:"dot", text:"closed"});
|
||||
// state = "closed";
|
||||
// }
|
||||
miDevicesUtils.setStatus(node, data);
|
||||
|
||||
|
||||
if (node.output == "0") {
|
||||
node.send([msg]);
|
||||
} else if (node.output == "1") {
|
||||
var status = null;
|
||||
var duration = null;
|
||||
|
||||
if (data.status) {
|
||||
status = {"payload": data.status};
|
||||
}
|
||||
if (data.no_motion) {
|
||||
status = {"payload": "no_motion"};
|
||||
duration = {"payload": {"no_motion": data.no_motion}};
|
||||
}
|
||||
|
||||
node.send([[status], [duration]]);
|
||||
} else if (node.output == "2") {
|
||||
var status = null;
|
||||
|
||||
if (data.status === 'motion') {
|
||||
status = {"payload": mustache.render(node.motionmsg, data)}
|
||||
} else {
|
||||
status = {"payload": mustache.render(node.nomotionmsg, data)}
|
||||
}
|
||||
node.send([status]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Prepare for request
|
||||
else {
|
||||
miDevicesUtils.prepareForGatewayRequest(node, msg);
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
});
|
||||
|
||||
} else {
|
||||
// no gateway configured
|
||||
}
|
||||
|
||||
miDevicesUtils.defaultNode(RED, config, this);
|
||||
}
|
||||
|
||||
RED.nodes.registerType("xiaomi-motion", XiaomiMotionNode);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,21 +16,6 @@
|
||||
icon: "outlet-wifi-icon.png",
|
||||
label: function () {
|
||||
return this.name || "xiaomi-plug-wifi";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var node = this;
|
||||
|
||||
$("#node-input-output").change(function () {
|
||||
if ($(this).val() == "2") {
|
||||
$(".node-input-msg").show();
|
||||
} else {
|
||||
$(".node-input-msg").hide();
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
oneditsave: function() {
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -44,22 +29,6 @@
|
||||
<label for="node-input-ip"><i class="icon-tag"></i> Ip</label>
|
||||
<input type="text" id="node-input-ip" placeholder="ip address">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-output"><i class="icon-tag"></i> Output</label>
|
||||
<select id="node-input-output" style="width:70%;">
|
||||
<option value="0">Full data</option>
|
||||
<option value="1">Just values</option>
|
||||
<option value="2">Template</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-onmsg"><i class="fa fa-power-off"></i> On msg</label>
|
||||
<input type="text" id="node-input-onmsg">
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-offmsg"><i class="fa fa-power-off"></i> Off msg</label>
|
||||
<input type="text" id="node-input-offmsg">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xiaomi-plug-wifi">
|
||||
@@ -77,43 +46,22 @@
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<ol class="node-ports">
|
||||
<li>Status output
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string | json</span></dt>
|
||||
<dd>raw data, value or template.</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">object</span></dt>
|
||||
<dd>Data from gateway, see below.</dd>
|
||||
</dl>
|
||||
</ol>
|
||||
|
||||
<h3>Details</h3>
|
||||
<h4>Details</h4>
|
||||
<p>On the input you can send the string <code>on</code> to switch the plug on. To turn it off just send the string <code>off</code></p>
|
||||
<p>Output 1 reports the status</p>
|
||||
|
||||
<p>Three output types are supported:
|
||||
<ul>
|
||||
<li>Full data</li>
|
||||
<li>Just values</li>
|
||||
<li>Template</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h4>Full data</h4>
|
||||
<p>Passes a json object with detailed information about the plug. Use this if you need the raw data.</p>
|
||||
<h4>Just values</h4>
|
||||
<p>Only passes the values <code>on</code> or <code>off</code></p>
|
||||
<h4>Template</h4>
|
||||
<p>Use your own template to pass the values on. The template can contain <a href="http://mustache.github.io/mustache.5.html">mustache-style</a> tags.
|
||||
Any property from the data section of the full object can be used.</p>
|
||||
|
||||
<p>Sample message full data:</p>
|
||||
<p><pre>
|
||||
{
|
||||
"type": "power-plug",
|
||||
"model": "chuangmi.plug.m1",
|
||||
"capabilities: [ {'0': "power-channels"} ],
|
||||
"address": "192.168.178.31",
|
||||
"port": 54321,
|
||||
"power": { '0': false }
|
||||
}"
|
||||
}</pre></p>
|
||||
<p><pre>{
|
||||
type: "power-plug",
|
||||
model: "chuangmi.plug.m1",
|
||||
capabilities: [ {"0": "power-channels"} ],
|
||||
address: "192.168.178.31",
|
||||
port: 54321,
|
||||
power: { "0": false },
|
||||
state: "on"
|
||||
}</pre></p>
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
var crypto = require("crypto");
|
||||
var miio = require("miio");
|
||||
const miio = require("miio");
|
||||
|
||||
module.exports = (RED) => {
|
||||
var connectionState = "timeout";
|
||||
var retryTimer;
|
||||
var delayedStatusMsgTimer;
|
||||
@@ -11,23 +9,18 @@ module.exports = function(RED) {
|
||||
function XiaomiPlugWifiNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.ip = config.ip;
|
||||
this.output = config.output;
|
||||
this.onmsg = config.onmsg;
|
||||
this.offmsg = config.offmsg;
|
||||
this.plug = null;
|
||||
|
||||
var node = this;
|
||||
this.status({fill: "yellow", shape: "dot", text: "connecting"});
|
||||
|
||||
node.status({fill: "yellow", shape: "dot", text: "connecting"});
|
||||
|
||||
miio.device({address: node.ip})
|
||||
.then(function (plug) {
|
||||
node.plug = plug;
|
||||
node.status({fill:"green", shape:"dot", text:"connected"});
|
||||
miio.device({address: this.ip})
|
||||
.then((plug) => {
|
||||
this.plug = plug;
|
||||
this.status({fill:"green", shape:"dot", text:"connected"});
|
||||
connectionState = "connected";
|
||||
delayedStatusMsgUpdate(node);
|
||||
|
||||
node.plug.on('propertyChanged', function(e) {
|
||||
this.plug.on('propertyChanged', (e) => {
|
||||
if (e.property === "power") {
|
||||
if (e.value['0']) {
|
||||
setState("on");
|
||||
@@ -38,73 +31,58 @@ module.exports = function(RED) {
|
||||
});
|
||||
watchdog();
|
||||
})
|
||||
.catch(function (error) {
|
||||
.catch((error) => {
|
||||
connectionState = "reconnecting";
|
||||
watchdog();
|
||||
})
|
||||
|
||||
node.on('input', function (msg) {
|
||||
this.on('input', (msg) => {
|
||||
var payload = msg.payload;
|
||||
if (connectionState === "connected") {
|
||||
if (payload == 'on') {
|
||||
node.plug.setPower(true);
|
||||
this.plug.setPower(true);
|
||||
}
|
||||
|
||||
if (payload == 'off') {
|
||||
node.plug.setPower(false);
|
||||
this.plug.setPower(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
node.on('close', function (done) {
|
||||
this.on('close', (done) => {
|
||||
if (retryTimer) {
|
||||
clearTimeout(retryTimer);
|
||||
}
|
||||
if (delayedStatusMsgTimer) {
|
||||
clearTimeout(delayedStatusMsgTimer);
|
||||
}
|
||||
if (node.plug) {
|
||||
node.plug.destroy();
|
||||
if (this.plug) {
|
||||
this.plug.destroy();
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
var setState = function(state) {
|
||||
if (node.plug) {
|
||||
var status = null;
|
||||
var info = {"payload": {
|
||||
"id": node.plug.id,
|
||||
"type": node.plug.type,
|
||||
"model": node.plug.model,
|
||||
"capabilities": node.plug.capabilities,
|
||||
"address": node.plug.address,
|
||||
"port": node.plug.port,
|
||||
"power": node.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 setState = (state) => {
|
||||
if (this.plug) {
|
||||
let status = {
|
||||
payload: {
|
||||
id: this.plug.id,
|
||||
type: this.plug.type,
|
||||
model: this.plug.model,
|
||||
capabilities: this.plug.capabilities,
|
||||
address: this.plug.address,
|
||||
port: this.plug.port,
|
||||
power: this.plug.power(),
|
||||
state: state
|
||||
}
|
||||
};
|
||||
this.send(status);
|
||||
}
|
||||
};
|
||||
|
||||
var delayedStatusMsgUpdate = function() {
|
||||
delayedStatusMsgTimer = setTimeout(function() {
|
||||
if (node.plug.power()['0']) {
|
||||
var delayedStatusMsgUpdate = () => {
|
||||
delayedStatusMsgTimer = setTimeout(() => {
|
||||
if (this.plug.power()['0']) {
|
||||
setState("on");
|
||||
} else {
|
||||
setState("off");
|
||||
@@ -112,12 +90,12 @@ module.exports = function(RED) {
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
var discoverDevice = function() {
|
||||
miio.device({address: node.ip})
|
||||
.then(function (plug) {
|
||||
if (node.plug == null) {
|
||||
node.plug = plug;
|
||||
node.plug.on('propertyChanged', function(e) {
|
||||
var discoverDevice = () => {
|
||||
miio.device({address: this.ip})
|
||||
.then((plug) => {
|
||||
if (this.plug == null) {
|
||||
this.plug = plug;
|
||||
this.plug.on('propertyChanged', (e) => {
|
||||
if (e.property === "power") {
|
||||
if (e.value['0']) {
|
||||
setState("on");
|
||||
@@ -128,28 +106,30 @@ module.exports = function(RED) {
|
||||
});
|
||||
}
|
||||
if (connectionState === "reconnecting") {
|
||||
node.status({fill:"green", shape:"dot", text:"connected"});
|
||||
this.status({fill:"green", shape:"dot", text:"connected"});
|
||||
connectionState = "connected";
|
||||
delayedStatusMsgUpdate();
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
.catch((error) => {
|
||||
connectionState = "reconnecting";
|
||||
if (node.plug) {
|
||||
node.plug.destroy();
|
||||
node.plug = null;
|
||||
if (this.plug) {
|
||||
this.plug.destroy();
|
||||
this.plug = null;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
var watchdog = function() {
|
||||
setTimeout(function retryTimer() {
|
||||
var watchdog = () => {
|
||||
var node = this;
|
||||
function retryTimer() {
|
||||
discoverDevice();
|
||||
if (connectionState === "reconnecting") {
|
||||
node.status({fill: "red", shape: "dot", text: "reconnecting"});
|
||||
}
|
||||
setTimeout(retryTimer, 30000);
|
||||
}, 30000);
|
||||
}
|
||||
setTimeout(retryTimer, 30000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
output: {value: "0"}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 2,
|
||||
outputLabels: ["Status","Control"],
|
||||
outputs: 1,
|
||||
paletteLabel: "plug (zigbee)",
|
||||
icon: "outlet-icon.png",
|
||||
label: function () {
|
||||
@@ -26,14 +25,6 @@
|
||||
// Get the config node using the ID:
|
||||
var configNode = RED.nodes.node(configNodeID);
|
||||
|
||||
$("#node-input-output").change(function () {
|
||||
if ($(this).val() == "2") {
|
||||
$(".node-input-msg").show();
|
||||
} else {
|
||||
$(".node-input-msg").hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#node-input-gateway").change(function () {
|
||||
|
||||
});
|
||||
@@ -66,22 +57,6 @@
|
||||
<label for="node-input-sid"><i class="icon-tag"></i> Device</label>
|
||||
<select id="node-input-sid" placeholder="xiaomi gateway"></select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-output"><i class="icon-tag"></i> Output</label>
|
||||
<select id="node-input-output" style="width:70%;">
|
||||
<option value="0">Full data</option>
|
||||
<option value="1">Just values</option>
|
||||
<option value="2">Template</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-onmsg"><i class="fa fa-power-off"></i> On msg</label>
|
||||
<input type="text" id="node-input-onmsg">
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-offmsg"><i class="fa fa-power-off"></i> Off msg</label>
|
||||
<input type="text" id="node-input-offmsg">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xiaomi-plug">
|
||||
@@ -115,41 +90,22 @@
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h3>Details</h3>
|
||||
<h4>Details</h4>
|
||||
<p>The incoming json message is parsed if the type model is <code>plug</code> and
|
||||
the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>On the input you can send the string <code>on</code> to switch the plug on. To turn it off just send the string <code>off</code></p>
|
||||
<p>Output 1 reports the status, output 2 is the write command for the plug.</p>
|
||||
|
||||
<p>Three output types are supported:
|
||||
<ul>
|
||||
<li>Full data</li>
|
||||
<li>Just values</li>
|
||||
<li>Template</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h4>Full data</h4>
|
||||
<p>Passes the complete json object received from the gateway on output 1. Use this if you need the raw data.</p>
|
||||
<h4>Just values</h4>
|
||||
<p>Only passes the values <code>on</code> or <code>off</code> on output 1.</p>
|
||||
<h4>Template</h4>
|
||||
<p>Use your own template to pass the values on. The template can contain <a href="http://mustache.github.io/mustache.5.html">mustache-style</a> tags.
|
||||
Any property from the data section of the full object can be used.</p>
|
||||
|
||||
<p>Sample message:</p>
|
||||
<p><pre>
|
||||
{
|
||||
cmd: "write_ack"
|
||||
model: "plug"
|
||||
sid: "158d00012f1fb5"
|
||||
short_id: 47414
|
||||
data: "{
|
||||
"voltage":3600,
|
||||
"status":"off",
|
||||
"inuse":"0",
|
||||
"power_consumed":"4000",
|
||||
"load_power":"0"
|
||||
}"
|
||||
}</pre></p>
|
||||
<p><pre>{
|
||||
cmd: "write_ack"
|
||||
model: "plug"
|
||||
sid: "158d00012f1fb5"
|
||||
short_id: 47414
|
||||
data: {
|
||||
voltage:3600,
|
||||
status:"off",
|
||||
inuse:"0",
|
||||
power_consumed:"4000",
|
||||
load_power:"0"
|
||||
}
|
||||
}</pre></p>
|
||||
</script>
|
||||
|
||||
@@ -1,26 +1,19 @@
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
var crypto = require("crypto");
|
||||
const crypto = require("crypto");
|
||||
|
||||
module.exports = (RED) => {
|
||||
function XiaomiPlugNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.gateway = RED.nodes.getNode(config.gateway);
|
||||
this.sid = config.sid;
|
||||
this.output = config.output;
|
||||
this.onmsg = config.onmsg;
|
||||
this.offmsg = config.offmsg;
|
||||
this.key = this.gateway.key;
|
||||
|
||||
var node = this;
|
||||
var currentToken = "";
|
||||
var state = "";
|
||||
|
||||
node.status({fill:"yellow", shape:"ring", text:"waiting for key"});
|
||||
this.status({fill:"yellow", shape:"ring", text:"waiting for key"});
|
||||
|
||||
if (this.gateway && this.key != "") {
|
||||
node.on('input', function(msg) {
|
||||
// var payload = JSON.parse(msg);
|
||||
this.on('input', (msg) => {
|
||||
var payload = msg.payload;
|
||||
|
||||
if (payload.cmd == "heartbeat" && payload.model == "gateway") {
|
||||
@@ -70,37 +63,12 @@ module.exports = function(RED) {
|
||||
state = "off";
|
||||
}
|
||||
|
||||
if (node.output == "0") {
|
||||
msg.payload = payload;
|
||||
node.send([msg]);
|
||||
} else if (node.output == "1") {
|
||||
var status = null;
|
||||
|
||||
if (data.status) {
|
||||
status = {"payload": data.status};
|
||||
}
|
||||
node.send([status]);
|
||||
} else if (node.output == "2") {
|
||||
var status = null;
|
||||
|
||||
if (data.status === 'on') {
|
||||
status = {"payload": mustache.render(node.onmsg, data)}
|
||||
} else {
|
||||
status = {"payload": mustache.render(node.offmsg, data)}
|
||||
}
|
||||
node.send([status]);
|
||||
}
|
||||
msg.payload = payload;
|
||||
node.send([msg]);
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
});
|
||||
|
||||
} else {
|
||||
// no gateway configured
|
||||
if (this.key == "") {
|
||||
node.status({fill:"red", shape:"dot", text:"no key configured"});
|
||||
}
|
||||
} else if (this.key == "") {
|
||||
node.status({fill:"red", shape:"dot", text:"no key configured"});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
output: {value: "0"}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 2,
|
||||
outputLabels: ["Single-click", "Double-click"],
|
||||
outputs: 1,
|
||||
paletteLabel: "switch",
|
||||
icon: "light-icon.png",
|
||||
label: function () {
|
||||
@@ -53,14 +52,6 @@
|
||||
changeGateway("switch");
|
||||
});
|
||||
|
||||
$("#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);
|
||||
},
|
||||
@@ -84,22 +75,6 @@
|
||||
<label for="node-input-sid"><i class="icon-tag"></i> Device</label>
|
||||
<select id="node-input-sid" placeholder="xiaomi gateway"></select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-output"><i class="icon-tag"></i> Output</label>
|
||||
<select id="node-input-output" style="width:70%;">
|
||||
<option value="0">Full data</option>
|
||||
<option value="1">Just values</option>
|
||||
<option value="2">Template</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-outmsg"><i class="fa fa-hand-pointer-o"></i> Single-click</label>
|
||||
<input type="text" id="node-input-outmsg">
|
||||
</div>
|
||||
<div class="form-row node-input-msg">
|
||||
<label for="node-input-outmsgdbcl"><i class="fa fa-hand-peace-o"></i> Double-click</label>
|
||||
<input type="text" id="node-input-outmsgdbcl">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xiaomi-switch">
|
||||
@@ -115,49 +90,24 @@
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<ol class="node-ports">
|
||||
<li>Single click output
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string | json</span></dt>
|
||||
<dd>raw data, value or template.</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>Double click output
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string | json</span></dt>
|
||||
<dd>raw data, value or template.</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">object</span></dt>
|
||||
<dd>Data from gateway, see below.</dd>
|
||||
</dl>
|
||||
</ol>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>The incoming json message is parsed if the type model is <code>switch</code> or <code>sensor_switch.aq2</code> and
|
||||
the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>Three output types are supported:
|
||||
<ul>
|
||||
<li>Full data</li>
|
||||
<li>Just values</li>
|
||||
<li>Template</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h4>Full data</h4>
|
||||
<p>Passes the complete json object received from the gateway on output 1. Use this if you need the raw data.</p>
|
||||
<h4>Just values</h4>
|
||||
<p>Only passes the string values <code>single_click</code> on output 1 and <code>double_click</code> on output 2.</p>
|
||||
<h4>Template</h4>
|
||||
<p>Use your own template to pass the values on. The template can contain <a href="http://mustache.github.io/mustache.5.html">mustache-style</a> tags.
|
||||
Any property from the data section of the full object can be used.</p>
|
||||
|
||||
<h4>Details</h4>
|
||||
<p>The incoming message is processed if the <code>sid</code> matches the configured value for this device.</p>
|
||||
<p>Sample message:</p>
|
||||
<p><pre>
|
||||
{
|
||||
cmd: "report"
|
||||
model: "switch"
|
||||
sid: "158d000128b124"
|
||||
short_id: 56773
|
||||
data: "{
|
||||
"status":"click"
|
||||
}"
|
||||
}</pre></p>
|
||||
<p><pre>{
|
||||
cmd: "report"
|
||||
model: "switch"
|
||||
sid: "158d000128b124"
|
||||
short_id: 56773
|
||||
data: {
|
||||
status: "click",
|
||||
batteryLevel: 23
|
||||
}
|
||||
}</pre></p>
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,71 +1,8 @@
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
var miDevicesUtils = require('../utils');
|
||||
const miDevicesUtils = require('../src/utils');
|
||||
|
||||
module.exports = (RED) => {
|
||||
function XiaomiSwitchNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.gateway = RED.nodes.getNode(config.gateway);
|
||||
this.sid = config.sid;
|
||||
this.output = config.output;
|
||||
this.outmsg = config.outmsg;
|
||||
this.outmsgdbcl = config.outmsgdbcl;
|
||||
|
||||
var node = this;
|
||||
|
||||
node.status({fill:"grey", shape:"ring", text:"battery - na"});
|
||||
|
||||
if (this.gateway) {
|
||||
node.on('input', function(msg) {
|
||||
// var payload = JSON.parse(msg);
|
||||
var payload = msg.payload;
|
||||
|
||||
// Input from gateway
|
||||
if (payload.sid) {
|
||||
if (payload.sid == node.sid && ["switch", "sensor_switch.aq2"].indexOf(payload.model) >= 0) {
|
||||
var data = payload.data;
|
||||
miDevicesUtils.setStatus(node, data);
|
||||
|
||||
if (node.output == "0") {
|
||||
node.send([msg]);
|
||||
} else if (node.output == "1") {
|
||||
var status = null;
|
||||
|
||||
if (data.status) {
|
||||
status = {"payload": data.status};
|
||||
}
|
||||
node.send([status]);
|
||||
} else if (node.output == "2") {
|
||||
var status = null;
|
||||
|
||||
if (data.status && data.status == "click") {
|
||||
status = {"payload": mustache.render(node.outmsg, data)}
|
||||
node.send([[status],[]]);
|
||||
}
|
||||
|
||||
if (data.status && data.status == "double_click") {
|
||||
status = {"payload": mustache.render(node.outmsgdbcl, data)}
|
||||
node.send([[],[status]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Prepare for request
|
||||
else {
|
||||
miDevicesUtils.prepareForGatewayRequest(node, msg);
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
});
|
||||
|
||||
} else {
|
||||
// no gateway configured
|
||||
}
|
||||
|
||||
miDevicesUtils.defaultNode(RED, config, this);
|
||||
}
|
||||
|
||||
RED.nodes.registerType("xiaomi-switch", XiaomiSwitchNode);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red-contrib-mi-devices",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "A set of nodes to control some of the popular Xiaomi sensors which are connected to the Xiaomi Gateway, and the Gateway itself.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -32,7 +32,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"cryptojs": "^2.5.3",
|
||||
"mustache": "^2.3.0",
|
||||
"miio": "0.13.0"
|
||||
},
|
||||
"engines": {
|
||||
"node" : ">=4.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ module.exports = {
|
||||
When full, CR2032 batteries are between 3 and 3.4V
|
||||
http://farnell.com/datasheets/1496885.pdf
|
||||
*/
|
||||
return Math.min(Math.round((voltage - 2200) / 14), 100);
|
||||
return Math.min(Math.round((voltage - 2200) / 10), 100);
|
||||
},
|
||||
setStatus: function(node, data) {
|
||||
if (data.voltage) {
|
||||
@@ -39,6 +39,18 @@ module.exports = {
|
||||
|
||||
return key;
|
||||
},
|
||||
sendWritePayloadToGateway: function(node, msg, data) {
|
||||
let gateway = node.gateway;
|
||||
if(gateway && gateway.sid && gateway.key && gateway.lastToken) {
|
||||
data.sid = data.sid || gateway.sid;
|
||||
data.key = this.getGatewayKey(gateway.key, gateway.lastToken);
|
||||
msg.payload = {
|
||||
cmd: "write",
|
||||
data: data
|
||||
};
|
||||
node.send(msg);
|
||||
}
|
||||
},
|
||||
prepareForGatewayRequest: function(node, msg) {
|
||||
msg.sid = node.sid;
|
||||
msg.gateway = node.gateway;
|
||||
@@ -64,5 +76,31 @@ module.exports = {
|
||||
brightness: brightness,
|
||||
color: { red: red, green: green, blue: blue }
|
||||
};
|
||||
},
|
||||
defaultNode: function(RED, config, node) {
|
||||
RED.nodes.createNode(node, config);
|
||||
node.gateway = RED.nodes.getNode(config.gateway);
|
||||
node.sid = config.sid;
|
||||
|
||||
node.status({fill:"grey", shape:"ring", text:"battery - na"});
|
||||
|
||||
if (node.gateway) {
|
||||
node.on('input', (msg) => {
|
||||
let payload = msg.payload;
|
||||
|
||||
// Input from gateway
|
||||
if (payload.sid) {
|
||||
if (payload.sid == node.sid) {
|
||||
miDevicesUtils.setStatus(node, payload.data);
|
||||
node.send([msg]);
|
||||
}
|
||||
}
|
||||
// Prepare for request
|
||||
else {
|
||||
miDevicesUtils.prepareForGatewayRequest(node, msg);
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user