DTO interfaces for API responses.

This commit is contained in:
2023-08-27 13:43:04 +02:00
parent b9a5fde53f
commit f5f759ca0a
6 changed files with 129 additions and 47 deletions

View File

@@ -1,22 +1,31 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte' import { onMount } from 'svelte';
import CardButton from "./CardButton.svelte"; import CardButton from './CardButton.svelte';
import Activity from "../icons/Activity.svelte"; import Activity from '../icons/Activity.svelte';
import { ISensorDTO } from '../interfaces/ISensorDTO';
import { IRelaysDTO } from '../interfaces/IRelaysDTO';
import { IStateDTO } from '../interfaces/IStateDTO';
export let inside; export let inside: ISensorDTO;
export let outside; export let outside: ISensorDTO;
export let relays: IRelaysDTO[] = [];
export let state: IStateDTO;
let loadedTime: number = new Date().getTime(); let loadedTime: number = new Date().getTime();
let currentTime: number = new Date().getTime(); let currentTime: number = new Date().getTime();
let autoReload = false; let autoReload = false;
const currentGoal = 18.5;
function updateTime() { function updateTime() {
currentTime = new Date().getTime(); currentTime = new Date().getTime();
} }
function flipCard(): void { function flipCard(): void {
console.log("flip-a-delphia") console.log('flip-a-delphia');
}
function tempToStateClass(temp: number | undefined) {
if (temp === undefined || !!isNaN(temp)) return 'idle';
return Number(temp) > 14 ? 'heating' : 'cooling';
} }
onMount(() => setInterval(updateTime, 1000)); onMount(() => setInterval(updateTime, 1000));
@@ -24,41 +33,47 @@
</script> </script>
<div class="card"> <div class="card">
<h1>Fridge sensors</h1>
<CardButton> <CardButton>
<Activity on:click={flipCard} /> <Activity on:click="{flipCard}" />
</CardButton> </CardButton>
<h2>Current target temperature</h2> <h2>Current target temperature</h2>
<div class="sensor-reading"> <div class="sensor-reading">
<div class="blue"> <div class="{state.state}">
<span class="value">{currentGoal}</span> <span class="value">{state.goal}</span>
<span class="unit">°C</span> <span class="unit">°C</span>
</div> </div>
</div>
<h2>Inside temperature</h2>
<div class="sensor-reading">
<div class="blue">
<span class="value">{inside?.temperature}</span>
<span class="unit">{inside?.temperature_unit}</span>
</div>
<div> <div>
<span class="value">{Math.floor(inside?.humidity)}</span> <span class="value"></span>
<span class="unit">{state.state}</span>
</div>
</div>
<h2>Inside frigde temperature</h2>
<div class="sensor-reading">
<div class="{tempToStateClass(inside?.temperature)}">
<span class="value">{inside?.temperature || 0}</span>
<span class="unit">{inside?.temperature_unit || '°C'}</span>
</div>
<div>
<span class="value">{Math.floor(inside?.humidity || 0)}</span>
<span class="unit">{inside?.humidity_unit || '%'}</span> <span class="unit">{inside?.humidity_unit || '%'}</span>
</div> </div>
</div> </div>
<h2>Outside temperature</h2> <h2>Outside temperature</h2>
<div class="sensor-reading"> <div class="sensor-reading">
<div class="red"> <div class="{tempToStateClass(outside?.temperature)}">
<span class="value">{outside?.temperature}</span> <span class="value">{outside?.temperature || 0}</span>
<span class="unit">{outside?.temperature_unit}</span> <span class="unit">{outside?.temperature_unit || '°C'}</span>
</div> </div>
<div> <div>
<span class="value">{Math.floor(outside?.humidity)}</span> <span class="value">{Math.floor(outside?.humidity || 0)}</span>
<span class="unit">{outside?.humidity_unit}</span> <span class="unit">{outside?.humidity_unit || '%'}</span>
</div> </div>
</div> </div>
@@ -70,14 +85,16 @@
<div class="button-timer"> <div class="button-timer">
<span>Updated {secondsSinceUpdate === 0 ? 'now' : secondsSinceUpdate + 's ago'}</span> <span>Updated {secondsSinceUpdate === 0 ? 'now' : secondsSinceUpdate + 's ago'}</span>
</div> </div>
</div> </div>
<style lang="scss" module="scoped"> <style lang="scss" module="scoped">
@import '../../styles/media-queries.scss'; @import '../../styles/media-queries.scss';
.card {
position: relative;
}
h2 { h2 {
font-size: 1.4rem; font-size: 1.4rem;
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
@@ -92,6 +109,7 @@
.sensor-reading { .sensor-reading {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap;
margin-bottom: 1.75rem; margin-bottom: 1.75rem;
font-size: 2.2rem; font-size: 2.2rem;
@@ -117,13 +135,24 @@
margin-left: 0.3rem; margin-left: 0.3rem;
} }
.red { .info {
font-size: 1rem;
width: 100%;
margin-bottom: 0;
font-weight: 500;
}
.heating {
color: var(--red); color: var(--red);
} }
.blue { .cooling {
color: var(--blue); color: var(--blue);
} }
.idle {
color: var(--green);
}
} }
.button-timer { .button-timer {

View File

@@ -0,0 +1,17 @@
enum Controls {
heating = 'heating',
cooling = 'cooling',
fan = 'fan',
lights = 'lights'
}
interface IRelaysDTO {
controls: Controls;
pin: number;
state: boolean;
}
export {
IRelaysDTO,
Controls
}

View File

@@ -0,0 +1,19 @@
enum Location {
inside = 'inside',
outside = 'outside'
}
interface ISensorDTO {
location: Location;
temperature?: number
temperature_unit?: string
humidity?: number
humidity_unit?: string
pressure?: number
pressure_unit?: string
}
export {
ISensorDTO,
Location
}

View File

@@ -0,0 +1,15 @@
enum State {
idle = 'idle',
cooling = 'cooling',
heating = 'heating'
}
interface IStateDTO {
goal: number;
state: State
}
export {
IStateDTO,
State
}

View File

@@ -1,34 +1,36 @@
import { BREWLOGGER_HOST } from '$env/static/private'; import { BREWLOGGER_HOST } from '$env/static/private';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
import type { ISensorDTO } from '../lib/interfaces/ISensorDTO'
import { IRelaysDTO } from '../lib/interfaces/IRelaysDTO';
import { IStateDTO } from '../lib/interfaces/IStateDTO';
const sensorsUrl = `${BREWLOGGER_HOST}/api/sensors`; const sensorsUrl = `${BREWLOGGER_HOST}/api/sensors`;
const relaysUrl = `${BREWLOGGER_HOST}/api/relays`; const relaysUrl = `${BREWLOGGER_HOST}/api/relays`;
const stateUrl = `${BREWLOGGER_HOST}/api/regulator`;
async function getSensors() { async function getFromEndpoint(endpoint: string) {
return fetch(sensorsUrl) return fetch(endpoint)
.then((resp) => resp.json()) .then((resp) => resp.json())
.then((response) => { .catch((error) => {
return response?.sensors; console.error('Failed to fetch endpoint:', endpoint);
}); console.error(error);
} return null
async function getRelays() {
return fetch(relaysUrl)
.then((resp) => resp.json())
.then((response) => {
return response?.relays || [];
}); });
} }
export const load: PageServerLoad = async () => { export const load: PageServerLoad = async () => {
const [sensors, relays] = await Promise.all([getSensors(), getRelays()]); const [sensorsResp, relaysResp, stateResp] = await Promise.all([getFromEndpoint(sensorsUrl), getFromEndpoint(relaysUrl), getFromEndpoint(stateUrl)]);
const sensors: ISensorDTO[] = sensorsResp?.sensors || []
const relays: IRelaysDTO[] = relaysResp?.relays || []
const state: IStateDTO = stateResp
const inside = sensors.find((sensor) => sensor.location === 'inside'); const inside = sensors.find((sensor: ISensorDTO) => sensor.location === 'inside');
const outside = sensors.find((sensor) => sensor.location === 'outside'); const outside = sensors.find((sensor: ISensorDTO) => sensor.location === 'outside');
return { return {
inside: inside || null, inside: inside || null,
outside: outside || null, outside: outside || null,
relays relays,
state
}; };
}; };

View File

@@ -1,10 +1,10 @@
<script lang="ts"> <script lang="ts">
import Logo from '../lib/components/Logo.svelte'; import Logo from '../lib/components/Logo.svelte';
import VerticalSensorDisplay from '../lib/components/VerticalSensorDisplay.svelte'; import VerticalSensorDisplay from '../lib/components/VerticalSensorDisplay.svelte';
// import Livestream from '$lib/components/Livestream.svelte'
import BrewProgress from '../lib/components/BrewProgress.svelte'; import BrewProgress from '../lib/components/BrewProgress.svelte';
import type { PageData } from './$types';
import RelayControls from '../lib/components/RelayControls.svelte'; import RelayControls from '../lib/components/RelayControls.svelte';
import type { PageData } from './$types';
import type { IStateDTO } from '../lib/interfaces/IStateDTO';
export let data: PageData; export let data: PageData;
const { inside, outside, relays } = data; const { inside, outside, relays } = data;
@@ -15,7 +15,7 @@
<div class="vertical-grid"> <div class="vertical-grid">
<BrewProgress /> <BrewProgress />
<VerticalSensorDisplay inside="{inside}" outside="{outside}" /> <VerticalSensorDisplay {inside} {outside} {relays} {state} />
<RelayControls relays="{relays}" /> <RelayControls relays="{relays}" />