860 lines
27 KiB
JavaScript
860 lines
27 KiB
JavaScript
"use strict";
|
|
const express = require('express');
|
|
const router = express.Router();
|
|
const moment = require('moment');
|
|
const mathe = require('mathjs');
|
|
const fs = require('fs');
|
|
const util = require('./utilities');
|
|
|
|
|
|
// Mongo wird in app.js geöffnet und verbunden und bleibt immer verbunden !!
|
|
|
|
// Get the city for given Sensor
|
|
async function getCity(db, sensorid) {
|
|
let pcoll = db.collection("properties");
|
|
let properties = await pcoll.findOne({_id:sensorid});
|
|
let addr = "unKnown";
|
|
try {
|
|
addr = properties.location[0].address.country + " " +
|
|
properties.location[0].address.plz + " " +
|
|
properties.location[0].address.city;
|
|
}
|
|
catch(e) {
|
|
// do nothing, just skip
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
/*
|
|
// API to put data into dBase
|
|
router.post('/putdata/:what', function(req,res) {
|
|
let db = req.app.get('dbase');
|
|
let cmd = req.query.cmd;
|
|
let what = req.params.what;
|
|
if (what=='problems') {
|
|
putAPIproblemdata(db, cmd, req.body)
|
|
.then((erg) => {
|
|
// console.log(erg);
|
|
res.send(erg);
|
|
});
|
|
} else {
|
|
res.send ( {error:'wrong call'})
|
|
}
|
|
});
|
|
*/
|
|
|
|
|
|
//API to read all datas from the database
|
|
router.get('/getdata', function (req, res) {
|
|
let db = req.app.get('dbase');
|
|
let sid=1;
|
|
if (!((req.query.sensorid == undefined) || (req.query.sensorid == ""))) {
|
|
sid = parseInt(req.query.sensorid);
|
|
}
|
|
let avg = req.query.avg;
|
|
let span = req.query.span;
|
|
let dt = req.query.datetime;
|
|
if(isNaN(sid)) {
|
|
getAPIdataTown(db, req.query.sensorid, avg, span, dt, res)
|
|
.then(erg => res.json(erg));
|
|
} else {
|
|
getAPIdataSensor(db, sid, avg, span, dt)
|
|
.then(erg => res.json(erg));
|
|
}
|
|
|
|
// if(req.query.sensorid == "all") {
|
|
// getAPIalldata(db, dt)
|
|
// .then(erg => res.json(erg));
|
|
});
|
|
|
|
router.get('/getprops', function (req, res) {
|
|
let db = req.app.get('dbase');
|
|
let sid=0;
|
|
if (!((req.query.sensorid == undefined) || (req.query.sensorid == ""))) {
|
|
sid = parseInt(req.query.sensorid);
|
|
}
|
|
let dt = "1900-01-01T00:00:00";
|
|
if(!((req.query.since === undefined) || (req.query.since ==""))) {
|
|
dt = req.query.since;
|
|
}
|
|
let name = ""
|
|
if(!((req.query.sensortyp === undefined) || (req.query.sensortyp ==""))) {
|
|
name = req.query.sensortyp;
|
|
}
|
|
|
|
getAPIprops(db, sid, name, dt)
|
|
.then(erg => res.json(erg));
|
|
});
|
|
|
|
|
|
router.get('/getmapsensors', function (req, res) {
|
|
let db = req.app.get('dbase'); // db wird in req übergeben (von app.js)
|
|
let bounds = {};
|
|
bounds.south = parseFloat(req.query.south);
|
|
bounds.north = parseFloat(req.query.north);
|
|
bounds.east = parseFloat(req.query.east);
|
|
bounds.west = parseFloat(req.query.west);
|
|
bounds.poly = [];
|
|
if (req.query.poly != undefined) {
|
|
bounds.poly = JSON.parse(req.query.poly);
|
|
}
|
|
let ptype = parseInt(req.query.ptype);
|
|
let stype = req.query.stype;
|
|
let st = req.query.start;
|
|
|
|
getApiMapSensors(db, bounds, stype, ptype, st)
|
|
.then(erg => res.json(erg));
|
|
});
|
|
|
|
router.get('/getcities', (req,res) => {
|
|
let db = req.app.get('dbase'); // db wird in req übergeben (von app.js)
|
|
let country = req.query.country;
|
|
let type = req.query.type;
|
|
if (country == undefined) {
|
|
country = 'all';
|
|
}
|
|
if (type == undefined) {
|
|
type = 'PM';
|
|
}
|
|
getApiCities(db,country.toUpperCase(),type.toUpperCase())
|
|
.then(erg => res.json(erg));
|
|
});
|
|
|
|
// Get address from coordinates using OpenStreetMap Nominatim API
|
|
router.get('/getaddress', function (req, res) {
|
|
let db = req.app.get('dbase');
|
|
let sid = 0;
|
|
if (!((req.query.sensorid == undefined) || (req.query.sensorid == ""))) {
|
|
sid = parseInt(req.query.sensorid);
|
|
}
|
|
|
|
if (sid === 0) {
|
|
res.json({address: null, err: "No sensorid provided"});
|
|
return;
|
|
}
|
|
|
|
util.getAddress(db, sid)
|
|
.then(erg => res.json(erg))
|
|
.catch(err => {
|
|
console.log("getaddress error:", err);
|
|
res.json({address: null, err: err.message});
|
|
});
|
|
});
|
|
|
|
// ***********************************************************
|
|
// putAPIproblemdata - Daten in der DB speichern
|
|
//
|
|
// Parameter:
|
|
// db: Mongo-Database
|
|
// cmd: 'start', 'end', 'data'
|
|
// data: JSON string to put into db
|
|
//
|
|
// return:
|
|
// error, if not correctly saved, else null
|
|
// ***********************************************************
|
|
/*
|
|
async function putAPIproblemdata(db, cmd, data) {
|
|
// console.log("putAPIproblemdata"," Länge: ", data.length);
|
|
let collection = db.collection('problemsensors');
|
|
if(cmd == 'end') {
|
|
return {error: 'done'};
|
|
}
|
|
if(cmd == 'data') {
|
|
let inserted;
|
|
let upd = [];
|
|
for (let i=0; i< data.length; i++){
|
|
let one = { updateOne: { "filter" : { "_id": data[i]._id}, "update": { $set: data[i]}, "upsert": true } };
|
|
upd.push(one);
|
|
}
|
|
try {
|
|
inserted = await collection.bulkWrite(upd)
|
|
// console.log("Modifiziert:", inserted.modifiedCount)
|
|
}
|
|
catch(e) {
|
|
console.log(e)
|
|
}
|
|
return {error: "OK"}
|
|
}
|
|
return { error: 'wrong command'};
|
|
}
|
|
*/
|
|
// ***********************************************************
|
|
// getAPIprobSensors - Get data for problematic sensors
|
|
//
|
|
// Parameter:
|
|
// db: Mongo-Database
|
|
//
|
|
// return:
|
|
// JSON Dokument mit den angefragten Werten
|
|
// ***********************************************************
|
|
/*
|
|
async function getAPIprobSensors(db,pnr,only,withTxt) {
|
|
let coll = db.collection('problemsensors');
|
|
let query = {_id: {$gt: 0}};
|
|
let proj = {};
|
|
let count = 0;
|
|
if(withTxt == undefined) {
|
|
withTxt = true;
|
|
}
|
|
if (pnr != 0) {
|
|
query = { $and: [ {problemNr: pnr}, {_id: {$gt: 0}} ]} ;
|
|
}
|
|
if(only) {
|
|
proj = {_id: 1};
|
|
}
|
|
let docs = await coll.find(query,proj).toArray();
|
|
if(docs != null) {
|
|
count = docs.length;
|
|
}
|
|
let texte = {};
|
|
if(withTxt) {
|
|
let tt = await coll.findOne({_id: 0});
|
|
if (tt == null) {
|
|
texte.texte = [];
|
|
}
|
|
}
|
|
let ret;
|
|
if (only) {
|
|
ret = {count: count, problemNr: pnr, values: docs, texte: texte.texte};
|
|
} else {
|
|
ret = {count: count, values: docs, texte: texte.texte};
|
|
}
|
|
if(!withTxt) {
|
|
delete ret.texte;
|
|
}
|
|
return ret
|
|
}
|
|
*/
|
|
|
|
|
|
// ***********************************************************
|
|
// getAPIdataNew - Get data direct via API for one sensor
|
|
//
|
|
// Parameter:
|
|
// db: Mongo-Database
|
|
// sid: sensor ID
|
|
// mavg: time over that to build the average [minutes]
|
|
// dauer: duration for the data [hours]
|
|
// start: starting point of 'dauer'
|
|
// end: end of 'dauer'
|
|
//
|
|
// return:
|
|
// JSON Dokument mit den angefragten Werten
|
|
// ***********************************************************
|
|
/*
|
|
async function getAPIdataNew(db,sid,mavg,dauer,start,end, gstart) {
|
|
let st = moment(start).startOf('day'); // clone start/end ..
|
|
let en = moment(end).startOf('day'); // .. and set to start of day
|
|
|
|
let retur = {sid: sid, avg: mavg, span: dauer, start: gstart};
|
|
let collection = db.collection('values');
|
|
let ergArr = [];
|
|
let values;
|
|
for (; st <= en; st.add(1, 'd')) {
|
|
let id = sid + '_' + st.format('YYYYMMDD');
|
|
try {
|
|
values = await collection.findOne({
|
|
_id: id
|
|
});
|
|
}
|
|
catch (e) {
|
|
console.log(e);
|
|
}
|
|
if(values && (values.values.length != 0)) {
|
|
ergArr.push(...values.values);
|
|
}
|
|
}
|
|
if (ergArr.length == 0) {
|
|
retur.count = 0;
|
|
retur['values'] = [];
|
|
} else {
|
|
// Bereich einschränken
|
|
let v = [];
|
|
let fnd = ergArr.findIndex(x => x.datetime >= start);
|
|
if (fnd != -1) {
|
|
v = ergArr.slice(fnd);
|
|
ergArr = v;
|
|
}
|
|
fnd = ergArr.findIndex(x => x.dateTime > end);
|
|
if (fnd != -1) {
|
|
v = ergArr.slice(-fnd);
|
|
erg.Arr = v;
|
|
}
|
|
if ((mavg === undefined) || (mavg == 1)) {
|
|
retur.count = ergArr.length;
|
|
retur['values'] = ergArr;
|
|
}
|
|
// Mittelwert berechnen
|
|
let x = util.calcMovingAverage(db, ergArr, mavg, 0, 0, true);
|
|
fnd = x.findIndex(u => u.dt >= gstart);
|
|
if((fnd == -1) && (dauer == 0)) {
|
|
let y = x.slice(-1);
|
|
x = y;
|
|
} else {
|
|
if (fnd != -1) {
|
|
let y = x.slice(fnd);
|
|
x = y;
|
|
}
|
|
}
|
|
retur.count = x.length;
|
|
retur.values = x;
|
|
}
|
|
return retur;
|
|
}
|
|
*/
|
|
|
|
// ******************************************************************
|
|
// getAPITN - Get data direct via API for all sensors in a town
|
|
//
|
|
// Parameter:
|
|
// dbase: Mongo-Database
|
|
// sensors: array of sensors
|
|
// mavg: time over that to build the average [minutes]
|
|
// dauer: duration for the data [hours]
|
|
// start: starting point of 'dauer'
|
|
// end: end of 'dauer'
|
|
// town: name of town
|
|
//
|
|
// return:
|
|
// JSON document with data for ALL sensors in town
|
|
//
|
|
// ***** Neue DB-Struktur - Versuch
|
|
//
|
|
// ********************************************************************
|
|
async function getAPITN (dbase,sensors,mavg,dauer,start,end,gstart,town) {
|
|
// Fetch for all this sensors
|
|
let los = moment(); // debug, to time it
|
|
let erg = {sid:town, avg: mavg, span: dauer, start: gstart, count: 0, sensordata: []}; // prepare object
|
|
let val;
|
|
for(let j=0; j<sensors.length; j++) { // loop thru array of sensors
|
|
try {
|
|
val = await getAPIdata(dbase,sensors[j],mavg,dauer,start,end,gstart); // get data for obe sensor
|
|
if(val.count != 0) { // if there is data
|
|
delete val.avg; // delete unnecessary elements
|
|
delete val.span;
|
|
delete val.start;
|
|
erg.sensordata.push(val); // and push data to result array
|
|
}
|
|
}
|
|
catch(e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
console.log("Zeit in getAPIdataTown:",(moment()-los)/1000,'[sec]'); // time it
|
|
console.log('Daten für',erg.sensordata.length,' Sensoren gelesen');
|
|
erg.count = erg.sensordata.length; // save count
|
|
return erg; // and return all data
|
|
}
|
|
|
|
|
|
// ******************************************************************
|
|
// getAPIdataTown - Get data direct via API for all sensors in a town
|
|
//
|
|
// Call:
|
|
// http://feinstaub.rexfue.de/api/getdata/?sensorid=stuttgart&avg=5&span=12
|
|
//
|
|
// mit:
|
|
// sensorid: Name der Stadt
|
|
// avg: Mittelwert-Bildung über xxx Minuten
|
|
// span: Zeitraum für die Mittelwertbildung in Stunden
|
|
// dt: Startzeitpunkt
|
|
//
|
|
// Parameter:
|
|
// db: Mongo-Database
|
|
// town: name of town
|
|
// avg: time over that to build the average [minutes]
|
|
// span: duration for the data [hours]
|
|
// dt: starting point of 'span'
|
|
// res: http-object to send result
|
|
//
|
|
// return:
|
|
// nothing; JSON document will be sent back
|
|
//
|
|
//
|
|
// For every town, there has to be an JSON-file with the
|
|
// sensornumbers of ervery sensor living in that town.
|
|
//
|
|
// ***** Neue DB-Struktur - Versuch
|
|
//
|
|
// ********************************************************************
|
|
async function getAPIdataTown(db, town, avg, span, dt, res) {
|
|
// get sensors for the town as array of ids
|
|
let p = parseParams(avg, span, dt);
|
|
// get sensor numbers from town-sensor-file
|
|
let sensors = [];
|
|
let tw = town.toLowerCase();
|
|
let data = fs.readFileSync(tw+'.txt');
|
|
sensors = JSON.parse(data);
|
|
|
|
return getAPITN (db,sensors,p.mavg,p.dauer,p.start,p.end,p.gstart, town);
|
|
}
|
|
|
|
|
|
// ******************************************************************
|
|
// getAPIdataSenssor - Get data direct via API for all sensors in a town
|
|
//
|
|
// Call:
|
|
// http://feinstaub.rexfue.de/api/getdata/?sensorid=140&avg=5&span=12&datetime=2018-08-ß02T20:12:00
|
|
//
|
|
// mit:
|
|
// sensorid: ID des gewümschten Sensors
|
|
// avg: Mittelwert-Bildung über xxx Minuten
|
|
// span: Zeitraum für die Mittelwertbildung in Stunden
|
|
// datetime: Startzeitpunkt
|
|
//
|
|
// Parameter:
|
|
// db: Datenbank
|
|
// sid: ID of sensor
|
|
// avg: time over that to build the average [minutes]
|
|
// span: duration for the data [hours]
|
|
// dt: starting point of 'span'
|
|
//
|
|
// return:
|
|
// nothing; JSON document will be sent back
|
|
//
|
|
//
|
|
// ***** Neue DB-Struktur - Versuch
|
|
//
|
|
// ********************************************************************
|
|
async function getAPIdataSensor(db, sid, avg, span, dt) {
|
|
let p = parseParams(avg, span, dt);
|
|
return getAPIdata(db,sid,p.mavg,p.dauer,p.start,p.end,p.gstart)
|
|
}
|
|
|
|
|
|
// *********************************************
|
|
// Get data direct via API for one sensor
|
|
//
|
|
// Call:
|
|
// http://feinstaub.rexfue.de/api?sid=1234&avg=5&span=24
|
|
//
|
|
// mit:
|
|
// sid: Sensornummer
|
|
// avg: Mittelwert-Bildung über xxx Minuten
|
|
// span: Zeitraum für die Mittelwertbildung in Stunden
|
|
//
|
|
// return:
|
|
// JSON Dokument mit den angefragten Werten
|
|
// *********************************************
|
|
async function getAPIdata(db, sid, mavg, dauer, start, end, gstart) {
|
|
let values = [];
|
|
let retur = {sid: sid, avg: mavg, span: dauer, start: gstart};
|
|
|
|
// First, determine sensor type from properties
|
|
let pcoll = db.collection("properties");
|
|
let props = await pcoll.findOne({_id: sid});
|
|
if (!props) {
|
|
retur.count = 0;
|
|
retur['values'] = [];
|
|
retur.error = 'Sensor not found';
|
|
return retur;
|
|
}
|
|
|
|
// Determine collection based on type
|
|
let collectionName;
|
|
if (props.type === 'radioactivity') {
|
|
collectionName = 'radioactivity_sensors';
|
|
} else {
|
|
// Assume THP for any other type
|
|
collectionName = 'thp_sensors';
|
|
}
|
|
|
|
let collection = db.collection(collectionName);
|
|
try {
|
|
values = await collection.find(
|
|
{
|
|
sensorid: sid,
|
|
datetime: {
|
|
$gte: new Date(start),
|
|
$lt: new Date(end)
|
|
}
|
|
},
|
|
{
|
|
projection: {_id: 0},
|
|
sort: {datetime: 1}
|
|
}
|
|
).toArray()
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
if(values.length == 0) {
|
|
retur.count = 0;
|
|
retur['values'] = [];
|
|
} else {
|
|
if((mavg===undefined) || (mavg == 1)) {
|
|
retur.count = values.length;
|
|
retur['values'] = values;
|
|
}
|
|
let x = await util.calcMovingAverage(db, sid, values, mavg, true);
|
|
let fnd = x.findIndex(u => u.dt >= gstart);
|
|
if((fnd == -1) && (dauer == 0)) {
|
|
let y = x.slice(-1);
|
|
x = y;
|
|
} else {
|
|
if (fnd != -1) {
|
|
let y = x.slice(fnd);
|
|
x = y;
|
|
}
|
|
}
|
|
retur.count = x.length;
|
|
retur.values = x;
|
|
}
|
|
return retur;
|
|
}
|
|
|
|
/* ===============================================================
|
|
// PM (FEINSTAUB) FUNCTIONS REMOVED - Not needed in new DB
|
|
// ===============================================================
|
|
|
|
// *********************************************
|
|
// Get data direct via API for ALL sensor - WAS PM-SPECIFIC
|
|
//
|
|
// Call:
|
|
// http://feinstaub.rexfue.de/api?sid=all&datetime="2018-06-02T12:00Z"
|
|
//
|
|
// mit:
|
|
// dt: Zeitpunkt, für den die Daten geholt werden
|
|
// Es werden Daten <= dem Zeitpunkt geholt
|
|
//
|
|
// return:
|
|
// JSON Dokument mit den angefragten Werten
|
|
// *********************************************
|
|
async function getAPIalldata(db,dt) {
|
|
// REMOVED - Was PM-specific, not applicable to Radiation/THP sensors
|
|
return { error: 'Function removed - was PM-specific' };
|
|
}
|
|
|
|
function isPM(name) {
|
|
// REMOVED - No longer needed, only Radiation and THP sensors
|
|
return false;
|
|
}
|
|
*/
|
|
|
|
// *********************************************
|
|
// Get properties for all sensors
|
|
//
|
|
// Call:
|
|
// http://feinstaub.rexfue.de/api/getprops?sensorid=1234&since=2810-03-23&sensortyp=SDS011
|
|
//
|
|
// mit:
|
|
// sid: Sensornummer (all -> alle Sensoren)
|
|
// since: seit dem Datum (incl)
|
|
// sensortyp: Type des Sensors (z.B. SDS011 oder PM(für alle Feinstaub-Sensoren))
|
|
//
|
|
// params:
|
|
// db Datenbank
|
|
// sid Sensor-Nummer oder all
|
|
// typ Sensor-Typ
|
|
// dt Datum, ab wann gesucht werden soll
|
|
//
|
|
// return:
|
|
// JSON Dokument mit den angefragten werten
|
|
// *********************************************
|
|
async function getAPIprops(db,sid,typ,dt) {
|
|
let properties = [];
|
|
let erg = [];
|
|
let entry = {};
|
|
let pcoll = db.collection("properties");
|
|
let query = {};
|
|
if(sid == 0) {
|
|
if(typ == "") {
|
|
query = {}; // Get all sensors
|
|
} else if (typ == 'radioactivity') {
|
|
query = {type: 'radioactivity'};
|
|
} else if (typ == 'THP') {
|
|
query = {type: {$ne: 'radioactivity'}}; // Anything not radioactivity is THP
|
|
} else {
|
|
// For specific sensor type names, check in name array
|
|
query = {'name.name': typ};
|
|
}
|
|
} else {
|
|
query = { _id:sid };
|
|
}
|
|
properties = await pcoll.find(query).sort({_id: 1}).toArray();
|
|
|
|
for (let i = 0; i < properties.length; i++) {
|
|
let loclast = (properties[i].location.length)-1;
|
|
|
|
// Get current name from array
|
|
let currentName = properties[i].name;
|
|
if (Array.isArray(properties[i].name)) {
|
|
currentName = properties[i].name[properties[i].name.length - 1].name;
|
|
}
|
|
|
|
// Get last_seen from values.timestamp if available
|
|
let lastSeen = properties[i].last_seen || (properties[i].values && properties[i].values.timestamp);
|
|
if (!lastSeen) {
|
|
lastSeen = moment("1900-01-01T00:00Z");
|
|
} else if (lastSeen.$date) {
|
|
lastSeen = moment(lastSeen.$date);
|
|
} else {
|
|
lastSeen = moment(lastSeen);
|
|
}
|
|
|
|
// Build result object
|
|
let result = {
|
|
sid: properties[i]._id,
|
|
typ: currentName,
|
|
lat: properties[i].location[loclast].loc.coordinates[1],
|
|
lon: properties[i].location[loclast].loc.coordinates[0],
|
|
alt: properties[i].location[loclast].altitude,
|
|
lastSeen: lastSeen.format(),
|
|
country: properties[i].location[loclast].country
|
|
};
|
|
|
|
// Add since date if available
|
|
if (properties[i].location[loclast].since) {
|
|
if (properties[i].location[loclast].since.$date) {
|
|
result.since = moment(properties[i].location[loclast].since.$date).format();
|
|
} else {
|
|
result.since = moment(properties[i].location[loclast].since).format();
|
|
}
|
|
}
|
|
|
|
erg.push(result);
|
|
}
|
|
entry.sensortyp = typ =="" ? "all" : typ;
|
|
entry.count = erg.length;
|
|
entry.since = dt;
|
|
entry.values = erg;
|
|
return entry;
|
|
}
|
|
|
|
|
|
// *******************************************************************
|
|
// parseParams - parse the given paramaters
|
|
//
|
|
// params:
|
|
// avg: averegae time in min
|
|
// span: data range in hours
|
|
// dt: start date of data range
|
|
//
|
|
// return:
|
|
// object with:
|
|
// mavg: average time in min (default 1min, max; 1440min))
|
|
// dauer: data range in hoiurs (default 24h, max: 720h)
|
|
// start: start date/time to calculate average
|
|
// end: end of data range
|
|
// gstart: start on datarange (without avg-time)
|
|
//
|
|
// **********************************************************************
|
|
function parseParams(avg, span, dt) {
|
|
let params = {};
|
|
params.mavg = 1; // default average
|
|
if (avg !== undefined) { // if acg defined ..
|
|
params.mavg = parseInt(avg); // .. use it
|
|
}
|
|
if (params.mavg > 1440) { params.mavg = 1440;} // avgmax = 1 day
|
|
params.dauer = 24; // span default 1 day
|
|
if(span !== undefined) { // if defined ..
|
|
params.dauer = parseInt(span); // .. use it
|
|
}
|
|
if (params.dauer > 720) { params.dauer = 720;} // spanmax = 30 days
|
|
params.start = moment(); // default start -> now
|
|
params.end = moment(); // define end
|
|
if(dt != undefined) { // if defined ..
|
|
params.start = moment(dt); // .. use it ..
|
|
params.end = moment(dt).add(params.dauer,'h'); // .. and calculate new end
|
|
} else { // if not defined, calc start ..
|
|
params.start.subtract(params.dauer, 'h'); // .. from span (= dauer)
|
|
}
|
|
params.gstart = moment(params.start);
|
|
params.start.subtract(params.mavg,'m'); // start earlier to calc right average
|
|
|
|
return params;
|
|
}
|
|
|
|
// ******************************************************************
|
|
// getAPIproblemSensors - Get senosor-IDs of problematic sensor
|
|
// within map bounds
|
|
//
|
|
// Call:
|
|
// http://feinstaub.rexfue.de/api/getprobsens/?bounds=[bounds]&ptype=1&datetime=2018-08-ß02T20:12:00
|
|
//
|
|
// mit:
|
|
// bounds: corner coordinates of map or polygone for town border
|
|
// ptype: type of problem (optional)
|
|
// datetime: day for which to calculate (optional)
|
|
//
|
|
// Parameter:
|
|
// db: database
|
|
// bounds: corner coordinates of map or polygone for town border
|
|
// stype: 'PM' or 'THP' or 'TH' os 'T' or 'H' (default: 'PM')
|
|
// ptype: type of problem (undefined means ALL problems)
|
|
// st: date to calculate for
|
|
//
|
|
// return:
|
|
// array wit 24h-Average-Value for the last 24hours for every sensor
|
|
//
|
|
//
|
|
//
|
|
// ********************************************************************
|
|
async function getApiMapSensors(db, bounds, stype, ptype, st) {
|
|
// fetch list of sensor ids within bounds
|
|
let slist = [];
|
|
let collection = db.collection('properties');
|
|
let loc;
|
|
let name = 'PM';
|
|
if (stype != undefined) {
|
|
name = stype;
|
|
}
|
|
if (bounds.poly.length != 0) {
|
|
loc = {
|
|
'location.0.loc': {
|
|
$geoWithin: {
|
|
$geometry: {
|
|
type: "Polygon",
|
|
coordinates: [bounds.poly],
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
} else {
|
|
loc = {
|
|
'location.0.loc': {
|
|
$geoWithin: {
|
|
$box: [
|
|
[bounds.west, bounds.south],
|
|
[bounds.east, bounds.north]
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
let docs = await collection.find(loc, {_id: 1, name:1}).toArray(); // find all data within map borders (box)
|
|
// .toArray(async function (err, docs) {
|
|
// console.log(docs);
|
|
for (let i = docs.length - 1; i >= 0; i--) {
|
|
if (!((name == 'PM') == isPM(docs[i].name))) {
|
|
docs.splice(i, 1);
|
|
continue;
|
|
}
|
|
let erg = await getAPIdataSensor(db, docs[i]._id, 1, 24);
|
|
|
|
if (erg.values.length == 0) {
|
|
docs[i].mean = -1;
|
|
docs[i].std = 0;
|
|
docs[i].type = 'noData';
|
|
delete docs[i].name;
|
|
continue;
|
|
}
|
|
|
|
// if (!erg.values[0].hasOwnProperty('P1')) {
|
|
// continue;
|
|
// }
|
|
|
|
// console.log(erg);
|
|
let result = erg.values.map(x => x.P1);
|
|
// console.log(result);
|
|
let mean = mathe.mean(result);
|
|
let std = mathe.std(result);
|
|
console.log(mean);
|
|
docs[i].mean = Math.round(mean);
|
|
docs[i].std = std;
|
|
delete docs[i].name;
|
|
}
|
|
// console.log(docs);
|
|
// nun in docs alle Mittelwerte über die letzten 24h
|
|
// nun sortieren
|
|
let docs_sorted = docs.sort((a, b) => a.mean - b.mean);
|
|
let docs_std = docs.sort((a, b) => a.std - b.std);
|
|
// console.log(docs_sorted);
|
|
return docs_sorted;
|
|
}
|
|
|
|
function isPM(name) {
|
|
let pms = ['SDS011','PMS7003','PMS3003','PMS5003','HPM','SDS021','PPD42NS'];
|
|
if (pms.findIndex(n => n == name) != -1) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// ******************************************************************
|
|
// getAPICities - Get all cities, containing sensors
|
|
//
|
|
//
|
|
// Call:
|
|
// http://feinstaub.rexfue.de/api/getcities/?country=de
|
|
//
|
|
// with:
|
|
// county: 2 character coutrycode to find the city (all or absent => world)
|
|
// type: PM or THP (or absent => PM)
|
|
//
|
|
// Parameter:
|
|
// db: database
|
|
// county: 2 character coutrycode to find the citie (all => world)
|
|
// pm: PM for particulate sensors, THP for temp/hum/press-sensors
|
|
//
|
|
// return:
|
|
// JSON array with cities
|
|
//
|
|
//
|
|
//
|
|
// ********************************************************************
|
|
async function getApiCities(db, country, sensorType) {
|
|
let slist = [];
|
|
let collection = db.collection('properties');
|
|
let query = {};
|
|
|
|
// Build country query - in new DB, country is directly in location, not in address
|
|
if(country != 'ALL') {
|
|
query = {'location.country': country};
|
|
}
|
|
|
|
// Filter by sensor type
|
|
let matchtype = {};
|
|
if (sensorType == 'radioactivity') {
|
|
matchtype = {type: 'radioactivity'};
|
|
} else if (sensorType == 'THP') {
|
|
matchtype = {type: {$ne: 'radioactivity'}}; // Anything not radioactivity
|
|
}
|
|
// If sensorType is not specified or something else, get all
|
|
|
|
let docs = await collection.aggregate([
|
|
{$match: matchtype},
|
|
{ $match: query},
|
|
{ $project: {
|
|
_id:1,
|
|
name:1,
|
|
location: {
|
|
'$map': {
|
|
input: '$location',
|
|
as: 'm',
|
|
in: {
|
|
country: '$$m.address.country',
|
|
city: '$$m.address.city',
|
|
plz: '$$m.address.plz'
|
|
}
|
|
}
|
|
}
|
|
}},
|
|
{ $unwind: '$location'},
|
|
{ $group: {
|
|
sensorids: { $addToSet: '$_id'},
|
|
_id: '$location.city',
|
|
plz: { $addToSet: '$location.plz'},
|
|
country: { $first: '$location.country' }
|
|
}},
|
|
{ $project: {
|
|
_id: 0,
|
|
city: '$_id',
|
|
sensors: { count: {$size: '$sensorids'}, ids : '$sensorids'},
|
|
plz: '$plz',
|
|
country: '$country',
|
|
}}
|
|
]).toArray();
|
|
// console.log(docs);
|
|
return { count: docs.length, cities: docs };
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = router;
|
|
module.exports.api = { getCity };
|
|
|