248 lines
7.9 KiB
JavaScript
248 lines
7.9 KiB
JavaScript
// 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
|
|
}
|