diff --git a/server/src/influx.mjs b/server/src/influx.mjs index afb4ef4..3749380 100644 --- a/server/src/influx.mjs +++ b/server/src/influx.mjs @@ -1,11 +1,11 @@ import {cfg} from './config.mjs'; -const MEASUREMENTS = ['accumulation', 'environment', 'light', 'lightning', 'rain', 'seismic', 'wind']; - -async function query(c, q) { +async function query(c, q, start, end) { const url = new URL('/api/v1/query_range', c.INFLUX_URL); url.searchParams.set('query', q); - url.searchParams.set('step', '60s'); + url.searchParams.set('step', '60s'); + if (start) url.searchParams.set('start', start); + if (end) url.searchParams.set('end', end); const res = await fetch(url); const json = await res.json(); return json.data?.result || []; @@ -29,69 +29,67 @@ function metricToFields(results) { return out; } +// vm.mjs export async function queryCurrent() { const c = cfg(); - const now = Math.floor(Date.now() / 1000); const out = {time: new Date()}; - for (const m of MEASUREMENTS) { - const results = await queryInstant(c, `{measurement="${m}"}`); - Object.assign(out, metricToFields(results)); - } + // Query all metrics at once, no measurement filter needed + const results = await queryInstant(c, `{__name__!=""}`); + Object.assign(out, metricToFields(results)); return out; } export async function queryHourly(start, end) { - const c = cfg(); - const s = Math.floor(start.getTime() / 1000); - const e = Math.floor(end.getTime() / 1000); + const c = cfg(); + const s = Math.floor(start.getTime() / 1000); + const e = Math.floor(end.getTime() / 1000); const byTime = {}; - for (const m of MEASUREMENTS) { - const results = await query(c, `avg_over_time({measurement="${m}"}[1h])`); - results.forEach(r => { - const field = r.metric.__name__; - r.values.forEach(([ts, val]) => { - const time = new Date(ts * 1000).toISOString().slice(0, 13) + ':00'; - if (!byTime[time]) byTime[time] = {time}; - byTime[time][field] = parseFloat(val); - }); + const results = await query(c, `avg_over_time({__name__!=""}[1h])`, s, e); + results.forEach(r => { + const field = r.metric.__name__; + r.values.forEach(([ts, val]) => { + const time = new Date(ts * 1000).toISOString().slice(0, 13) + ':00'; + if (!byTime[time]) byTime[time] = {time}; + byTime[time][field] = parseFloat(val); }); - } + }); return Object.values(byTime).sort((a, b) => a.time.localeCompare(b.time)); } export async function queryDaily(start, end) { const c = cfg(); + const s = Math.floor(start.getTime() / 1000); + const e = Math.floor(end.getTime() / 1000); const byTime = {}; - for (const m of ['accumulation', 'environment', 'light', 'lightning', 'seismic']) { - const [means, mins, maxs] = await Promise.all([ - query(c, `avg_over_time({measurement="${m}"}[1d])`), - query(c, `min_over_time({measurement="${m}"}[1d])`), - query(c, `max_over_time({measurement="${m}"}[1d])`), - ]); + const [means, mins, maxs] = await Promise.all([ + query(c, `avg_over_time({__name__!=""}[1d])`, s, e), + query(c, `min_over_time({__name__!=""}[1d])`, s, e), + query(c, `max_over_time({__name__!=""}[1d])`, s, e), + ]); - means.forEach(r => { - r.values.forEach(([ts, val]) => { - const time = new Date(ts * 1000).toISOString().slice(0, 10); - if (!byTime[time]) byTime[time] = {time}; - byTime[time][r.metric.__name__] = parseFloat(val); - }); + means.forEach(r => { + r.values.forEach(([ts, val]) => { + const time = new Date(ts * 1000).toISOString().slice(0, 10); + if (!byTime[time]) byTime[time] = {time}; + byTime[time][r.metric.__name__] = parseFloat(val); }); + }); - const applyMinMax = (results, suffix) => results.forEach(r => { - if (r.metric.__name__ !== 'temperature') return; - r.values.forEach(([ts, val]) => { - const time = new Date(ts * 1000).toISOString().slice(0, 10); - if (!byTime[time]) byTime[time] = {time}; - byTime[time][suffix] = parseFloat(val); - }); + const applyMinMax = (results, suffix) => results.forEach(r => { + if (r.metric.__name__ !== 'temperature') return; + r.values.forEach(([ts, val]) => { + const time = new Date(ts * 1000).toISOString().slice(0, 10); + if (!byTime[time]) byTime[time] = {time}; + byTime[time][suffix] = parseFloat(val); }); + }); + + applyMinMax(mins, 'env_temp_min_c'); + applyMinMax(maxs, 'env_temp_max_c'); - applyMinMax(mins, 'env_temp_min_c'); - applyMinMax(maxs, 'env_temp_max_c'); - } return Object.values(byTime).sort((a, b) => a.time.localeCompare(b.time)); } diff --git a/setup.sh b/setup.sh index 3058573..778838a 100755 --- a/setup.sh +++ b/setup.sh @@ -3,7 +3,6 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" USER_NAME="$(whoami)" -VM_VERSION="1.99.0" VM_DIR="/opt/victoriametrics" echo "🔧 Setting up Weather Station..." @@ -13,10 +12,9 @@ echo "🔧 Setting up Weather Station..." if ! systemctl is-enabled --quiet victoriametrics 2>/dev/null; then echo "📦 Installing VictoriaMetrics..." sudo mkdir -p $VM_DIR/data - - wget -qO /tmp/vm.tar.gz \ - "https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v${VM_VERSION}/victoria-metrics-arm-v7-v${VM_VERSION}.tar.gz" - sudo tar xf /tmp/vm.tar.gz -C $VM_DIR + cd $VM_DIR + wget -qO vm.tar.gz "https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.146.0/victoria-metrics-linux-arm64-v1.146.0.tar.gz" + sudo tar -xzf vm.tar.gz sudo chmod +x $VM_DIR/victoria-metrics-prod rm /tmp/vm.tar.gz