// 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 }