Compare commits

..

No commits in common. "8cb33997fa0b91170a208a40d7c124d3c30b6002" and "2b84618d1e8ed8bfe0bef958cdebd3f489c6cac3" have entirely different histories.

11 changed files with 403 additions and 33 deletions

View File

@ -6,9 +6,6 @@ Entstanden im Oktober 2013 von Lucas als bastelprojekt im mal etwas mit
NodeJS zu machen. Damals mit express, und SpaceAPI Support. Es wurde NodeJS zu machen. Damals mit express, und SpaceAPI Support. Es wurde
der Switch im Raum gepingt um zu schauen ob der Raum "auf" ist. der Switch im Raum gepingt um zu schauen ob der Raum "auf" ist.
Das ganze wurde mit Angular (1) und ExpressJS gebaut. Es werden die Daten
live via Websockets zwischen Server und Browser übertragen.
Via nmap Scan im Raum wurde die Anzahl von Geräten ermittelt und angezeigt. Via nmap Scan im Raum wurde die Anzahl von Geräten ermittelt und angezeigt.
Später erfolgte ein Umbau auf SNMP. Es wurde der Router gefragt welche Später erfolgte ein Umbau auf SNMP. Es wurde der Router gefragt welche
Mac Adressen Online sind, so wurde eine Optionale User-Liste im Status Mac Adressen Online sind, so wurde eine Optionale User-Liste im Status
@ -22,12 +19,3 @@ Tunix kam dazu und stellte schöne Icons und machts kleinere Verbesserungen,
Fionera fügte HTML5 Push notifications hinzu. Fionera fügte HTML5 Push notifications hinzu.
Danach kleinere Änderungen und Erweiterungen von henne, zeus, smash. Danach kleinere Änderungen und Erweiterungen von henne, zeus, smash.
## Entrümpelung 2022
Das meiste an Funktionn wurde wiede raus geworfen weil sich die CTDO infrastruktur
sehr verändert hat und einiges kaputt war.
Der Status zeit nur noch Power und Raumstatus an. Es läuft wie gehabt via nmap-Ping.

View File

@ -4,22 +4,19 @@ var request = require('request');
var Flukso = function(hostname, pathname) { var Flukso = function(hostname, pathname) {
var self = this; var self = this;
var regexp = /([0-9]+)\]\]$/; // /\(([0-9]+) hosts* up\)/;
this.pollPower = function() { this.pollPower = function() {
request({url: "http://" + hostname + pathname}, function(error, res, response) { request({url: "http://" + hostname + pathname}, function(error, res, response) {
if (error) { if (error) {
self.emit('failed', error) self.emit('failed', error)
} else { } else {
var matches = regexp.exec(response);
try { if(matches != null && matches.length == 2) {
var jsondata = JSON.parse(response); var time = Date.now();
var power = jsondata[jsondata.length-1][1]; var num = matches[1];
self.emit('done', parseInt(num));
self.emit('done', parseInt(power));
} catch(err) {
console.log("error parsing fluxo data");
} }
} }
}); });
}; };

View File

