*** WIP WIP *** woks now for live and havg

This commit is contained in:
rxf
2023-03-27 09:56:18 +02:00
parent 26e4b75a6f
commit 126acfeb7f
11 changed files with 498 additions and 99 deletions
+1 -1
View File
@@ -67,7 +67,7 @@ const readLastDates = async (typ) => {
return await fetchFromInflux(ret, query)
}
export const getData4map = async (params) => {
export var getData4map = async (params) => {
let start = DateTime.now()
let ret = {err: null}
+7 -5
View File
@@ -104,7 +104,8 @@ export const calcRange = (opts) => {
// return:
// Returns from the special routines
// *********************************************
export const getSensorData = async (params) => {
// export const getSensorData = async (params) => {
export async function getSensorData(params) {
let ret = {err: null}
let {opts, err} = checkParams(params, { // check for sensorid
mandatory: [{name: 'sensorid', type: 'int'}],
@@ -116,7 +117,7 @@ export const getSensorData = async (params) => {
// with the sensorid get the type of this sensor
let erg = await getOneProperty({sensorid: opts.sensorid})
if (erg.err) {
return returnOnError(ret, err1, getSensorData.name)
return returnOnError(ret, erg.err, getSensorData.name)
}
// distribute to the right routine
@@ -132,7 +133,8 @@ export const getSensorData = async (params) => {
export const getActData = async (opts) => {
// export const getActData = async (opts) => {
export async function getActData(opts) {
let ret = {err: null, values: []}
let sorting = ''
if(opts.sort) {
@@ -156,7 +158,7 @@ ${sorting}
// ..../api/getavgdata?sensorid=123&span=2&avg=10&moving=true&datetime=2022-04-12T13:14:15Z
export const getAvgData = async (params) => {
export var getAvgData = async (params) => {
let ret = {data: {count: 0, values: []}, err: null}
let {opts, err} = checkParams(params,
{
@@ -200,7 +202,7 @@ export const getAvgData = async (params) => {
}
// ..../api/getlongavg?sensorid=123&span=2
export const getLongAvg = async (params) => {
export var getLongAvg = async (params) => {
let ret = {data: {count: 0, values: []}, err: null}
let {opts, err} = checkParams(params,
{
+3 -3
View File
@@ -5,8 +5,8 @@ import cookieParser from 'cookie-parser'
import cors from 'cors'
import indexRouter from './routes/index.js'
import { apiRouter } from './routes/api.js'
import chartRouter from './routes/chartapi.js'
import { apiRouter, chartapiRouter } from './routes/api.js'
// import chartRouter from './routes/chartapi.js'
const app = express()
@@ -18,7 +18,7 @@ app.use(cookieParser())
app.use('/', indexRouter)
app.use('/api', apiRouter)
app.use('/chart', chartRouter)
app.use('/chart', chartapiRouter)
// catch 404 and forward to error handler
+29 -4
View File
@@ -1,16 +1,33 @@
import express from 'express'
import {getData4map} from "../actions/data4map.js"
import * as cTable from "../utilities/commands.js"
import * as tables from "../utilities/tables.js"
import * as ERR from "../utilities/errortexts.js"
import * as getData from "../actions/getsensorData.js";
import * as getProps from "../actions/getproperties.js";
import * as getAKWs from "../actions/getAKWData.js";
import * as holAddr from "../actions/getaddress.js";
export const apiRouter = express.Router();
export const chartapiRouter = express.Router();
export const dispatchCommand = async (cmd, table, query, res) => {
const cmdTable = [
{cmd: 'getactdata', func: getData.getActData},
{cmd: 'getlongavg', func: getData.getLongAvg},
{cmd: 'getavgdata', func: getData.getAvgData},
{cmd: 'getoneproperty', func: getProps.getOneProperty},
{cmd: 'getakwdata', func: getAKWs.getakwdata},
{cmd: 'getaddress', func: holAddr.getAddress},
{cmd: 'getsensordata', func: getData.getSensorData},
{cmd: 'getmapdata', func: getData4map}
]
export const dispatchCommand = async (cmd, table, params, res) => {
for (let c of table) {
if (c.cmd === cmd) {
let erg = await c.func(query)
let erg = await c.func(params)
if (typeof erg === 'string') {
res.type('text')
res.send(erg)
@@ -25,6 +42,14 @@ export const dispatchCommand = async (cmd, table, query, res) => {
// normal routes called from javascript client
apiRouter.get('/:cmd', async (req, res) => {
await dispatchCommand(req.params.cmd, cTable.cmdTable, req.query, res)
const params = req.query
params.chart = false
await dispatchCommand(req.params.cmd, cmdTable, params, res)
})
// normal routes called from javascript client
chartapiRouter.get('/:cmd', async (req, res) => {
const params = req.query
params.chart = true
await dispatchCommand(req.params.cmd, cmdTable, params, res)
})
+8 -34
View File
@@ -1,40 +1,14 @@
import express from 'express'
import * as tables from "../utilities/tables.js"
import { dispatchCommand } from "./api.js"
import {getData4map} from "../actions/data4map.js"
import * as cTable from "../utilities/commands.js"
import * as ERR from "../utilities/errortexts.js"
const router = express.Router();
/* GET home page. */
const chartapiRouter = express.Router();
// normal routes called from javascript client
router.get('/:cmd', async (req, res) => {
const cmd = req.params.cmd
let table
for (let c of cTable.chartcmdTable) {
if (c.cmd === cmd) {
let erg = await c.func(req.query)
if (typeof erg === 'string') {
res.type('text')
res.send(erg)
} else {
res.json(erg)
}
return
}
}
res.json({err: ERR.CMNDUNKOWN})
chartapiRouter.get('/:cmd', async (req, res) => {
const params = req.query
params.kind = 'chart'
await dispatchCommand(req.params.cmd, tables.cmdTable, params, res)
})
router.post('/:cmd', async (req, res) => {
const cmd = req.params.cmd
if (cmd === 'getdata4maps') {
const erg = await getData4map(req.body)
res.json(erg)
} else {
res.json({err: ERR.CMNDUNKOWN})
}
})
export default router
export default chartapiRouter
-3
View File
@@ -1,7 +1,4 @@
import express from 'express'
import {getData4map} from "../actions/data4map.js"
import * as cTable from "../utilities/commands.js"
import * as ERR from "../utilities/errortexts.js"
const router = express.Router();
+23 -17
View File
@@ -4,11 +4,9 @@
import {returnOnError} from "../utilities/reporterror.js";
import { getActData, getAvgData, getLongAvg, fetchFromInflux, calcRange} from "../actions/getsensorData.js"
import checkParams from "../utilities/checkparams.js";
import {getOneProperty} from "../actions/getproperties.js";
import * as ERR from "../utilities/errortexts.js"
import {DateTime} from 'luxon'
import {getData4map} from "../actions/data4map.js";
import {NODATA} from "../utilities/errortexts.js";
import * as noiseChart from "./noiseChart.js";
const setoptionfromtable = (opt,tabval) => {
let ret = opt
@@ -25,6 +23,7 @@ export const getNoiseData = async (params, possibles, props) => {
let {opts, err} = checkParams(params, {
mandatory:[
{name:'sensorid', type: 'int'},
{name:'chart', type: 'bool'},
],
optional: possibles
})
@@ -44,6 +43,9 @@ export const getNoiseData = async (params, possibles, props) => {
opts.start = start
opts.stop = stop
let erg = await x.func(opts) // get the data
if (opts.chart) {
return erg
}
ret = {
err: erg.err,
sid: opts.sensorid,
@@ -92,8 +94,12 @@ export const getNoiseData = async (params, possibles, props) => {
// ....
//
// *********************************************
const getLiveData = async (opt) => {
return await getActData(opt)
const getLiveData = async (opts) => {
const erg = await getActData(opts)
if (!opts.chart || erg.err) {
return erg
}
return noiseChart.liveData(opts, erg.values)
}
@@ -135,9 +141,10 @@ const gethavgData = async (opts, props) => {
}
}
return csvStr
} else {
} else if (!opts.chart || erg.err) {
return {err: erg.err, values: erg.values}
} else {
return noiseChart.havgData(opts, erg.values)
}
}
@@ -413,16 +420,6 @@ const getAPIprops = (opt) => {
}
const whatTable = [
{'what':'live', 'span': 1, 'daystart': false, peak: false, 'func': getLiveData},
{'what':'havg', 'span': 7, 'daystart': true, peak: true, 'func': gethavgData},
{'what':'davg', 'span': 30, 'daystart': true, peak: true, 'func': getdavgData},
{'what':'daynight', 'span': 30, 'daystart': true, peak: false, 'func': getdaynightData},
{'what':'lden', 'span': 30, 'daystart': true, peak: false, 'func': getLdenData},
{'what':'props', 'span': 0, 'daystart': true, peak:false, 'func': getAPIprops},
];
const getNoiseAVGData = async (opts) => {
let ret = {err: null, values: []}
let emptyValues = {n_AVG:-1}
@@ -506,3 +503,12 @@ peak = data
return { err: ret.err, values: hoursArr}
}
const whatTable = [
{'what':'live', 'span': 1, 'daystart': false, peak: false, 'func': getLiveData},
{'what':'havg', 'span': 7, 'daystart': true, peak: true, 'func': gethavgData},
{'what':'davg', 'span': 30, 'daystart': true, peak: true, 'func': getdavgData},
{'what':'daynight', 'span': 30, 'daystart': true, peak: false, 'func': getdaynightData},
{'what':'lden', 'span': 30, 'daystart': true, peak: false, 'func': getLdenData},
{'what':'props', 'span': 0, 'daystart': true, peak:false, 'func': getAPIprops},
];
+272 -1
View File
@@ -1,2 +1,273 @@
// Prepare all data to plt the charts
// Prepare all data to plot the charts
import * as utils from '../utilities/chartoptions.js'
export const liveData = (params, values) => {
let series1 = []
let series2 = []
let series3 = []
// save the current (actual) values here
let aktVal = {}
// Put values into the arrays
let cnt = 0
values.forEach((x) => {
let dat = new Date(x.datetime).getTime()
series1.push([dat, x.noise_LAeq])
series2.push([dat, x.noise_LA_max])
series3.push([dat, x.noise_LA_min]) // put data and value into series array
})
if (values.length != 0) {
const lastidx = values.length - 1
// Aktuelle Werte speichern
aktVal['LAeq'] = values[lastidx].noise_LAeq
aktVal['LAMax'] = values[lastidx].noise_LA_max
aktVal['LAMin'] = values[lastidx].noise_LA_min
// InfoTafel füllen
let infoTafel =
'<table class="infoTafel"><tr >' +
'<th colspan="3">Aktuelle Werte</th>' +
'</tr><tr>' +
'<td>LAeq</td><td>' + (aktVal.LAeq).toFixed(1) + '</td><td>dbA</td>'
infoTafel +=
'</tr><tr>' +
'<td>LAmin</td><td>' + (aktVal.LAMin).toFixed(0) + '</td><td>dbA</td>'
infoTafel +=
'</tr><tr>' +
'<td>LAmax</td><td>' + (aktVal.LAMax).toFixed(0) + '</td><td>dbA</td>'
infoTafel +=
'</tr></table>' +
'</div>'
}
let txtMeldung = false
// Plot-Options
let options = utils.createGlobObtions('dd.LL HH:mm:ss')
let series_LAeq = {
name: 'LAeq',
data: series1,
color: utils.colors.eq,
yAxis: 0,
zIndex: 1,
marker: {
enabled: false,
symbol: 'square',
},
visible: true,
fillColor: {
linearGradient: [0, 600, 0, 0],
stops: [
[0, 'rgb(238,223,236)'],
[1, 'rgb(238,223,236)']
]
},
}
let series_LAMax = {
name: 'LAmax',
data: series2,
color: utils.colors.max,
yAxis: 0,
zIndex: 0,
marker: {
enabled: false,
symbol: 'square',
},
visible: true,
fillColor: {
linearGradient: [0, 600, 0, 0],
stops: [
[0, 'rgb(255,233,236)'],
[1, 'rgb(255,233,236)']
]
},
// fillOpacity: 0.2,
}
let series_LAMin = {
name: 'LAmin',
data: series3,
color: utils.colors.min,
yAxis: 0,
zIndex: 6,
marker: {
enabled: false,
symbol: 'square',
},
visible: true,
fillColor: {
linearGradient: [0, 600, 0, 0],
stops: [
[0, 'rgb(219,216,217)'],
[1, 'rgb(219,216,217)']
]
},
}
let yAxis_LAeq = { // 1
title: {
text: 'dbA',
style: {
color: 'black'
}
},
max: utils.noise_ymax,
// min: utils.noise_ymin,
min: 20,
// opposite: true,
tickAmount: 11,
useHTML: true,
}
options.series = []
options.yAxis = []
options.series[0] = series_LAeq
options.series[1] = series_LAMin
options.title.text = 'Noise level for one day'
options.subtitle.useHTML = true
options.subtitle.text = '2.5min log. average values <br /> &nbsp'
options.series[2] = series_LAMax
// options.yAxis[2] = yAxis_LAMin
options.yAxis[0] = yAxis_LAeq
// options.yAxis[1] = yAxis_LAMax
options.chart.zoomType = 'x'
options.chart.type = 'area'
options.chart.resetZoomButton= {
position: {
align: 'left',
verticalAlign: 'bottom',
x: 20,
y: -50,
},
relativeTo: 'chart'
}
options.tooltip.formatter = function () {
let y = Math.round(this.y * 100) / 100
return '<div style="border: 2px solid ' + this.point.color + '; padding: 3px;">' +
DateTime.fromMillis(this.x, {zone: 'utc'}).toFormat("dd.LL - HH:mm:ss") + '<br />' +
'<span style="color: ' + this.point.color + '">&#9679;&nbsp;</span>' +
this.series.name + ':&nbsp; <b>' + y + '</b></div>'
}
let noDataTafel = '<div class="errTafel">' +
'Für heute liegen leider keine Daten vor!<br /> Bitte den Sensor überprüfen!\' <br />' +
'</div>'
let navy = 20
let navbreit = 55
let navtxt = ['-24h', '-12h', 'live', '+12h', '+24h']
let navtime = [-24, -12, 0, 12, 24]
return { options: options, params: params}
}
export const havgData = (params, values) => {
let series1 = []
let series2 = []
// Put values into the serieses
let cnt = 0
values.forEach((x) => {
if (x.n_AVG != -1) {
let dat = new Date(x.datetime).getTime() // retrieve the date
series1.push([dat, x.n_AVG])
series2.push([dat, x.peakcount])
}
})
// Plot-Options
let options = utils.createGlobObtions()
options.xAxis.tickInterval = 6 * 3600 * 1000
// options.xAxis.plotBands = utils.calcWeekends(data, true)
options.xAxis.minTickInterval = 3600 * 1000
options.yAxis = {
title: {
text: 'dbA',
useHTML: true,
},
min: utils.noise_ymin,
tickAmount: 10,
gridLineColor: 'lightgray',
}
options.series = [
{
name: 'Mean value LAeq',
data: series1,
color: utils.colors.eq,
type: 'column',
zIndex: 2,
},
]
options.plotOptions.column = {
pointWidth: 8,
groupPadding: 0.5
}
options.title.text = 'Noise hourly mean values'
options.subtitle.text = 'Hourly mean values of LAeq for each full hour <br />&nbsp'
options.subtitle.useHTML = true
options.chart.zoomType = 'x'
options.chart.height = 350
options.chart.resetZoomButton= {
position: {
align: 'left',
// verticalAlign: 'bottom',
x: 20,
y: 300,
},
relativeTo: 'chart'
}
options.tooltip.formatter = function () {
let y = Math.round(this.y * 10) / 10
return '<div style="border: 2px solid ' + this.point.color + '; padding: 3px;">' +
DateTime.fromMillis(this.x, {zone: 'utc'}).toFormat("dd.LL - HH'h'") + '<br />' +
'<span style="color: ' + this.point.color + '">&#9679;&nbsp;</span>' +
this.series.name + ':&nbsp; <b>' + y + '</b></div>'
}
return { options: options, params: params}
/*
// Do PLOT 1
let ch = Highcharts.chart('dhour', options, function (chart) {
utils.addSensorID2chart(chart, {sid: data.sid, indoor: data.indoor}, document.getElementById('dhour').offsetWidth)
})
// Do PLOT 2
options.series[0] = {
name: 'Peaks',
data: series2,
color: utils.colors.peaks,
type: 'column'
}
options.title.text = 'Peaks more than ' + data.peak + ' dbA'
options.subtitle.text = 'Number of exceedances per hour <br />&nbsp'
options.yAxis = {
title: {
text: 'Counts',
useHTML: true,
},
tickAmount: 10,
allowDecimals: false,
gridLineColor: 'lightgray',
}
options.tooltip.formatter = function () {
let y = Math.round(this.y)
return '<div style="border: 2px solid ' + this.point.color + '; padding: 3px;">' +
DateTime.fromMillis(this.x, {zone: 'utc'}).toFormat("dd.LL - HH'h'") + '<br />' +
'<span style="color: ' + this.point.color + '">&#9679;&nbsp;</span>' +
this.series.name + ':&nbsp; <b>' + y + '</b></div>'
}
let ch1 = Highcharts.chart('dpeak', options)
}
*/
}
+142
View File
@@ -0,0 +1,142 @@
// Utility routine for plotting the data
export const colors = {'eq': '#0000FF', 'max': '#FF0000', 'min': '#008000', 'peaks': '#DAA520'};
export function createGlobObtions() {
// Options, die für alle Plots identisch sind
let globObject = {
chart: {
height: 600,
// width: 1000,
spacingRight: 20,
spacingLeft: 20,
spacingTop: 25,
backgroundColor: {
linearGradient: [0, 400, 0, 0],
stops: [
[0, '#eee'],//[0, '#ACD0AA'], //[0, '#A18D99'], // [0, '#886A8B'], // [0, '#F2D0B5'],
[1, '#fff']
]
},
type: 'line',
borderWidth: '2',
events: {
selection: function (event) {
if (event.xAxis) {
doUpdate = false;
} else {
doUpdate = true;
}
}
}
},
title: {
// text: 'Feinstaub über 1 Tag',
align: 'left',
style: {'fontSize': '25px'},
useHTML: true,
},
subtitle: {
// text: 'Gemessene Werte und ' + avgTime + 'min-gleitende Mittelwerte',
align: 'left',
},
tooltip: {
valueDecimals: 1,
backgroundColor: 0,
borderWidth: 0,
borderRadius: 0,
useHTML: true,
},
xAxis: {
type: 'datetime',
title: {
text: 'date/time',
},
gridLineWidth: 2,
labels: {
formatter: function () {
let v = this.axis.defaultLabelFormatter.call(this);
if (v.indexOf(':') == -1) {
return '<span style="font-weight:bold;color:red">' + v + '<span>';
} else {
return v;
}
}
},
},
legend: {
enabled: true,
layout: 'horizontal',
// verticalAlign: 'top',
borderWidth: 1,
align: 'center',
},
plotOptions: {
series: {
animation: false,
turboThreshold: 0,
marker: {
enabled: false,
},
},
}
};
return globObject;
}
export function calcWeekends(data, isyear) {
let weekend = [];
let oldDay = 8;
for (let i = 0; i < data.length; i++) {
let mom = moment(data[i].date);
if (isyear) {
mom = moment(data[i]._id)
}
let day = mom.day();
let st = mom.startOf('day');
if (day != oldDay) {
if (day == 6) {
weekend.push({
color: 'rgba(169,235,158,0.4)',
from: st.valueOf(),
to: st.add(1, 'days').valueOf(),
zIndex: 0
})
} else if (day == 0) {
weekend.push({
color: 'rgba(169,235,158,0.4)',
from: st.valueOf(),
to: st.add(1, 'days').valueOf(),
zIndex: 0
})
}
oldDay = day;
}
}
return weekend;
}
export function calcDays(data, isyear) {
let days = [];
if (data.length == 0) {
return days
}
let oldday = moment(data[0].date).day();
if (isyear) {
oldday = moment(data[0]._id).day();
}
for (let i = 0; i < data.length; i++) {
let m = moment(data[i].date);
if (isyear) {
m = moment(data[i]._id);
}
let tag = m.day()
if (tag != oldday) {
m.startOf('day');
days.push({color: 'lightgray', value: m.valueOf(), width: 1, zIndex: 2});
oldday = tag;
}
}
return days;
};
-31
View File
@@ -1,31 +0,0 @@
// Command table for http calls
import * as getData from "../actions/getsensorData.js"
import * as getProps from "../actions/getproperties.js"
import * as getAKWs from "../actions/getAKWData.js"
import * as holAddr from "../actions/getaddress.js"
import * as radioact from "../sensorspecials/radioact.js"
import * as noise from "../sensorspecials/noise.js"
import {getData4map} from "../actions/data4map.js";
export const cmdTable = [
{cmd: 'getactdata', func: getData.getActData},
{cmd: 'getlongavg', func: getData.getLongAvg},
{cmd: 'getavgdata', func: getData.getAvgData},
{cmd: 'getoneproperty', func: getProps.getOneProperty},
{cmd: 'getakwdata', func: getAKWs.getakwdata},
{cmd: 'getaddress', func: holAddr.getAddress},
{cmd: 'getsensordata', func: getData.getSensorData},
{cmd: 'getmapdata', func: getData4map}
]
export const chartcmdTable = [
{cmd: 'getactdata', func: getData.getActData},
{cmd: 'getlongavg', func: getData.getLongAvg},
{cmd: 'getavgdata', func: getData.getAvgData},
{cmd: 'getoneproperty', func: getProps.getOneProperty},
{cmd: 'getakwdata', func: getAKWs.getakwdata},
{cmd: 'getaddress', func: holAddr.getAddress},
{cmd: 'getsensordata', func: getData.getChartSensorData},
{cmd: 'getmapdata', func: getData4map}
]
+13
View File
@@ -0,0 +1,13 @@
// Command table for http calls
import * as getData from "../actions/getsensorData.js"
import * as getProps from "../actions/getproperties.js"
import * as getAKWs from "../actions/getAKWData.js"
import * as holAddr from "../actions/getaddress.js"
import * as radioact from "../sensorspecials/radioact.js"
import * as noise from "../sensorspecials/noise.js"
import {getData4map} from "../actions/data4map.js"
import * as noiseChart from '../sensorspecials/noiseChart.js'