Skip to content

Commit

Permalink
map
Browse files Browse the repository at this point in the history
  • Loading branch information
andreypopov committed May 8, 2020
1 parent ef8b0d8 commit 6109fdd
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 3 deletions.
25 changes: 25 additions & 0 deletions api.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,29 @@ module.exports = function(RED) {
res.status(404).end();
}
});

RED.httpAdmin.get(NODE_PATH + 'refreshMap', function (req, res) {
var config = req.query;
var controller = RED.nodes.getNode(config.controllerID);
if (controller && controller.constructor.name === "ServerNode") {
controller.refreshMap(true).then(function(response){
res.json(response);
}).catch(error => {
res.status(404).end();
});
} else {
res.status(404).end();
}
});
RED.httpAdmin.get(NODE_PATH + 'showMap', function (req, res) {
var config = req.query;
var controller = RED.nodes.getNode(config.controllerID);
if (controller && controller.constructor.name === "ServerNode") {
var response = controller.map;
res.writeHead(200, {'Content-Type': 'image/svg+xml'});
res.end(response); // Send the file data to the browser.
} else {
res.status(404).end();
}
});
}
38 changes: 38 additions & 0 deletions nodes/bridge.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@
<ol id="node-input-groups-container"></ol>
</div>
</div>


<div id="node-z2m-tab-map" class="node-z2m-tab-map" style="position: relative; margin-top: 30px;">
<a href="#" id="z2m_map_refresh_btn" class="red-ui-item-add red-ui-button"><i class="fa fa-refresh"></i>&nbsp;<span data-i18n="map.refresh"></span></a>
<a href="#" id="z2m_map_fullscreen_btn" style="display:none;" class="red-ui-item-add red-ui-button"><i class="fa fa-external-link"></i>&nbsp;<span data-i18n="map.fullscreen"></span></a>
<div id="z2m_map_img"></div>
</div>
</div>
</div>
</script>
Expand Down Expand Up @@ -150,6 +157,10 @@
id: "node-z2m-tab-groups",
label: RED._("node-red-contrib-zigbee2mqtt/bridge:tabs.groups")
});
node.tabs.addTab({
id: "node-z2m-tab-map",
label: RED._("node-red-contrib-zigbee2mqtt/bridge:tabs.map")
});

$('#refreshBtn').on("click", function(){
init(true);
Expand Down Expand Up @@ -235,6 +246,33 @@
});
});

$('#z2m_map_refresh_btn').off('click').on('click', function () {
var $btn = $(this);
$('#z2m_map_img').html('');
$btn.find('.fa-refresh').addClass('fa-spin');
$btn.find('span').text(RED._("node-red-contrib-zigbee2mqtt/bridge:map.loading"));
$('#z2m_map_fullscreen_btn').hide();
$.getJSON('zigbee2mqtt/refreshMap', {
controllerID: node.server
}).done(function (data, textStatus, jqXHR) {
$btn.find('.fa-refresh').removeClass('fa-spin');
$btn.find('span').text(RED._("node-red-contrib-zigbee2mqtt/bridge:map.refresh"));
$('#z2m_map_fullscreen_btn').show();
$('#z2m_map_img').html(data.svg).find('svg').attr('width','100%').attr('height','100%');
});
});
$('#z2m_map_fullscreen_btn').off('click').on('click', function () {
var url = '/zigbee2mqtt/showMap?controllerID='+node.server;

var win = window.open(url, '_blank');
if (win) {
//Browser has allowed it to be opened
win.focus();
} else {
//Browser has blocked it
alert('Please allow popups for this website');
}
});