@ -1,20 +1,50 @@
//var redis = require("redis");
var util = require('util'); var util = require('util');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var exec = require('child_process').exec; var exec = require('child_process').exec;
var moment = require('moment');
var redisprefix = "ippoll:";
var IpPoll = function(switchaddr, hostsaddr) { var IpPoll = function(switchaddr, hostsaddr) {
var self = this; var self = this;
// var redisClient = redis.createClient();
var regexp = /\(([0-9]+) hosts* up\)/; var regexp = /\(([0-9]+) hosts* up\)/;
var nmap = "nmap -n -sP "; var nmap = "nmap -n -sP ";
/*
redisClient.on("connect", function () {
console.log("IP-Poll: connected to redis");
self.emit('ready');
});
this.pollCount = function() {
exec(nmap + "--min-hostgroup 10 " + hostsaddr, function (error, stdout, stderr) {
if(error == null) {
var matches = regexp.exec(stdout);
if(matches != null && matches.length == 2) {
var time = Date.now();
redisClient.zremrangebyscore(redisprefix + 'onlinecount', "-inf", time - 7*24*60*1000);
var num = matches[1];
redisClient.zadd(redisprefix + 'onlinecount', time, time + "|" + num, function() {
self.emit('doneCount', parseInt(num));
});
}
}
});
};*/
this.pollState = function() { this.pollState = function() {
exec(nmap + switchaddr, function (error, stdout, stderr) { exec(nmap + switchaddr, function (error, stdout, stderr) {
if(error == null) { if(error == null) {
var matches = regexp.exec(stdout); var matches = regexp.exec(stdout);
if(matches != null && matches.length === 2) { if(matches != null && matches.length == 2) {
self.emit('doneState', matches[1] === "1"); self.emit('doneState', matches[1] == "1");
} }
} else { } else {
self.emit('doneState', "unknown"); self.emit('doneState', "unknown");
@ -22,7 +52,22 @@ var IpPoll = function(switchaddr, hostsaddr) {
}); });
}; };
/*
this.getHistory = function(start, end, callback) {
redisClient.zrangebyscore(redisprefix + 'onlinecount', "-inf", "+inf", function(err, replies) {
var data = [];
replies.forEach(function (reply, i) {
var line = reply.split('|');
data.push( { at: moment(parseInt(line[0])).format(), value: line[1] });
});
callback(data);
});
};*/
}; };
util.inherits(IpPoll, EventEmitter); util.inherits(IpPoll, EventEmitter);
module.exports = IpPoll; module.exports = IpPoll;

25
public/css/ink-ie7-min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -31,6 +31,12 @@ h2 {
margin-bottom: 0.7em; margin-bottom: 0.7em;
} }
#graph {
max-width: 400px;
height: 200px;
margin-top: 0;
}
#gauge { #gauge {
width: 290px; width: 290px;
height: 200px; height: 200px;
@ -38,12 +44,75 @@ h2 {
margin: 0; margin: 0;
} }
a:focus { .btn-block {
margin-top: 5px;
}
.btn-danger.focus, .btn-danger:focus {
color: #FFF;
background-color: #C9302C;
border-color: #761C19;
}
.btn.focus, .btn:focus, .btn:hover {
color: #333;
text-decoration: none;
}
.btn.active.focus, .btn.active:focus, .btn.focus, .btn.focus:active, .btn:active:focus, .btn:focus {
outline: thin dotted; outline: thin dotted;
outline-offset: -2px; outline-offset: -2px;
}
}
a:focus {
outline: thin dotted;
outline-offset: -2px;
}
a:focus, a:hover { a:focus, a:hover {
color: #23527C; color: #23527C;
text-decoration: underline; text-decoration: underline;
}
.btn-block {
display: block;
width: 100%;
}
.btn-danger {
color: #FFF;
background-color: #D9534F;
border-color: #D43F3A;
}
.btn-success {
color: #FFF;
background-color: #5CB85C;
border-color: #4CAE4C;
}
.btn {
display: inline-block;
padding: 6px 12px;
margin-bottom: 0px;
font-size: 14px;
font-weight: 400;
line-height: 1.42857;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
-moz-user-select: none;
background-image: none;
border: 1px solid transparent;
border-radius: 4px;
} }

View File

