initial commit
This commit is contained in:
commit
d545d449c6
9 changed files with 514 additions and 0 deletions
8
Makefile
Normal file
8
Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
install:
|
||||
env | grep DESTDIR
|
||||
env | grep PREFIX
|
||||
mkdir -p ${DESTDIR}/usr/bin
|
||||
cp collector.js ${DESTDIR}/usr/bin/wattsapp-collector
|
||||
chmod +x ${DESTDIR}/usr/bin/wattsapp-collector
|
||||
mkdir -p ${DESTDIR}/etc/avahi/services/
|
||||
cp avahi.service ${DESTDIR}/etc/avahi/services/wattsapp-collector.service
|
10
avahi.service
Normal file
10
avahi.service
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
|
||||
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||
<service-group>
|
||||
<name>collector</name>
|
||||
<service>
|
||||
<type>_https._tcp</type>
|
||||
<port>8443</port>
|
||||
<txt-record>ns=wattsapp;ip=2001:638:709:5::5</txt-record>
|
||||
</service>
|
||||
</service-group>
|
376
collector.js
Executable file
376
collector.js
Executable file
|
@ -0,0 +1,376 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const crypto = require('crypto'),
|
||||
http = require('http'),
|
||||
https = require('https'),
|
||||
fs = require('fs'),
|
||||
util = require('util'),
|
||||
url = require('url'),
|
||||
exec = require('child_process').exec,
|
||||
// mdns = require('mdns'),
|
||||
sqlite3 = require('sqlite3').verbose();
|
||||
db = new sqlite3.Database('/var/lib/wattsapp/collector.sqlite');
|
||||
|
||||
function handle_list(res, query) {
|
||||
result = [];
|
||||
|
||||
db.each('SELECT * FROM sensors', function(err, row) {
|
||||
if (err) throw err;
|
||||
result.push({
|
||||
'id': row['id'],
|
||||
'name': row['name'],
|
||||
'status': row['status'] == 0 ? "inactive" : "active",
|
||||
'type': row['type'],
|
||||
'unit': row['unit'],
|
||||
'location': row['lat']+','+row['lon']
|
||||
});
|
||||
},
|
||||
function() {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify(result));
|
||||
});
|
||||
}
|
||||
|
||||
function handle_details(res, query) {
|
||||
function foreach_value_row(err, row) {
|
||||
if (err) throw err;
|
||||
result[row['id']]['values'].push({
|
||||
'begin': row['begin'],
|
||||
'end': row['end'],
|
||||
'value': row['value'],
|
||||
});
|
||||
};
|
||||
|
||||
function foreach_value_complete() {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify(result));
|
||||
}
|
||||
|
||||
function foreach_sensors_row(err, row) {
|
||||
if (err) throw err;
|
||||
result[row['id']] = {
|
||||
'name': row['name'],
|
||||
'status': row['status'] == 0 ? 'inactive' : 'active',
|
||||
'type': row['type'],
|
||||
'unit': row['unit'],
|
||||
'location': row['lat']+","+row['lon'],
|
||||
'values': []
|
||||
}
|
||||
}
|
||||
|
||||
function foreach_sensors_complete() {
|
||||
var values_query = "SELECT * FROM value";
|
||||
var values_param = [];
|
||||
var begin_time = null;
|
||||
var end_time = null;
|
||||
|
||||
if (query['meters'] || query['time']) {
|
||||
values_query += " WHERE";
|
||||
}
|
||||
|
||||
if (query['meters']) {
|
||||
var sensors = query['meters'].split(',');
|
||||
values_query += " id IN (";
|
||||
values_query += sensors.map(function(e) { return "?" }).join(',');
|
||||
values_query += ")";
|
||||
values_param = values_param.concat(sensors);
|
||||
}
|
||||
|
||||
if (query['meters'] && query['time']) {
|
||||
values_query += " AND";
|
||||
}
|
||||
|
||||
if (query['time']) {
|
||||
var time = query['time'].split(':')
|
||||
time_begin = time[0];
|
||||
time_end = time[1];
|
||||
|
||||
if (time_begin > 0 && time_end > 0) {
|
||||
values_query += " begin > ? AND end < ?";
|
||||
values_param = values_param.concat([time_begin, time_end]);
|
||||
} else if (time_begin > 0) {
|
||||
values_query += " begin > ?";
|
||||
values_param = values_param.concat([time_begin]);
|
||||
} else if (time_end > 0) {
|
||||
values_query += " end < ?";
|
||||
values_param = values_param.concat([time_end]);
|
||||
}
|
||||
}
|
||||
|
||||
db.each(values_query, values_param, foreach_value_row, foreach_value_complete);
|
||||
}
|
||||
|
||||
result = {};
|
||||
|
||||
var sensors_query = "SELECT * FROM sensors";
|
||||
var sensors = [];
|
||||
|
||||
if (query['meters']) {
|
||||
var sensors = query['meters'].split(',');
|
||||
sensors_query += " WHERE id IN (";
|
||||
sensors_query += sensors.map(function(e) { return "?" }).join(',');
|
||||
sensors_query += ")"
|
||||
}
|
||||
|
||||
db.each(sensors_query, sensors, foreach_sensors_row, foreach_sensors_complete);
|
||||
}
|
||||
|
||||
function handle_sum(res, query) {
|
||||
function foreach_value_row(err, row) {
|
||||
if (err) throw err;
|
||||
result[row['id']]['values'].push({
|
||||
'begin': row['begin'],
|
||||
'end': row['end'],
|
||||
'value': row['value'],
|
||||
});
|
||||
};
|
||||
|
||||
function foreach_value_complete() {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify(result));
|
||||
}
|
||||
|
||||
function foreach_sensors_row(err, row) {
|
||||
if (err) throw err;
|
||||
result[row['id']] = {
|
||||
'name': row['name'],
|
||||
'status': row['status'] == 0 ? 'inactive' : 'active',
|
||||
'type': row['type'],
|
||||
'unit': row['unit'],
|
||||
'location': row['lat']+","+row['lon'],
|
||||
'values': []
|
||||
}
|
||||
}
|
||||
|
||||
function foreach_sensors_complete() {
|
||||
var values_query = "SELECT id, MIN(begin) AS begin, MAX(end) AS end, SUM(value) AS value FROM value";
|
||||
var values_param = [];
|
||||
var begin_time = null;
|
||||
var end_time = null;
|
||||
|
||||
if (query['meters'] || query['time']) {
|
||||
values_query += " WHERE";
|
||||
}
|
||||
|
||||
if (query['meters']) {
|
||||
var sensors = query['meters'].split(',');
|
||||
values_query += " id IN (";
|
||||
values_query += sensors.map(function(e) { return "?" }).join(',');
|
||||
values_query += ")";
|
||||
values_param = values_param.concat(sensors);
|
||||
}
|
||||
|
||||
if (query['meters'] && query['time']) {
|
||||
values_query += " AND";
|
||||
}
|
||||
|
||||
if (query['time']) {
|
||||
var time = query['time'].split(':')
|
||||
time_begin = time[0];
|
||||
time_end = time[1];
|
||||
|
||||
if (time_begin > 0 && time_end > 0) {
|
||||
values_query += " begin > ? AND end < ?";
|
||||
values_param = values_param.concat([time_begin, time_end]);
|
||||
} else if (time_begin > 0) {
|
||||
values_query += " begin > ?";
|
||||
values_param = values_param.concat([time_begin]);
|
||||
} else if (time_end > 0) {
|
||||
values_query += " end < ?";
|
||||
values_param = values_param.concat([time_end]);
|
||||
}
|
||||
}
|
||||
|
||||
values_query += " GROUP BY id";
|
||||
|
||||
db.each(values_query, values_param, foreach_value_row, foreach_value_complete);
|
||||
}
|
||||
|
||||
result = {};
|
||||
|
||||
var sensors_query = "SELECT * FROM sensors";
|
||||
var sensors = [];
|
||||
|
||||
if (query['meters']) {
|
||||
var sensors = query['meters'].split(',');
|
||||
sensors_query += " WHERE id IN (";
|
||||
sensors_query += sensors.map(function(e) { return "?" }).join(',');
|
||||
sensors_query += ")"
|
||||
}
|
||||
|
||||
db.each(sensors_query, sensors, foreach_sensors_row, foreach_sensors_complete);
|
||||
}
|
||||
|
||||
function handle_blacklist(res, query) {
|
||||
var blacklist_query = "UPDATE sensors SET status=0 WHERE id=?";
|
||||
|
||||
if (!query['sensor']) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify([]));
|
||||
return;
|
||||
}
|
||||
|
||||
db.run(blacklist_query, query['sensor'], function(err) {
|
||||
if (err) throw err;
|
||||
|
||||
var result_query = "SELECT * FROM sensors WHERE id=?";
|
||||
|
||||
db.get(result_query, query['sensor'], function(err, row) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify(row));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handle_unblacklist(res, query) {
|
||||
var blacklist_query = "UPDATE sensors SET status=1 WHERE id=?";
|
||||
|
||||
if (!query['sensor']) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify([]));
|
||||
return;
|
||||
}
|
||||
|
||||
db.run(blacklist_query, query['sensor'], function(err) {
|
||||
if (err) throw err;
|
||||
|
||||
var result_query = "SELECT * FROM sensors WHERE id=?";
|
||||
|
||||
db.get(result_query, query['sensor'], function(err, row) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify(row));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handle_rename(res, query) {
|
||||
var rename_query = "UPDATE sensors SET name=? WHERE id=?";
|
||||
|
||||
if (!query['sensor'] || !query['name']) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify([]));
|
||||
return;
|
||||
}
|
||||
|
||||
db.run(rename_query, query['name'], query['sensor'], function(err) {
|
||||
if (err) throw err;
|
||||
|
||||
var result_query = "SELECT * FROM sensors WHERE id=?";
|
||||
|
||||
db.get(result_query, query['sensor'], function(err, row) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify(row));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handle_relocate(res, query) {
|
||||
var rename_query = "UPDATE sensors SET lat=?, lon=? WHERE id=?";
|
||||
|
||||
if (!query['sensor'] || !query['location']) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify([]));
|
||||
return;
|
||||
}
|
||||
|
||||
var loc = query['location'].split(',');
|
||||
|
||||
if (!loc[0] || !loc[1]) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify([]));
|
||||
return;
|
||||
}
|
||||
|
||||
db.run(rename_query, loc[0], loc[1], query['sensor'], function(err) {
|
||||
if (err) throw err;
|
||||
|
||||
var result_query = "SELECT * FROM sensors WHERE id=?";
|
||||
|
||||
db.get(result_query, query['sensor'], function(err, row) {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify(row));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function request_handler(req, res) {
|
||||
if (!req.connection.authorized) {
|
||||
res.writeHead(403, {'Content-Type': 'text/plain'});
|
||||
res.end("invalid ssl client certificate");
|
||||
return;
|
||||
}
|
||||
|
||||
parsed = url.parse(req.url, true);
|
||||
|
||||
methods = {
|
||||
'/list': handle_list,
|
||||
'/details': handle_details,
|
||||
'/sum': handle_sum,
|
||||
'/blacklist': handle_blacklist,
|
||||
'/unblacklist': handle_unblacklist,
|
||||
'/rename': handle_rename,
|
||||
'/relocate': handle_relocate
|
||||
}
|
||||
|
||||
console.log(req.url);
|
||||
|
||||
if (parsed['pathname'] in methods) {
|
||||
methods[parsed['pathname']](res, parsed['query'])
|
||||
} else {
|
||||
res.writeHead(501, {'Content-Type': 'application/json'});
|
||||
res.end("")
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
function poll_sensors() {
|
||||
fs.readFile('sensors.json', 'utf8', function (err, data) {
|
||||
data = JSON.parse(data);
|
||||
|
||||
for (hosts in data) {
|
||||
var options = {
|
||||
host: hosts['host'],
|
||||
port: hosts['port'],
|
||||
path: '/details',
|
||||
method: 'GET'
|
||||
}
|
||||
|
||||
var request = http.request(options);
|
||||
|
||||
request.on('response', function (res) {
|
||||
console.log("success");
|
||||
});
|
||||
|
||||
request.on('error', function(e) {
|
||||
console.log(e.message);
|
||||
});
|
||||
|
||||
request.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setInterval(poll_sensors, 1000*3600); // once per hour
|
||||
*/
|
||||
|
||||
/*
|
||||
mdns.createAdvertisement('https', 8443).start();
|
||||
*/
|
||||
|
||||
/*
|
||||
child = exec("avahi-publish-service collector _https._tcp 8443 \"ns=wattsapp;ip=2001:638:709:5::5\"", function(error, stdout, stderr) {});
|
||||
*/
|
||||
|
||||
var options = {
|
||||
key: fs.readFileSync('/var/lib/wattsapp/collector.key'),
|
||||
cert: fs.readFileSync('/var/lib/wattsapp/collector.crt'),
|
||||
ca: fs.readdirSync('/var/lib/wattsapp/collector_clients').map(function(x) {
|
||||
return fs.readFileSync('/var/lib/wattsapp/collector_clients/'+x);
|
||||
}),
|
||||
requestCert: true,
|
||||
// rejectUnauthorized: true
|
||||
};
|
||||
|
||||
var server = https.createServer(options);
|
||||
server.addListener("request", request_handler);
|
||||
server.listen(8443);
|
5
debian/changelog
vendored
Normal file
5
debian/changelog
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
wattsapp-collector (0.1-1) oneiric; urgency=low
|
||||
|
||||
* initial version
|
||||
|
||||
-- Johannes Schauer <j.schauer@email.de> Thu, 07 Jul 2011 12:33:58 +0200
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
7
|
8
debian/control
vendored
Normal file
8
debian/control
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
Source: wattsapp-collector
|
||||
Maintainer: Johannes Schauer <j.schauer@email.de>
|
||||
Build-Depends: debhelper
|
||||
|
||||
Package: wattsapp-collector
|
||||
Architecture: all
|
||||
Depends: openssl, node-sqlite3, sqlite3, nodejs, avahi-daemon
|
||||
Description: wattsapp-collector
|
4
debian/rules
vendored
Executable file
4
debian/rules
vendored
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
60
debian/wattsapp-collector.init
vendored
Normal file
60
debian/wattsapp-collector.init
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
#! /bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: wattsapp-collector
|
||||
# Required-Start: $syslog
|
||||
# Required-Stop: $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: wattsapp collector
|
||||
### END INIT INFO
|
||||
|
||||
set -e
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON=/usr/bin/wattsapp-collector
|
||||
NAME=wattsapp-collector
|
||||
DESC="wattsapp collector"
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
do_start()
|
||||
{
|
||||
start-stop-daemon --start --quiet --oknodo --make-pidfile --pidfile /var/run/wattsapp-collector.pid --background --exec $DAEMON -- $DAEMON_OPTS
|
||||
}
|
||||
|
||||
do_stop()
|
||||
{
|
||||
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/wattsapp-collector.pid
|
||||
rm -f /var/run/wattsapp-collector.pid
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
log_daemon_msg "Starting $DESC" "$NAME"
|
||||
do_start
|
||||
log_end_msg $?
|
||||
;;
|
||||
stop)
|
||||
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
do_stop
|
||||
log_end_msg $?
|
||||
;;
|
||||
|
||||
restart|force-reload)
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
do_stop
|
||||
sleep 1
|
||||
do_start
|
||||
log_end_msg $?
|
||||
;;
|
||||
|
||||
*)
|
||||
log_success_msg "Usage: $0 {start|stop|restart|force-reload}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
42
debian/wattsapp-collector.postinst
vendored
Normal file
42
debian/wattsapp-collector.postinst
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
mkdir -p /var/lib/wattsapp
|
||||
mkdir -p /var/lib/wattsapp/collector_clients
|
||||
if [ ! -f /var/lib/wattsapp/collector.key ]; then
|
||||
openssl genrsa -out /var/lib/wattsapp/collector.key 1024
|
||||
echo "created privaate key in /var/lib/wattsapp/collector.key"
|
||||
openssl req -new -key /var/lib/wattsapp/collector.key -out /tmp/certrequest.csr
|
||||
openssl x509 -req -in /tmp/certrequest.csr -signkey /var/lib/wattsapp/collector.key -out /var/lib/wattsapp/collector.crt
|
||||
echo "created self-signed certificate in /var/lib/wattsapp/collector.crt"
|
||||
echo "distribute it to the cloud"
|
||||
rm /tmp/certrequest.csr
|
||||
fi
|
||||
if [ ! -f /var/lib/wattsapp/collector.sqlite ]; then
|
||||
cat | sqlite3 /var/lib/wattsapp/collector.sqlite << END
|
||||
PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE sensors (
|
||||
id INTEGER,
|
||||
name TEXT,
|
||||
status INTEGER,
|
||||
type TEXT,
|
||||
unit TEXT,
|
||||
lat REAL,
|
||||
lon REAL
|
||||
, uuid TEXT);
|
||||
CREATE TABLE value (
|
||||
id INTEGER,
|
||||
begin INTEGER,
|
||||
end INTEGER,
|
||||
value REAL
|
||||
);
|
||||
COMMIT;
|
||||
END
|
||||
fi
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
Loading…
Reference in a new issue