mirror of
https://github.com/KevinMidboe/brewPi.git
synced 2025-10-29 08:40:13 +00:00
/graph API endpoint for proxy to elastic, all use this endpoint or lib/server functions to get data
This commit is contained in:
@@ -83,8 +83,8 @@ function buildQuery(field: String, from: Date, to: Date, interval: String) {
|
||||
{
|
||||
range: {
|
||||
'@timestamp': {
|
||||
gte: toDateString,
|
||||
lte: fromDateString,
|
||||
gte: fromDateString,
|
||||
lte: toDateString,
|
||||
format: 'strict_date_optional_time'
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,7 @@ function calculateInterval(from, to, interval, size) {
|
||||
if (interval !== 'auto') {
|
||||
return interval;
|
||||
}
|
||||
const dateMathInterval = roundInterval((from - to) / size);
|
||||
const dateMathInterval = roundInterval((to - from) / size);
|
||||
// const dateMathIntervalMs = toMS(dateMathInterval);
|
||||
// const minMs = toMS(min);
|
||||
// if (dateMathIntervalMs !== undefined && minMs !== undefined && dateMathIntervalMs < minMs) {
|
||||
@@ -148,6 +148,7 @@ function calculateInterval(from, to, interval, size) {
|
||||
}
|
||||
|
||||
function parseTempResponse(data: IESTelemetry): IChartFrame[] {
|
||||
console.log('got temp response:', data);
|
||||
return data?.aggregations?.data?.buckets.map((bucket) => {
|
||||
return {
|
||||
value: bucket?.maxValue?.value,
|
||||
@@ -161,12 +162,7 @@ function parseLatestResponse(data: IESTelemetry) {
|
||||
return data?.hits?.hits[0]?._source;
|
||||
}
|
||||
|
||||
export function fetchTemperature(
|
||||
from: Date,
|
||||
to: Date,
|
||||
size: number = 50,
|
||||
fetch: Function
|
||||
): Promise<IChartFrame[]> {
|
||||
export function fetchTemperature(from: Date, to: Date, size: number = 50): Promise<IChartFrame[]> {
|
||||
const fromMS = from.getTime();
|
||||
const toMS = to.getTime();
|
||||
const interval = calculateInterval(fromMS, toMS, 'auto', size);
|
||||
@@ -181,18 +177,14 @@ export function fetchTemperature(
|
||||
},
|
||||
body: JSON.stringify(esSearchQuery)
|
||||
};
|
||||
console.log('temp options:', options);
|
||||
|
||||
return fetch(TELEMETRY_ENDPOINT, options)
|
||||
.then((resp) => resp.json())
|
||||
.then(parseTempResponse);
|
||||
}
|
||||
|
||||
export function fetchHumidity(
|
||||
from: Date,
|
||||
to: Date,
|
||||
size: number = 50,
|
||||
fetch: Function
|
||||
): Promise<IChartFrame[]> {
|
||||
export function fetchHumidity(from: Date, to: Date, size: number = 50): Promise<IChartFrame[]> {
|
||||
const fromMS = from.getTime();
|
||||
const toMS = to.getTime();
|
||||
const interval = calculateInterval(fromMS, toMS, 'auto', size);
|
||||
@@ -213,12 +205,7 @@ export function fetchHumidity(
|
||||
.then(parseTempResponse);
|
||||
}
|
||||
|
||||
export function fetchPressure(
|
||||
from: Date,
|
||||
to: Date,
|
||||
size: number = 50,
|
||||
fetch: Function
|
||||
): Promise<IChartFrame[]> {
|
||||
export function fetchPressure(from: Date, to: Date, size: number = 50): Promise<IChartFrame[]> {
|
||||
const fromMS = from.getTime();
|
||||
const toMS = to.getTime();
|
||||
const interval = calculateInterval(fromMS, toMS, 'auto', size);
|
||||
@@ -1,7 +1,5 @@
|
||||
import { getLatestInsideReadings, getLatestOutsideReadings } from '$lib/graphQueryGenerator';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
let DEFAULT_MINUTES = 14400;
|
||||
const host = 'http://brewpi.schleppe:5000';
|
||||
const sensorsUrl = `${host}/api/sensors`;
|
||||
const relaysUrl = `${host}/api/relays`;
|
||||
@@ -24,8 +22,6 @@ async function getRelays() {
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
const [sensors, relays] = await Promise.all([getSensors(), getRelays()]);
|
||||
console.log('got sensors and relays');
|
||||
console.log(sensors, relays);
|
||||
|
||||
const inside = sensors.find((sensor) => sensor.location === 'inside');
|
||||
const outside = sensors.find((sensor) => sensor.location === 'outside');
|
||||
|
||||
39
src/routes/api/graph/[unit]/+server.ts
Normal file
39
src/routes/api/graph/[unit]/+server.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { json, RequestEvent } from '@sveltejs/kit';
|
||||
import {
|
||||
fetchTemperature,
|
||||
fetchHumidity,
|
||||
fetchPressure
|
||||
} from '../../../../lib/server/graphQueryGenerator';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
const UNITS = ['temperature', 'humidity', 'pressure'];
|
||||
const UNITS_STRING = UNITS.join(', ');
|
||||
|
||||
export const POST = (async (event: RequestEvent) => {
|
||||
const { request, params } = event;
|
||||
|
||||
const { unit } = params;
|
||||
if (!unit || UNITS.indexOf(unit) == -1) {
|
||||
return json({
|
||||
success: false,
|
||||
message: `Unit ${unit} not found. Choose from: ${UNITS_STRING}`
|
||||
});
|
||||
}
|
||||
|
||||
const bodyData = await request.json();
|
||||
let data;
|
||||
let { from, to } = bodyData;
|
||||
const { size } = bodyData;
|
||||
from = new Date(from);
|
||||
to = new Date(to);
|
||||
|
||||
if (unit === 'temperature') {
|
||||
data = await fetchTemperature(from, to, size);
|
||||
} else if (unit === 'humidity') {
|
||||
data = await fetchHumidity(from, to, size);
|
||||
} else if (unit === 'pressure') {
|
||||
data = await fetchPressure(from, to, size);
|
||||
}
|
||||
|
||||
return json({ success: true, data });
|
||||
}) satisfies RequestHandler;
|
||||
@@ -1,13 +1,21 @@
|
||||
import { fetchTemperature, fetchHumidity, fetchPressure } from '$lib/graphQueryGenerator';
|
||||
import {
|
||||
fetchTemperature,
|
||||
fetchHumidity,
|
||||
fetchPressure
|
||||
} from '../../lib/server/graphQueryGenerator';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import type IChartFrame from '$lib/interfaces/IChartFrame';
|
||||
import type IChartFrame from '../../lib/interfaces/IChartFrame';
|
||||
|
||||
let DEFAULT_MINUTES = 10080;
|
||||
const DEFAULT_MINUTES = 10080;
|
||||
|
||||
export const load: PageServerLoad = async ({ fetch }) => {
|
||||
const temperatureData: IChartFrame[] = await getTemp(DEFAULT_MINUTES, fetch);
|
||||
const humidityData: IChartFrame[] = await getHumidity(DEFAULT_MINUTES, fetch);
|
||||
const pressureData: IChartFrame[] = await getPressure(DEFAULT_MINUTES, fetch);
|
||||
const to = new Date();
|
||||
const from = new Date(to.getTime() - DEFAULT_MINUTES * 60 * 1000);
|
||||
const size = 40;
|
||||
|
||||
const temperatureData: IChartFrame[] = await fetchTemperature(from, to, size);
|
||||
const humidityData: IChartFrame[] = await fetchHumidity(from, to, size);
|
||||
const pressureData: IChartFrame[] = await fetchPressure(from, to, size);
|
||||
|
||||
return {
|
||||
temperatureData,
|
||||
@@ -16,23 +24,3 @@ export const load: PageServerLoad = async ({ fetch }) => {
|
||||
DEFAULT_MINUTES
|
||||
};
|
||||
};
|
||||
|
||||
function getSensor(func: Function, minutes: number, fetch: Function) {
|
||||
const from: Date = new Date();
|
||||
const to = new Date(from.getTime() - minutes * 60 * 1000);
|
||||
const size = 40;
|
||||
|
||||
return func(from, to, size, fetch);
|
||||
}
|
||||
|
||||
function getTemp(minutes: number, fetch: Function): IChartFrame[] {
|
||||
return getSensor(fetchTemperature, minutes, fetch);
|
||||
}
|
||||
|
||||
function getHumidity(minutes: number, fetch: Function): IChartFrame[] {
|
||||
return getSensor(fetchHumidity, minutes, fetch);
|
||||
}
|
||||
|
||||
function getPressure(minutes: number, fetch: Function): IChartFrame[] {
|
||||
return getSensor(fetchPressure, minutes, fetch);
|
||||
}
|
||||
|
||||
@@ -1,55 +1,48 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { fetchTemperature, fetchHumidity, fetchPressure } from '$lib/graphQueryGenerator';
|
||||
import Graph from '$lib/components/Graph.svelte';
|
||||
import type IChartFrame from '$lib/interfaces/IChartFrame';
|
||||
import Graph from '../../lib/components/Graph.svelte';
|
||||
import type IChartFrame from '../../lib/interfaces/IChartFrame';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData
|
||||
export let data: PageData;
|
||||
|
||||
let temperatureData: IChartFrame[] = data?.temperatureData;
|
||||
let humidityData: IChartFrame[] = data?.temperatureData;
|
||||
let pressureData: IChartFrame[] = data?.temperatureData;
|
||||
let DEFAULT_MINUTES: number = data?.DEFAULT_MINUTES
|
||||
let humidityData: IChartFrame[] = data?.humidityData;
|
||||
let pressureData: IChartFrame[] = data?.pressureData;
|
||||
let DEFAULT_MINUTES: number = data?.DEFAULT_MINUTES;
|
||||
let minutes: number = DEFAULT_MINUTES;
|
||||
|
||||
const buttonMinutes = [{
|
||||
value: 15,
|
||||
name: 'Last 15 minutes'
|
||||
}, {
|
||||
value: 60,
|
||||
name: 'Last hour'
|
||||
}, {
|
||||
value: 1440,
|
||||
name: 'Last day'
|
||||
}, {
|
||||
value: 10080,
|
||||
name: 'Last week'
|
||||
}, {
|
||||
value: 43200,
|
||||
name: 'Last month'
|
||||
}, {
|
||||
value: 129600,
|
||||
name: 'Last 3 months'
|
||||
}, {
|
||||
value: 259200,
|
||||
name: 'Last 6 months'
|
||||
}, {
|
||||
value: 518400,
|
||||
name: 'Last year',
|
||||
}]
|
||||
async function fetchData(unit: string, from: Date, to: Date, size: number) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ from, to, size })
|
||||
};
|
||||
|
||||
return fetch(`/api/graph/${unit}`, options).then((resp) => resp.json());
|
||||
}
|
||||
|
||||
const buttonMinutes = [
|
||||
{ value: 15, name: 'Last 15 minutes' },
|
||||
{ value: 60, name: 'Last hour' },
|
||||
{ value: 360, name: 'Last 6 hours' },
|
||||
{ value: 1440, name: 'Last day' },
|
||||
{ value: 10080, name: 'Last week' },
|
||||
{ value: 43200, name: 'Last month' },
|
||||
{ value: 129600, name: 'Last 3 months' },
|
||||
{ value: 259200, name: 'Last 6 months' },
|
||||
{ value: 518400, name: 'Last year' }
|
||||
];
|
||||
|
||||
function reload(mins: number) {
|
||||
minutes = mins
|
||||
const from: Date = new Date();
|
||||
const to = new Date(from.getTime() - minutes * 60 * 1000);
|
||||
minutes = mins;
|
||||
const to: Date = new Date();
|
||||
const from = new Date(to.getTime() - minutes * 60 * 1000);
|
||||
const size = 40;
|
||||
|
||||
fetchTemperature(from, to, size, window.fetch).then((resp) => (temperatureData = resp));
|
||||
fetchHumidity(from, to, size, window.fetch).then((resp) => (humidityData = resp));
|
||||
fetchPressure(from, to, size, window.fetch).then((resp) => (pressureData = resp));
|
||||
fetchData('temperature', from, to, size).then((resp) => (temperatureData = resp?.data));
|
||||
fetchData('humidity', from, to, size).then((resp) => (humidityData = resp?.data));
|
||||
fetchData('pressure', from, to, size).then((resp) => (pressureData = resp?.data));
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- <h1>Server: {emoji.emoji}</h1> -->
|
||||
|
||||
@@ -57,24 +50,27 @@
|
||||
|
||||
<div class="button-wrapper">
|
||||
{#each buttonMinutes as button}
|
||||
<button on:click={() => reload(button.value)} class="{button.value === minutes ? 'selected' : ''}">{ button.name }</button>
|
||||
<button
|
||||
on:click="{() => reload(button.value)}"
|
||||
class="{button.value === minutes ? 'selected' : ''}">{button.name}</button
|
||||
>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<section class="graphs">
|
||||
{#if temperatureData}
|
||||
<div class="graphWrapper">
|
||||
<Graph dataFrames={temperatureData} name="Temperature" />
|
||||
<div class="card">
|
||||
<Graph dataFrames="{temperatureData}" name="Temperature" />
|
||||
</div>
|
||||
{/if}
|
||||
{#if humidityData}
|
||||
<div class="graphWrapper">
|
||||
<Graph dataFrames={humidityData} name="Humidity" beginAtZero={false} />
|
||||
<div class="card">
|
||||
<Graph dataFrames="{humidityData}" name="Humidity" />
|
||||
</div>
|
||||
{/if}
|
||||
{#if pressureData}
|
||||
<div class="graphWrapper">
|
||||
<Graph dataFrames={pressureData} name="Pressure" beginAtZero={false} />
|
||||
<div class="card">
|
||||
<Graph dataFrames="{pressureData}" name="Pressure" />
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
@@ -89,17 +85,21 @@
|
||||
width: 100%;
|
||||
|
||||
@include mobile {
|
||||
grid-template-columns: 1fr;
|
||||
display: block;
|
||||
> *:not(*:first-child) {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.graphWrapper {
|
||||
max-width: 100vw;
|
||||
.card {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
display: flex;
|
||||
width: min-content;
|
||||
margin: 1rem 0;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
Reference in New Issue
Block a user