first
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
// Fetch the actual (= newest) data out of the dbase to show it on the map
|
||||
import {DateTime} from "luxon"
|
||||
import {logit} from "../utilities/logit.js"
|
||||
import * as mongo from "../databases/mongo.js"
|
||||
import {reportError, returnOnError} from "../utilities/reporterror.js"
|
||||
import * as ERR from "../utilities/errortexts.js"
|
||||
|
||||
|
||||
// Default distance for center search ( in km)
|
||||
const DEFAULT_DISTANCE = 10
|
||||
|
||||
|
||||
// Relations between types and value type
|
||||
const vtype2measurement = {
|
||||
P1: 'pm', P2: 'pm', P0: 'pm',
|
||||
temperature: 'thp', humidity: 'thp', pressure: 'thp',
|
||||
noise_LAeq: 'noise',
|
||||
counts_per_minute: 'radioactivity'
|
||||
};
|
||||
|
||||
|
||||
// find first value type from measurement
|
||||
const getfieldfromtype = (typ) => {
|
||||
for (const [key, value] of Object.entries(vtype2measurement)) {
|
||||
if (value === typ) {
|
||||
return key
|
||||
}
|
||||
}
|
||||
return ' '
|
||||
}
|
||||
|
||||
|
||||
export const getData4map = async (params) => {
|
||||
let start = DateTime.now()
|
||||
let retur = { err: null, data: { params: params} }
|
||||
|
||||
// check parameters
|
||||
if ((params.type === undefined) || (params.type === '')) {
|
||||
return returnOnError(retur, ERR.NOTYP, getData4map.name)
|
||||
}
|
||||
const typ = params.type
|
||||
let poly = []
|
||||
let south = null, north = null, east = null, west = null, center = null
|
||||
let distance = DEFAULT_DISTANCE
|
||||
if (!((params.box === undefined) || (params.box == ""))) {
|
||||
const box = params.box
|
||||
if (!((box === undefined) || (box === ' ') || (box === 'null'))) {
|
||||
south = parseFloat(box.south)
|
||||
north = parseFloat(box.north)
|
||||
east = parseFloat(box.east)
|
||||
west = parseFloat(box.west)
|
||||
logit(`getData4map: S=${south} N=${north} E=${east} W=${west}`)
|
||||
}
|
||||
}
|
||||
if (!((params.poly === undefined) || (params.poly === ' '))){
|
||||
poly = JSON.parse(params.poly)
|
||||
}
|
||||
if (params.center !== undefined) {
|
||||
center = params.center
|
||||
if ((params.distance !== undefined) &&
|
||||
(params.distance >= 1) && (params.distance <= 1000)) {
|
||||
distance = params.distance
|
||||
}
|
||||
}
|
||||
const aktData = []
|
||||
let lastDate = 0
|
||||
let query = {type: typ}
|
||||
|
||||
// if polyline or box were given, set query
|
||||
if (poly.length !== 0) { // polyline given
|
||||
query.location = {
|
||||
$geoWithin: {
|
||||
$geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [poly],
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (south !== null) { // box given
|
||||
query["location.loc"] = {
|
||||
$geoWithin: {
|
||||
$box: [
|
||||
[west, south],
|
||||
[east, north]
|
||||
]
|
||||
}
|
||||
}
|
||||
} else if (center !== null) { // center point given
|
||||
query["location.loc"] = {
|
||||
$nearSphere: {
|
||||
$geometry: {
|
||||
type: "Point",
|
||||
coordinates: center
|
||||
},
|
||||
$maxDistance: distance * 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
// depending of the type find the measurement field to fetch
|
||||
const vtype = getfieldfromtype(typ)
|
||||
|
||||
// fetch mapdata from mongodb
|
||||
try {
|
||||
let { values, err } = await mongo.readMapdata(query, 0)
|
||||
if(err) {
|
||||
return returnOnError(retur, ERR.NOSENSFOUND, getData4map.name)
|
||||
}
|
||||
for (let item of values) {
|
||||
const oneAktData = {
|
||||
location: item.location.loc.coordinates,
|
||||
id: item._id,
|
||||
name: item.name,
|
||||
indoor: item.location.indoor,
|
||||
value: Math.round(item.value[vtype] * 100) / 100
|
||||
}
|
||||
let now = new Date().getTime()
|
||||
let diff = now - item.timestamp
|
||||
if (diff >= 7 * 24 * 3600 * 1000) {
|
||||
oneAktData.value = -2
|
||||
} else if (diff >= 2 * 3600 * 1000) {
|
||||
oneAktData.value = -1
|
||||
}
|
||||
if (item.timestamp > lastDate) {
|
||||
lastDate = item.timestamp
|
||||
}
|
||||
aktData.push(oneAktData)
|
||||
}
|
||||
logit(`Query duration: ${start.diffNow('seconds').toObject().seconds * -1} sec`)
|
||||
retur.data.lastDate = lastDate
|
||||
retur.data.valuetype = vtype
|
||||
retur.data.count = aktData.length
|
||||
retur.data.values = aktData
|
||||
return retur
|
||||
}
|
||||
catch(e) {
|
||||
return returnOnError(retur, `catch\n${e}`, getData4map.name)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// get data for one sensor
|
||||
|
||||
import {DateTime} from "luxon"
|
||||
import { logit, logerror } from '../utilities/logit.js'
|
||||
import * as mongo from "../databases/mongo.js"
|
||||
import {reportError, returnOnError} from "../utilities/reporterror.js"
|
||||
import {csv2Json} from "../utilities/csv2json.js"
|
||||
|
||||
|
||||
// Fetch all akw data out of the dbase
|
||||
// router.get('/getakwdata/', async function (req, res) {
|
||||
export const getakwdata = async (options) => {
|
||||
let data = {err: null, ...options, count: 0, values: []}
|
||||
let erg = []
|
||||
try {
|
||||
let rawAKWs = await mongo.readAKWs(options)
|
||||
if (rawAKWs.err) {
|
||||
return returnOnError(date, rawAKWs.err, getakwdata.name)
|
||||
}
|
||||
for (let item of rawAKWs.values.akws) {
|
||||
var oneAktData = {};
|
||||
oneAktData['location'] = {
|
||||
type: 'Point',
|
||||
coordinates: [item.lon, item.lat]
|
||||
};
|
||||
oneAktData['name'] = item.Name;
|
||||
oneAktData['active'] = item.Status == 'aktiv';
|
||||
oneAktData['start'] = item.Baujahr;
|
||||
oneAktData['end'] = item.Stillgeleg;
|
||||
oneAktData['type'] = item.Status === 'aktiv' ? 'akw_a' : 'akw_s';
|
||||
oneAktData['link'] = item.Wiki_Link;
|
||||
erg.push(oneAktData); // dies ganzen Werte nun in das Array
|
||||
}
|
||||
for (let item of rawAKWs.values.th1_akws) {
|
||||
let oneAktData = {};
|
||||
let loc = item.geo.substr(6).split(' ');
|
||||
let lon = parseFloat(loc[0]);
|
||||
let lat = parseFloat(loc[1]);
|
||||
oneAktData['location'] = {
|
||||
type: 'Point',
|
||||
coordinates: [lon, lat]
|
||||
};
|
||||
oneAktData['name'] = item.name;
|
||||
oneAktData['typeText'] = item.types;
|
||||
oneAktData['type'] = item.types == "Nuclear power plant" ? 'akw_a' : 'other';
|
||||
oneAktData['link'] = item.item;
|
||||
if (item.itemServiceretirement != undefined) {
|
||||
oneAktData['ende'] = item.itemServiceretirement.substr(0, 4);
|
||||
}
|
||||
if (item.itemServiceentry != undefined) {
|
||||
oneAktData['begin'] = item.itemServiceentry.substr(0, 4);
|
||||
}
|
||||
erg.push(oneAktData);
|
||||
}
|
||||
data.values = erg
|
||||
data.count = erg.length
|
||||
} catch (e) {
|
||||
return returnOnError(data, e, getakwdata.name)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import {returnOnError} from "../utilities/reporterror.js"
|
||||
import axios from 'axios'
|
||||
import {logit} from "../utilities/logit.js"
|
||||
import {getOneProperty} from "./getproperties.js"
|
||||
|
||||
const NOMINATIM_URL = `https://nominatim.openstreetmap.org/reverse?lat=${'xx'}&lon=${'yy'}&format=json`
|
||||
|
||||
export const getAddress = async (params) => {
|
||||
let ret = {address: "", err: null}
|
||||
let {props, err} = await getOneProperty(params)
|
||||
if (err) {
|
||||
return returnOnError(ret, err, getAddress.name)
|
||||
}
|
||||
let coord = props.location[0].loc.coordinates
|
||||
let url = NOMINATIM_URL.replace('xx', coord[1]).replace('yy', coord[0])
|
||||
try {
|
||||
const response = await axios(encodeURI(url));
|
||||
if (response.status !== 200) {
|
||||
return returnOnError(ret, ERR.RESPSTATUS.replace('ss', response.status, getAddress.name))
|
||||
}
|
||||
let akt = response.data.address
|
||||
logit(JSON.stringify(akt))
|
||||
const CITY = ['city', 'town', 'village', 'suburb', 'county']
|
||||
let city = "unknown"
|
||||
for (let c of CITY) {
|
||||
if(akt[c] !== undefined) {
|
||||
city = akt[c]
|
||||
break
|
||||
}
|
||||
}
|
||||
ret.address = `${(akt.road ? akt.road : "")} ${(akt.postcode ? akt.postcode : "")} ${city}`;
|
||||
} catch (e) {
|
||||
return returnOnError(ret, e, getAddress.name)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
/*
|
||||
let addr = "Addr";
|
||||
try {
|
||||
let ret = await $.get("api/getprops?sensorid=" + marker.options.name);
|
||||
if(ret.values[0].address.city == null) {
|
||||
addr += " unbekannt !"
|
||||
} else {
|
||||
let akt = ret.values[0].address;
|
||||
addr = (akt.street ? akt.street : "") + " " + (akt.plz ? akt.plz : "") + " " + akt.city;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("onMarker - getpops", e)
|
||||
}
|
||||
console.log("addr:", addr);
|
||||
return addr;
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,55 @@
|
||||
// Fetch the properties for the given sensor
|
||||
|
||||
import * as mongo from "../databases/mongo.js"
|
||||
import * as mock from "../mocks/mongo_mock.js"
|
||||
import {returnOnError} from "../utilities/reporterror.js"
|
||||
import * as ERR from "../utilities/errortexts.js"
|
||||
import checkParams from "../utilities/checkparams.js"
|
||||
|
||||
const mockdb = false
|
||||
|
||||
let readProperties
|
||||
if (mockdb) {
|
||||
readProperties = mock.readProperties
|
||||
} else {
|
||||
readProperties = mongo.readProperties
|
||||
}
|
||||
export const getOneProperty = async (params) => {
|
||||
let properties = {props: {}, err: null}
|
||||
let {opts, err} = checkParams(params, {mandatory:[{name:'sensorid', type: 'int'}], optional:[]})
|
||||
if (err) {
|
||||
return returnOnError(properties, err, getOneProperty.name)
|
||||
}
|
||||
let sensorEntries = [];
|
||||
try {
|
||||
let pp = await readProperties({sid: opts.sensorid});
|
||||
if ((pp.values == null) || (pp.error)) {
|
||||
return returnOnError(properties, ERR.NOPROPSREAD.replace('xx', opts.sensorid), getOneProperty.name)
|
||||
}
|
||||
// now find sensors with same location
|
||||
let query
|
||||
if (pp.values.location_id !== undefined) {
|
||||
query = {location_id: pp.values.location_id}
|
||||
} else {
|
||||
query = {id: pp.values.id}
|
||||
}
|
||||
let others = await readProperties(query)
|
||||
if (others.error) {
|
||||
return returnOnError(properties, ERR.NOPROPSREAD.replace('xx',others.errortext), getOneProperty.name)
|
||||
}
|
||||
if (others.values.length > 0) {
|
||||
for (const x of others.values) {
|
||||
if(x.name[0].name === undefined) {
|
||||
sensorEntries.push({name: x.name, sid: x._id})
|
||||
} else {
|
||||
sensorEntries.push({name: x.name[0].name, sid: x._id})
|
||||
}
|
||||
}
|
||||
}
|
||||
properties.props = pp.values
|
||||
properties.props.othersensors = sensorEntries;
|
||||
} catch (e) {
|
||||
return returnOnError(properties, e, getOneProperty.name)
|
||||
}
|
||||
return properties
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
// get data for one sensor
|
||||
|
||||
import {DateTime} from "luxon"
|
||||
import * as influx from "../databases/influx.js"
|
||||
import {returnOnError} from "../utilities/reporterror.js"
|
||||
import {csv2Json} from "../utilities/csv2json.js"
|
||||
import checkParams from "../utilities/checkparams.js";
|
||||
import * as ERR from "../utilities/errortexts.js"
|
||||
import {getOneProperty} from "./getproperties.js";
|
||||
import {getNoiseData} from "../sensorspecials/noise.js";
|
||||
import {getRadioData} from "../sensorspecials/radioact.js";
|
||||
|
||||
// Possible params for the different sensor types
|
||||
const noiseParams = [
|
||||
{name:'data', type: 'string', default: 'live'},
|
||||
{name: 'span', type: 'int', default: ''},
|
||||
{name: 'daystart', type: 'bool', default: null},
|
||||
{name: 'peak', type: 'int', default: 70},
|
||||
{name: 'since', type: 'date', default: '1900-01-01T00:00:00Z'},
|
||||
{name: 'box', type: 'array', default: null},
|
||||
{name: 'out', type: 'string', default: ''},
|
||||
{name: 'csv', type: 'bool', default: false},
|
||||
{name: 'long', type: 'bool', default: false},
|
||||
{name: 'sort', type: 'int', default: 1},
|
||||
{name: 'last_seen', type: 'date', default: '1900-01-01T00:00:00Z'},
|
||||
{name: 'datetime', type: 'date', default: null}
|
||||
]
|
||||
const thpParams = []
|
||||
const pmParams = []
|
||||
const radioParams = []
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>> DUMMIES
|
||||
async function getPmData(opts) {
|
||||
|
||||
}
|
||||
async function getThpData(opts) {
|
||||
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<< DUMMIES
|
||||
|
||||
// Table for the different sensor types
|
||||
const sensorTypeTable = [
|
||||
{ typ: 'thp', possibleParams: thpParams, func: getThpData},
|
||||
{ typ: 'noise', possibleParams: noiseParams, func: getNoiseData},
|
||||
{ typ: 'pm', possibleParams: pmParams, func: getPmData},
|
||||
{ typ: 'radioactivity', possiblePramas: radioParams, func: getRadioData}
|
||||
]
|
||||
|
||||
/* Units:
|
||||
* span -> days
|
||||
* avg -> minutes
|
||||
*/
|
||||
|
||||
// *********************************************
|
||||
// calcRange
|
||||
//
|
||||
// Calculate the date/time range ro read the data from
|
||||
//
|
||||
// If 'datetime' is not given, use 'now()' as end and 'now()' - span as start
|
||||
// If 'datetime' is given, use it as start and 'datetime'+span as end
|
||||
// If 'daystart'==true, change start and end so, that they begin at 00:00:00h
|
||||
// if 'avg' has a value, move start backward ba 'avg' minutes
|
||||
//
|
||||
// params:
|
||||
// opts: Object with different options, specially
|
||||
// datetime, avg, daystart, span
|
||||
//
|
||||
// return:
|
||||
// Object with start and stop in ISO-Format
|
||||
// *********************************************
|
||||
export const calcRange = (opts) => {
|
||||
let start, end
|
||||
let ret = { start: start, stop: end, err: null}
|
||||
if((opts.datetime === null) || (opts.datetime === undefined) || (opts.datetime === '')) {
|
||||
start = end = DateTime.local().toUTC()
|
||||
start = start.minus({days: opts.span})
|
||||
} else {
|
||||
start = end = DateTime.fromISO(opts.datetime, {zone: 'utc'})
|
||||
end = end.plus({days: opts.span})
|
||||
}
|
||||
if(opts.daystart) {
|
||||
start = start.startOf("day")
|
||||
end = end.startOf("day")
|
||||
}
|
||||
if(opts.avg !== undefined) {
|
||||
start = start.minus({minutes: opts.avg})
|
||||
}
|
||||
ret.start = `start: ${start.toISO()}`
|
||||
ret.stop = `stop: ${end.toISO()}`
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
// *********************************************
|
||||
// getSensorData
|
||||
//
|
||||
// Depending on the parameter 'sensorid', ditribute to the speciell routines for
|
||||
// the sensors
|
||||
//
|
||||
// params:
|
||||
// params: all parameters from the url
|
||||
//
|
||||
// return:
|
||||
// Retirns from the special routines
|
||||
// *********************************************
|
||||
export const getSensorData = async (params) => {
|
||||
let ret = {err: null}
|
||||
let {opts, err} = checkParams(params, { // check for sensorid
|
||||
mandatory: [{name: 'sensorid', type: 'int'}],
|
||||
optional: []
|
||||
})
|
||||
if (err) {
|
||||
return returnOnError(ret, err, getSensordata.name)
|
||||
}
|
||||
// with the sensorid get the type of this sensor
|
||||
let {props, err1} = await getOneProperty({sensorid: opts.sensorid})
|
||||
if (err1) {
|
||||
return returnOnError(ret, err1, getSensorData.name)
|
||||
}
|
||||
|
||||
// distribute to the right routine
|
||||
for(let item of sensorTypeTable) {
|
||||
if(item.typ === props.type) {
|
||||
ret = item.func(params, item.possibleParams, props) // get the values from database
|
||||
return ret
|
||||
}
|
||||
}
|
||||
return returnOnError(ret, ERR.CMNDUNKOWN, getActData.name)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export const getActData = async (opts) => {
|
||||
let ret = {data: {count: 0, values: []}, err: null}
|
||||
let sorting = ''
|
||||
if(opts.sort) {
|
||||
if (opts.sort === 1) {
|
||||
sorting = '|> sort(columns: ["_time"], desc: false)'
|
||||
} else if (opts.sort === -1) {
|
||||
sorting = '|> sort(columns: ["_time"], desc: true)'
|
||||
}
|
||||
}
|
||||
// build the flux query
|
||||
let query = `
|
||||
from(bucket: "sensor_data")
|
||||
|> range(${opts.start}, ${opts.stop})
|
||||
|> filter(fn: (r) => r.sid == "${opts.sensorid}")
|
||||
${sorting}
|
||||
|> keep(columns: ["_time","_field","_value"])
|
||||
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|
||||
`
|
||||
return await fetchFromInflux(ret, query)
|
||||
}
|
||||
|
||||
|
||||
// ..../api/getavgdata?sensorid=123&span=2&avg=10&moving=true&datetime=2022-04-12T13:14:15Z
|
||||
export const getAvgData = async (params) => {
|
||||
let ret = {data: {count: 0, values: []}, err: null}
|
||||
let {opts, err} = checkParams(params,
|
||||
{
|
||||
mandatory:
|
||||
[
|
||||
{name: 'sensorid', type: 'int'},
|
||||
],
|
||||
optional:
|
||||
[
|
||||
{name: 'span', type: 'int', default: 1},
|
||||
{name: 'datetime', type: 'date', default: null},
|
||||
{name: 'avg', type: 'int', default: 10},
|
||||
{name: 'moving', type: 'bool', default: true},
|
||||
]
|
||||
}
|
||||
)
|
||||
if (err) {
|
||||
return returnOnError(ret, err, getActdata.name)
|
||||
}
|
||||
let {start, stop} = calcRange(opts)
|
||||
if (stop === '') {
|
||||
ret.data.start = DateTime.now().toUTC().minus({days: `${opts.span}`}).toFormat("yyyy-LL-dd'T'HH:mm:ss'Z'")
|
||||
} else {
|
||||
ret.data.start = DateTime.fromISO(opts.datetime, {zone: 'utc'}).toISO()
|
||||
}
|
||||
ret.data.span = opts.span
|
||||
ret.data.moving = opts.moving
|
||||
ret.data.avg = opts.avg
|
||||
|
||||
let every = opts.moving ? '150s' : `${opts.avg}m`
|
||||
let period = `${opts.avg}m`
|
||||
let query = `
|
||||
from(bucket: "sensor_data")
|
||||
|> range(${start}, ${stop})
|
||||
|> filter(fn: (r) => r.sid == "${opts.sensorid}")
|
||||
|> timedMovingAverage(every: ${every}, period: ${period})
|
||||
|> keep(columns: ["_time","_field","_value"])
|
||||
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|
||||
`
|
||||
return await fetchFromInflux(ret, query)
|
||||
}
|
||||
|
||||
// ..../api/getlongavg?sensorid=123&span=2
|
||||
export const getLongAvg = async (params) => {
|
||||
let ret = {data: {count: 0, values: []}, err: null}
|
||||
let {opts, err} = checkParams(params,
|
||||
{
|
||||
mandatory:
|
||||
[
|
||||
{name: 'sensorid', type: 'int'},
|
||||
],
|
||||
optional:
|
||||
[
|
||||
{name: 'span', type: 'int', default: 2},
|
||||
]
|
||||
}
|
||||
)
|
||||
if (err) {
|
||||
return returnOnError(ret, err, getActdata.name)
|
||||
}
|
||||
ret.data.span = opts.span
|
||||
let query = `
|
||||
from(bucket: "sensor_data")
|
||||
|> range(start: -${opts.span}d)
|
||||
|> filter(fn: (r) => r.sid == "${opts.sensorid}")
|
||||
|> mean()
|
||||
|> drop(columns: ["_start","_measurement", "sid"])
|
||||
|> pivot(rowKey:["_stop"], columnKey: ["_field"], valueColumn: "_value")
|
||||
`
|
||||
return fetchFromInflux(ret, query)
|
||||
}
|
||||
|
||||
|
||||
export const fetchFromInflux = async (data, query) => {
|
||||
let ret = {err: null}
|
||||
let { values, err} = await influx.influxRead(query)
|
||||
if(err) {
|
||||
if(err.toString().includes('400')) {
|
||||
return returnOnError(ret, ERR.SYNTAXURL, fetchFromInflux.name)
|
||||
} else {
|
||||
return returnOnError(ret, err, fetchFromInflux.name)
|
||||
}
|
||||
}
|
||||
if (values.length === 0) {
|
||||
return returnOnError(data, ERR.NODATA, fetchFromInflux.name)
|
||||
}
|
||||
ret.values = csv2Json(values)
|
||||
return ret
|
||||
}
|
||||
Reference in New Issue
Block a user