$.getJSON('zigbee2mqtt/getDevices', {
controllerID: node.server,
Expand Down
2 changes: 2 additions & 0 deletions nodes/bridge.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const Zigbee2mqttHelper = require('../lib/Zigbee2mqttHelper.js');
var mqtt = require('mqtt');


module.exports = function(RED) {

class Zigbee2mqttNodeBridge {
constructor(config) {

Expand Down
8 changes: 7 additions & 1 deletion nodes/locales/en-US/bridge.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"tabs": {
"bridge": "Bridge",
"devices": "Devices",
"groups": "Groups"
"groups": "Groups",
"map": "Map"
},
"devices": {
"ieee_addr": "IeeeAddr",
Expand All @@ -52,6 +53,11 @@
"enter_group_name": "Enter group name",
"sure_remove": "Are you sure you want to remove group?"
},
"map": {
"refresh": "Refresh map",
"fullscreen": "Open in full screen",
"loading": "Loading..."
},
"tokeninput": {
"searching": "Searching...",
"type_to_search": "Type to search device",
Expand Down
89 changes: 89 additions & 0 deletions nodes/server.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const Zigbee2mqttHelper = require('../lib/Zigbee2mqttHelper.js');
var mqtt = require('mqtt');
var Viz = require('viz.js');
var { Module, render } = require('viz.js/full.render.js');

module.exports = function (RED) {
class ServerNode{
Expand All @@ -16,6 +18,7 @@ module.exports = function (RED) {
node.devices_values = [];
node.bridge_config = null;
node.bridge_state = null;
node.map = null;
node.on('close', () => this.onClose());
node.setMaxListeners(0);

Expand Down Expand Up @@ -392,6 +395,90 @@ module.exports = function (RED) {
return {"success":true,"description":"command sent"};
}

refreshMap(wait = false) {
var node = this;

return new Promise(function (resolve, reject) {
if (wait) {
var timeout = null;
var timeout_ms = 60000 * 5;

var options = {
port: node.config.mqtt_port || 1883,
username: node.config.mqtt_username || null,
password: node.config.mqtt_password || null,
clientId: "NodeRed-tmp2-" + node.id
};
var client = mqtt.connect('mqtt://' + node.config.host, options);

client.on('connect', function () {

//end function after timeout, if now response
timeout = setTimeout(function () {
client.end(true);
}, timeout_ms);
client.subscribe(node.getBaseTopic() + "/bridge/networkmap/graphviz", function (err) {
if (!err) {
client.publish(node.getBaseTopic() + "/bridge/networkmap", 'graphviz');
node.log('Refreshing map and waiting...');
} else {
RED.log.error("zigbee2mqtt: error code #0023: " + err);
client.end(true);
reject({'success':false, 'description':'zigbee2mqtt: error code #0023'});
}
})
});

client.on('error', function (error) {
RED.log.error("zigbee2mqtt: error code #0024: " + error);
client.end(true);
reject({'success':false, 'description':'zigbee2mqtt: error code #0024'});
});

client.on('end', function (error, s) {
clearTimeout(timeout);
});

client.on('message', function (topic, message) {
if (node.getBaseTopic() + "/bridge/networkmap/graphviz" == topic) {

var messageString = message.toString();
node.graphviz(messageString).then(function (data) {
resolve({"success": true, "svg": node.map});
}).catch(error => {
reject({'success':false, 'description':'graphviz failed'});
});
client.end(true);
}
})
} else {
node.mqtt.publish(node.getBaseTopic() + "/bridge/networkmap", 'graphviz');
node.log('Refreshing map...');

resolve({"success": true, "svg": node.map});
}
});
}

graphviz(payload) {
var node = this;

return new Promise(function (resolve, reject) {
var options = {
format: 'svg',
engine: 'circo'
};
var viz = new Viz({ Module, render });
viz.renderString(payload,options).then(result => {
node.map = result;
resolve(result);
}).catch(error => {
console.error(error);
reject(error);
});
});
}

onMQTTConnect() {
var node = this;
node.connection = true;
Expand Down Expand Up @@ -495,6 +582,8 @@ module.exports = function (RED) {
}
}
}
} else if (node.getBaseTopic() + '/bridge/networkmap/graphviz' == topic) {
node.graphviz(messageString);
}


Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"eventsource": "^0.2.1",
"mqtt": "^2.18.8",
"multiple-select": "^1.4.1",
"request": "^2.81.0"
"request": "^2.81.0",
"viz.js": "^2.1.2"
},
"deprecated": false,
"description": "Zigbee2mqtt connectivity nodes for node-red",
Expand All @@ -38,5 +39,5 @@
"type": "git",
"url": "git+https://github.com/andreypopov/node-red-contrib-zigbee2mqtt.git"
},
"version": "0.3.2"
"version": "0.4.0"
}

0 comments on commit 6109fdd

Please sign in to comment.