@ -5,7 +5,6 @@ var gpower;
angular.module('roomstateapp.controllers', []). angular.module('roomstateapp.controllers', []).
controller('StatusCtrl', function ($scope, $http, Socket) { controller('StatusCtrl', function ($scope, $http, Socket) {
// on page load request current data via simple API.
$http({ $http({
method: 'GET', method: 'GET',
url: '/api/simple/v2' url: '/api/simple/v2'
@ -19,9 +18,8 @@ angular.module('roomstateapp.controllers', []).
console.log("error getting data"); console.log("error getting data");
}); });
// while page is loaded, new data will arrive via Websocket.
Socket.on('sdata', function(message) { Socket.on('sdata', function(message) {
console.log("received data from server: " + JSON.stringify(message.data)); console.log("received data from server: " + message.data.names);
$scope.simple = message.data; $scope.simple = message.data;
gpower.refresh(message.data.power); gpower.refresh(message.data.power);
}); });
@ -63,7 +61,7 @@ angular.module('roomstateapp.services', []).
angular.module('roomstateapp.statusfilter', []).filter('statustostring', function() { angular.module('roomstateapp.statusfilter', []).filter('statustostring', function() {
return function(input) { return function(input) {
return input === true ? 'geöffnet' : input === false ? 'geschlossen' : 'unbekannt'; return input == true ? 'geöffnet' : input == false ? 'geschlossen' : 'unbekannt';
}; };
}); });

89
public/js/vendor/autoload.js vendored Normal file
View File

@ -0,0 +1,89 @@
( function(){
var autoload = {
/***************************
* DatePicker - Default CSS selector is .ink-datepicker
***************************/
'DatePicker_1': '.ink-datepicker',
/***************************
* Gallery - Default CSS selector is ul.ink-gallery-source
***************************/
'Gallery_1': 'ul.ink-gallery-source',
/***************************
* Modal - Default CSS selector is .ink-modal
***************************/
'Modal_1': '.ink-modal',
/***************************
* ProgressBar - Default CSS selector is .ink-progress-bar
***************************/
'ProgressBar_1': '.ink-progress-bar',
/***************************
* SortableList - Default CSS selector is .ink-sortable-list
***************************/
'SortableList_1': '.ink-sortable-list',
/***************************
* Spy - Default CSS selector is *[data-spy="true"]
***************************/
'Spy_1': '*[data-spy="true"]',
/***************************
* Sticky - Default CSS selector is .ink-navigation.sticky
***************************/
'Sticky_1': '.ink-navigation.sticky',
/***************************
* Table - Default CSS selector is .ink-table
***************************/
'Table_1': '.ink-table',
/***************************
* Tabs - Default CSS selector is .ink-tabs
***************************/
'Tabs_1': '.ink-tabs',
/***************************
* TreeView - Default CSS selector is .ink-tree-view
***************************/
'TreeView_1': '.ink-tree-view',
/***************************
* Toggle - Default CSS selector is .toggle
***************************/
'Toggle_1': '.toggle',
/***************************
* Tooltip - Default CSS selector is .tooltip
***************************/
'Tooltip_1': '.tooltip'
};
Ink.requireModules(['Ink.Dom.Selector_1', 'Ink.Dom.Loaded_1', 'Ink.Util.Array_1', 'Ink.UI.SmoothScroller_1', 'Ink.UI.Close_1'],
function( Selector, Loaded, InkArray, Scroller, Close ){
var elements;
var fn = function( Component ) {
InkArray.each(elements, function( element ){
new Component(element);
});
};
Loaded.run(function(){
for( var mod in autoload ){
if( !autoload.hasOwnProperty(mod) ){
continue;
}
elements = Selector.select( autoload[mod] );
if( elements.length ){
Ink.requireModules( ['Ink.UI.' + mod ], fn);
}
}
Scroller.init();
new Close();
});
});
})();

108
snmp-mac.js Normal file
View File

@ -0,0 +1,108 @@
var redis = require("redis");
var snmp = require("net-snmp");
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var _u = require("underscore");
var redisprefix = "mac:";
var SnmpMac = function(hostname, community) {
var self = this;
var redisClient = redis.createClient();
var session = snmp.createSession(hostname, community, { version: snmp.Version2c } );
var baseoid = "1.3.6.1.2.1.17.7.1.2.2.1.3";
var regexp = /([0-9]+).([0-9]+).([0-9]+).([0-9]+).([0-9]+).([0-9]+)$/;
var names = [];
redisClient.on("connect", function () {
//redisClient.set(redisprefix + "00:80:a3:91:39:1c","ripe-atlas-probe");
//redisClient.set(redisprefix + "d4:ca:6d:33:cf:79","routerboard");
console.log("SNMP-MAC: connected to redis");
self.emit('ready');
});
redisClient.on('error', function(err) {
console.log("redis error: " + err);
});
function getMacFromOID(oid, callback) {
var matches = regexp.exec(oid);
var mac = "";
if(matches != null) {
for(var i = 1; i < matches.length; i++) {
var num = parseInt(matches[i]);
if(num <= 15) mac += "0";
mac += num.toString(16) + ":";
}
mac = mac.substr(0, mac.length-1);
callback(mac);
}
}
function doneCb(error) {
if (error)
console.error(error.toString ());
self.emit('done', _u.uniq(names));
}
function feedCb(varbinds) {
for (var i = 0; i < varbinds.length; i++) {
if (snmp.isVarbindError(varbinds[i])) {
console.error(snmp.varbindError (varbinds[i]));
} else {
if(varbinds[i].value == "3") { // only valid arp entries
getMacFromOID(varbinds[i].oid, function(mac) {
// console.log(mac);
redisClient.get(redisprefix + mac, function(err, reply) {
if(reply != null) {
if (reply.split('')[0] == '"' && reply.split('')[reply.split('').length -1] == '"') {
var name = "";
for (var i = 1; i < reply.split('').length - 1; i++){
name += reply.split('')[i]
}
names.push(name)
} else {
names.push(reply);
}
}
});
});
}
}
}
}
this.poll = function() {
names.length = 0;
session.subtree(baseoid, 20, feedCb, doneCb);
};
this.stop = function() {
redisClient.quit();
};
this.add = function (mac, name, callback) {
redisClient.set(redisprefix + mac, name, function (err) {
if(typeof callback === "function") callback(err);
});
};
this.delete = function(mac, callback) {
redisClient.del(redisprefix + mac, function(err) {
if(typeof callback === "function") callback(err);
});
};
};
util.inherits(SnmpMac, EventEmitter);
module.exports = SnmpMac;

View File

@ -79,7 +79,6 @@ ippoll.on('doneState', function (state) {
simpleanswer.lastchange = spaceanswer.state.lastchange; simpleanswer.lastchange = spaceanswer.state.lastchange;
simpleanswer.lastchange = new Date().getTime(); simpleanswer.lastchange = new Date().getTime();
io.sockets.emit('sdata', {data: simpleanswer}); io.sockets.emit('sdata', {data: simpleanswer});
console.log("room state changed: " + JSON.stringify(simpleanswer))
}); });
flukso.on('done', function (num) { flukso.on('done', function (num) {
@ -140,9 +139,9 @@ app.get('/api/simple/v2', function (req, res) {
function getstatusImage(req, res) { function getstatusImage(req, res) {
if (spaceanswer.state.open === true) { if (spaceanswer.state.open == true) {
res.sendFile(path.resolve(__dirname, 'public/img/green.png')); res.sendFile(path.resolve(__dirname, 'public/img/green.png'));
} else if (spaceanswer.state.open === false) { } else if (spaceanswer.state.open == false) {
res.sendFile(path.resolve(__dirname, 'public/img/red.png')); res.sendFile(path.resolve(__dirname, 'public/img/red.png'));
} else { } else {
res.sendFile(path.resolve(__dirname, 'public/img/yellow.png')); res.sendFile(path.resolve(__dirname, 'public/img/yellow.png'));

50
test.js Normal file
View File

@ -0,0 +1,50 @@
var moment = require("moment");
var snmp = require("net-snmp");
var baseoid = "1.3.6.1.2.1.17.7.1.2.2.1.3";
var regexp = /([0-9]+).([0-9]+).([0-9]+).([0-9]+).([0-9]+).([0-9]+)$/;
var session = snmp.createSession("juni.ctdo.de", "ctdo23", { version: snmp.Version2c } )
function getMacFromOID(oid, callback) {
var matches = regexp.exec(oid);
var mac = "";
if(matches != null) {
for(var i = 1; i < matches.length; i++) {
var num = parseInt(matches[i]);
if(num <= 15) mac += "0";
mac += num.toString(16) + ":";
}
mac = mac.substr(0, mac.length-1);
callback(mac);
}
}
function doneCb(error) {
if (error)
console.error(error.toString ());
}
function feedCb(varbinds) {
for (var i = 0; i < varbinds.length; i++) {
if (snmp.isVarbindError(varbinds[i])) {
console.error(snmp.varbindError (varbinds[i]));
} else {
if(varbinds[i].value == "3") { // only valid arp entries
getMacFromOID(varbinds[i].oid, function(mac) {
console.log(mac);
});
}
}
}
}
session.subtree(baseoid, 20, feedCb, doneCb);

View File

@ -3,6 +3,8 @@ html(ng-app="roomstateapp")
head head
title #{title} - CTDO Raumstatus title #{title} - CTDO Raumstatus
//if IE 7
link(rel="stylesheet",href="/css/ink-ie7-min.css",type="text/css",media="screen")
script(type="text/javascript", src="/js/vendor/angular.min.js") script(type="text/javascript", src="/js/vendor/angular.min.js")
script(type="text/javascript", src="/socket.io/socket.io.js") script(type="text/javascript", src="/socket.io/socket.io.js")