More UI work and start preparing for deployment

This commit is contained in:
2024-03-12 01:25:41 +00:00
parent 21f5522950
commit 3087059e75
15 changed files with 442 additions and 123 deletions

14
WebDisplay/Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
# build stage
FROM node:lts-alpine as build-stage
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY package*.json ./
RUN pnpm install
COPY . .
RUN pnpm run build
# production stage
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -12,7 +12,6 @@ declare module 'vue' {
CurrentPower: typeof import('./src/components/CurrentPower.vue')['default'] CurrentPower: typeof import('./src/components/CurrentPower.vue')['default']
CurrentWeather: typeof import('./src/components/CurrentWeather.vue')['default'] CurrentWeather: typeof import('./src/components/CurrentWeather.vue')['default']
DashboardItem: typeof import('./src/components/DashboardItem.vue')['default'] DashboardItem: typeof import('./src/components/DashboardItem.vue')['default']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
Indoor: typeof import('./src/components/Indoor.vue')['default'] Indoor: typeof import('./src/components/Indoor.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']

View File

@@ -0,0 +1,68 @@
name: $(Rev:r)
pr: none
trigger:
batch: 'true'
branches:
include:
- master
paths:
include:
- WebDisplay
stages:
- stage: Build
jobs:
- job: Build
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@0
displayName: 'Build an image'
inputs:
containerregistrytype: 'Container Registry'
dockerRegistryConnection: 'Docker Hub'
dockerFile: 'WebDisplay/Dockerfile'
imageName: 'ckaczor/home-monitor-web-display:$(Build.BuildNumber)'
includeLatestTag: true
- task: Docker@0
displayName: 'Push an image'
inputs:
containerregistrytype: 'Container Registry'
dockerRegistryConnection: 'Docker Hub'
action: 'Push an image'
imageName: 'ckaczor/home-monitor-web-display:$(Build.BuildNumber)'
includeLatestTag: true
- task: Bash@3
inputs:
targetType: 'inline'
script: 'sed -i s/#BUILD_BUILDNUMBER#/$BUILD_BUILDNUMBER/ WebDisplay/deploy/manifest.yaml'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: 'WebDisplay/deploy/manifest.yaml'
ArtifactName: 'Manifest'
publishLocation: 'Container'
- stage: Deploy
jobs:
- job: Deploy
pool:
vmImage: 'ubuntu-latest'
steps:
- task: DownloadBuildArtifacts@0
inputs:
artifactName: 'Manifest'
buildType: 'current'
downloadType: 'single'
downloadPath: '$(System.ArtifactsDirectory)'
- task: Kubernetes@1
inputs:
connectionType: 'Kubernetes Service Connection'
kubernetesServiceEndpoint: 'Kubernetes'
namespace: 'home-monitor'
command: 'apply'
useConfigurationFile: true
configuration: '$(System.ArtifactsDirectory)/Manifest/manifest.yaml'
secretType: 'dockerRegistry'
containerRegistryType: 'Container Registry'

View File

@@ -0,0 +1,76 @@
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: display
namespace: home-monitor
labels:
app: display
spec:
replicas: 1
selector:
matchLabels:
app: display
template:
metadata:
labels:
app: display
spec:
containers:
- name: display
image: ckaczor/home-monitor-web-display:#BUILD_BUILDNUMBER#
terminationMessagePath: "/dev/termination-log"
terminationMessagePolicy: File
imagePullPolicy: Always
securityContext:
privileged: true
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/hostname: kubernetes
schedulerName: default-scheduler
---
kind: Service
apiVersion: v1
metadata:
name: display
spec:
ports:
- name: client
port: 80
selector:
app: display
type: ClusterIP
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
annotations:
kubernetes.io/ingress.class: traefik
creationTimestamp: null
name: display
namespace: home-monitor
spec:
routes:
- kind: Rule
match: PathPrefix(`/`)
middlewares:
- name: display
namespace: home-monitor
services:
- kind: Service
name: display
namespace: home-monitor
port: 80
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
creationTimestamp: null
name: display
namespace: home-monitor
spec:
stripPrefix:
prefixes:
- /

View File

@@ -1,6 +1,6 @@
{ {
"name": "WebDisplay", "name": "web-display",
"version": "0.0.0", "version": "1.0.0",
"scripts": { "scripts": {
"dev": "cross-env NODE_OPTIONS='--no-warnings' vite", "dev": "cross-env NODE_OPTIONS='--no-warnings' vite",
"build": "vue-tsc --noEmit && vite build", "build": "vue-tsc --noEmit && vite build",

View File

@@ -45,7 +45,7 @@
<td> <td>
<div <div
v-if="weatherStore.current?.HeatIndex || weatherStore.current?.WindChill" v-if="weatherStore.current?.HeatIndex || weatherStore.current?.WindChill"
className="weather-current-header"> className="weather-current-header ml-8">
Feels like Feels like
</div> </div>
</td> </td>

View File

@@ -14,15 +14,9 @@
<style scoped> <style scoped>
.dashboard-item-header { .dashboard-item-header {
padding: 2px 10px; padding: 2px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
} }
.dashboard-item-content { .dashboard-item-content {
background-color: white; background-color: white;
border: 1px solid lightgray;
border-top: 0px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
} }
</style> </style>

View File

@@ -16,7 +16,9 @@
yAxisMaximum: { type: Number, required: false, default: undefined }, yAxisMaximum: { type: Number, required: false, default: undefined },
tickAmount: { type: Number, required: false, default: undefined }, tickAmount: { type: Number, required: false, default: undefined },
lineSize: { type: Number, required: false, default: 2 }, lineSize: { type: Number, required: false, default: 2 },
markerSize: { type: Number, required: false, default: 0 } markerSize: { type: Number, required: false, default: 0 },
yAxisLabelFormatter: { type: Function, required: false, default: undefined },
yAxisValueFormatter: { type: Function, required: false, default: undefined }
}); });
var chartOptions: ApexOptions = { var chartOptions: ApexOptions = {
@@ -48,6 +50,10 @@
}, },
y: { y: {
formatter: (value) => { formatter: (value) => {
if (props.yAxisValueFormatter) {
return props.yAxisValueFormatter(value);
}
return `${value.toFixed(props.valueDecimalPoints)}${props.unit}`; return `${value.toFixed(props.valueDecimalPoints)}${props.unit}`;
} }
} }
@@ -69,6 +75,10 @@
yaxis: { yaxis: {
labels: { labels: {
formatter: (value) => { formatter: (value) => {
if (props.yAxisLabelFormatter) {
return props.yAxisLabelFormatter(value);
}
return `${value.toFixed(props.yAxisDecimalPoints)}${props.unit}`; return `${value.toFixed(props.yAxisDecimalPoints)}${props.unit}`;
} }
}, },
@@ -94,7 +104,7 @@
<template> <template>
<div class="chart"> <div class="chart">
<v-container <v-container
v-if="!props.ready" v-show="!props.ready"
class="fill-height loading"> class="fill-height loading">
<v-responsive class="align-center text-center fill-height"> <v-responsive class="align-center text-center fill-height">
<v-progress-circular <v-progress-circular
@@ -105,7 +115,6 @@
</v-responsive> </v-responsive>
</v-container> </v-container>
<apexchart <apexchart
v-else
width="100%" width="100%"
height="250" height="250"
:type="props.type" :type="props.type"
@@ -118,9 +127,17 @@
.loading { .loading {
width: 100%; width: 100%;
min-height: 250px; min-height: 250px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 99;
background-color: #eeeeee;
} }
.chart { .chart {
position: relative;
border: 1px solid lightgray; border: 1px solid lightgray;
background-color: white; background-color: white;
padding-top: 10px; padding-top: 10px;

View File

@@ -1,7 +1,9 @@
import WindDirectionNumber from './wind-direction-number';
export default interface WindHistoryGrouped { export default interface WindHistoryGrouped {
bucket: string; bucket: string;
minimumSpeed: number; minimumSpeed: number;
averageSpeed: number; averageSpeed: number;
maximumSpeed: number; maximumSpeed: number;
averageDirection: number; averageDirection: WindDirectionNumber;
} }

View File

@@ -4,30 +4,34 @@
</script> </script>
<template> <template>
<v-container fluid class="container"> <v-container
<v-row dense align="start"> fluid
<v-col cols="3"> class="container">
<v-card class="current-weather">
<CurrentWeather></CurrentWeather> <CurrentWeather></CurrentWeather>
</v-col> </v-card>
<v-col cols="3"> <v-card class="almanac">
<Almanac></Almanac> <Almanac></Almanac>
</v-col> </v-card>
<v-col cols="2"> <v-card class="current-power">
<CurrentPower></CurrentPower> <CurrentPower></CurrentPower>
</v-col> </v-card>
<v-col cols="2"> <v-card class="current-laundry-status">
<CurrentLaundryStatus></CurrentLaundryStatus> <CurrentLaundryStatus></CurrentLaundryStatus>
</v-col> </v-card>
<v-col cols="4"> <v-card class="weather-summary">
<WeatherSummary></WeatherSummary> <WeatherSummary></WeatherSummary>
</v-col> </v-card>
<v-col cols="2"> <v-card class="upstairs">
<Indoor title="Upstairs" deviceName="main"></Indoor> <Indoor
</v-col> title="Upstairs"
<v-col cols="2"> deviceName="main"></Indoor>
<Indoor title="Downstairs" deviceName="basement"></Indoor> </v-card>
</v-col> <v-card class="downstairs">
</v-row> <Indoor
title="Downstairs"
deviceName="basement"></Indoor>
</v-card>
</v-container> </v-container>
</template> </template>
@@ -36,4 +40,66 @@
height: 100%; height: 100%;
background-color: #fafafa; background-color: #fafafa;
} }
@media (min-width: 700px) {
.container {
display: grid;
grid-template-columns: repeat(5, max-content);
grid-template-rows: repeat(5, max-content);
gap: 15px 15px;
grid-auto-flow: row;
grid-template-areas:
'current-weather current-weather almanac almanac current-power'
'current-weather current-weather almanac almanac current-laundry-status'
'weather-summary weather-summary weather-summary upstairs downstairs'
'weather-summary weather-summary weather-summary . .'
'. . . . .';
}
}
@media (max-width: 700px) {
.container {
padding: 7px;
display: grid;
grid-template-columns: repeat(1, max-content);
grid-template-rows: repeat(7, max-content);
gap: 10px 0px;
grid-template-areas:
'current-weather'
'almanac'
'current-power'
'current-laundry-status'
'weather-summary'
'upstairs'
'downstairs';
}
}
.current-weather {
grid-area: current-weather;
}
.almanac {
grid-area: almanac;
}
.current-power {
grid-area: current-power;
}
.current-laundry-status {
grid-area: current-laundry-status;
}
.weather-summary {
grid-area: weather-summary;
}
.upstairs {
grid-area: upstairs;
}
.downstairs {
grid-area: downstairs;
}
</style> </style>

View File

@@ -16,43 +16,43 @@
const start = ref(subHours(end.value, 24)); const start = ref(subHours(end.value, 24));
const timeSpan = ref(TimeSpan.Last24Hours); const timeSpan = ref(TimeSpan.Last24Hours);
const categories: number[] = []; const categories = ref<number[]>([]);
const mainTemperatureSeries = { name: 'Upstairs', data: [] as number[] }; const mainTemperatureSeries = ref({ name: 'Upstairs', data: [] as number[] });
const basementTemperatureSeries = { name: 'Downstairs', data: [] as number[] }; const basementTemperatureSeries = ref({ name: 'Downstairs', data: [] as number[] });
const mainHumiditySeries = { name: 'Upstairs', data: [] as number[] }; const mainHumiditySeries = ref({ name: 'Upstairs', data: [] as number[] });
const basementHumiditySeries = { name: 'Downstairs', data: [] as number[] }; const basementHumiditySeries = ref({ name: 'Downstairs', data: [] as number[] });
const mainPressureSeries = { name: 'Upstairs', data: [] as number[] }; const mainPressureSeries = ref({ name: 'Upstairs', data: [] as number[] });
const basementPressureSeries = { name: 'Downstairs', data: [] as number[] }; const basementPressureSeries = ref({ name: 'Downstairs', data: [] as number[] });
const load = () => { const load = () => {
ready.value = false; ready.value = false;
categories.length = 0;
mainTemperatureSeries.data.length = 0;
basementTemperatureSeries.data.length = 0;
mainHumiditySeries.data.length = 0;
basementHumiditySeries.data.length = 0;
mainPressureSeries.data.length = 0;
basementPressureSeries.data.length = 0;
indoorStore.getReadingValueHistoryGrouped(start.value, end.value, 15).then((groupedReadingsList) => { indoorStore.getReadingValueHistoryGrouped(start.value, end.value, 15).then((groupedReadingsList) => {
categories.value.length = 0;
mainTemperatureSeries.value.data.length = 0;
basementTemperatureSeries.value.data.length = 0;
mainHumiditySeries.value.data.length = 0;
basementHumiditySeries.value.data.length = 0;
mainPressureSeries.value.data.length = 0;
basementPressureSeries.value.data.length = 0;
groupedReadingsList.forEach((groupedReadings) => { groupedReadingsList.forEach((groupedReadings) => {
if (groupedReadings.name === 'main') { if (groupedReadings.name === 'main') {
categories.push(new Date(groupedReadings.bucket).getTime()); categories.value.push(new Date(groupedReadings.bucket).getTime());
mainTemperatureSeries.data.push(ConvertCToF(groupedReadings.averageTemperature)); mainTemperatureSeries.value.data.push(ConvertCToF(groupedReadings.averageTemperature));
mainHumiditySeries.data.push(groupedReadings.averageHumidity); mainHumiditySeries.value.data.push(groupedReadings.averageHumidity);
mainPressureSeries.data.push(ConvertMillibarToInchesOfMercury(groupedReadings.averagePressure)); mainPressureSeries.value.data.push(ConvertMillibarToInchesOfMercury(groupedReadings.averagePressure));
} else if (groupedReadings.name === 'basement') { } else if (groupedReadings.name === 'basement') {
basementTemperatureSeries.data.push(ConvertCToF(groupedReadings.averageTemperature)); basementTemperatureSeries.value.data.push(ConvertCToF(groupedReadings.averageTemperature));
basementHumiditySeries.data.push(groupedReadings.averageHumidity); basementHumiditySeries.value.data.push(groupedReadings.averageHumidity);
basementPressureSeries.data.push(ConvertMillibarToInchesOfMercury(groupedReadings.averagePressure)); basementPressureSeries.value.data.push(ConvertMillibarToInchesOfMercury(groupedReadings.averagePressure));
} }
}); });

View File

@@ -4,28 +4,28 @@
import { useWeatherStore } from '@/stores/weatherStore'; import { useWeatherStore } from '@/stores/weatherStore';
import { ConvertPascalToInchesOfMercury } from '@/pressureConverter'; import { ConvertPascalToInchesOfMercury } from '@/pressureConverter';
import ValueChart from '../components/ValueChart.vue'; import ValueChart from '../components/ValueChart.vue';
import WindDirectionNumber from '@/models/weather/wind-direction-number';
import TimeRange from '@/components/TimeRange.vue'; import TimeRange from '@/components/TimeRange.vue';
import TimeSpan from '@/models/time-span'; import TimeSpan from '@/models/time-span';
import { ConvertDegreesToShortLabel, ConvertWindDirectionToDegrees } from '@/windConverter';
const weatherStore = useWeatherStore(); const weatherStore = useWeatherStore();
const readingsReady = ref(false); const readingsReady = ref(false);
const windReady = ref(false); const windReady = ref(false);
const readingsCategories: number[] = []; const readingsCategories = ref<number[]>([]);
const windCategories: number[] = []; const windCategories = ref<number[]>([]);
const temperatureSeries = { name: 'Average Temperature', data: [] as number[] }; const temperatureSeries = ref({ name: 'Average Temperature', data: [] as number[] });
const humiditySeries = { name: 'Average Humidity', data: [] as number[] }; const humiditySeries = ref({ name: 'Average Humidity', data: [] as number[] });
const pressureSeries = { name: 'Average Pressure', data: [] as number[] }; const pressureSeries = ref({ name: 'Average Pressure', data: [] as number[] });
const lightSeries = { name: 'Average Light', data: [] as number[] }; const lightSeries = ref({ name: 'Average Light', data: [] as number[] });
const rainSeries = { name: 'Total Rain', data: [] as number[] }; const rainSeries = ref({ name: 'Total Rain', data: [] as number[] });
const windMinimumSeries = { name: 'Minimum', data: [] as number[] }; const windMinimumSeries = ref({ name: 'Minimum', data: [] as number[] });
const windAverageSeries = { name: 'Average', data: [] as number[] }; const windAverageSeries = ref({ name: 'Average', data: [] as number[] });
const windMaximumSeries = { name: 'Maximum', data: [] as number[] }; const windMaximumSeries = ref({ name: 'Maximum', data: [] as number[] });
const windDirectionSeries = { name: 'Average Direction', data: [] as number[] }; const windDirectionSeries = ref({ name: 'Average Direction', data: [] as number[] });
const end = ref(new Date()); const end = ref(new Date());
const start = ref(subHours(end.value, 24)); const start = ref(subHours(end.value, 24));
@@ -33,43 +33,44 @@
const load = () => { const load = () => {
readingsReady.value = false; readingsReady.value = false;
readingsCategories.length = 0;
temperatureSeries.data.length = 0;
humiditySeries.data.length = 0;
pressureSeries.data.length = 0;
lightSeries.data.length = 0;
rainSeries.data.length = 0;
windReady.value = false; windReady.value = false;
windCategories.length = 0;
windMinimumSeries.data.length = 0;
windAverageSeries.data.length = 0;
windMaximumSeries.data.length = 0;
windDirectionSeries.data.length = 0;
weatherStore.getReadingHistoryGrouped(start.value, end.value, 15).then((groupedReadingsList) => { weatherStore.getReadingHistoryGrouped(start.value, end.value, 15).then((groupedReadingsList) => {
groupedReadingsList.forEach((groupedReadings) => { readingsCategories.value.length = 0;
readingsCategories.push(new Date(groupedReadings.bucket).getTime()); temperatureSeries.value.data.length = 0;
humiditySeries.value.data.length = 0;
pressureSeries.value.data.length = 0;
lightSeries.value.data.length = 0;
rainSeries.value.data.length = 0;
temperatureSeries.data.push(groupedReadings.averageTemperature); groupedReadingsList.forEach((groupedReadings) => {
humiditySeries.data.push(groupedReadings.averageHumidity); readingsCategories.value.push(new Date(groupedReadings.bucket).getTime());
pressureSeries.data.push(ConvertPascalToInchesOfMercury(groupedReadings.averagePressure));
lightSeries.data.push(groupedReadings.averageLightLevel); temperatureSeries.value.data.push(groupedReadings.averageTemperature);
rainSeries.data.push(groupedReadings.rainTotal); humiditySeries.value.data.push(groupedReadings.averageHumidity);
pressureSeries.value.data.push(ConvertPascalToInchesOfMercury(groupedReadings.averagePressure));
lightSeries.value.data.push(groupedReadings.averageLightLevel);
rainSeries.value.data.push(groupedReadings.rainTotal);
}); });
readingsReady.value = true; readingsReady.value = true;
}); });
weatherStore.getWindHistoryGrouped(start.value, end.value, 15).then((groupedReadingsList) => { weatherStore.getWindHistoryGrouped(start.value, end.value, 15).then((groupedReadingsList) => {
windCategories.value.length = 0;
windMinimumSeries.value.data.length = 0;
windAverageSeries.value.data.length = 0;
windMaximumSeries.value.data.length = 0;
windDirectionSeries.value.data.length = 0;
groupedReadingsList.forEach((groupedReadings) => { groupedReadingsList.forEach((groupedReadings) => {
windCategories.push(new Date(groupedReadings.bucket).getTime()); windCategories.value.push(new Date(groupedReadings.bucket).getTime());
windMinimumSeries.data.push(groupedReadings.minimumSpeed); windMinimumSeries.value.data.push(groupedReadings.minimumSpeed);
windAverageSeries.data.push(groupedReadings.averageSpeed); windAverageSeries.value.data.push(groupedReadings.averageSpeed);
windMaximumSeries.data.push(groupedReadings.maximumSpeed); windMaximumSeries.value.data.push(groupedReadings.maximumSpeed);
windDirectionSeries.data.push(groupedReadings.averageDirection); windDirectionSeries.value.data.push(ConvertWindDirectionToDegrees(groupedReadings.averageDirection));
}); });
windReady.value = true; windReady.value = true;
@@ -200,11 +201,11 @@
title="Wind Direction" title="Wind Direction"
unit="" unit=""
group="outdoor" group="outdoor"
:tick-amount="3" :tick-amount="4"
:marker-size="3" :y-axis-minimum="0"
:line-size="0" :y-axis-maximum="360"
:y-axis-minimum="WindDirectionNumber.Min" :y-axis-label-formatter="ConvertDegreesToShortLabel"
:y-axis-maximum="WindDirectionNumber.Max" :y-axis-value-formatter="ConvertDegreesToShortLabel"
:categories="windCategories" :categories="windCategories"
:series="[windDirectionSeries]"> :series="[windDirectionSeries]">
</ValueChart> </ValueChart>

View File

@@ -14,13 +14,13 @@
const powerReady = ref(false); const powerReady = ref(false);
const lightReady = ref(false); const lightReady = ref(false);
const powerCategories: number[] = []; const powerCategories = ref<number[]>([]);
const lightCategories: number[] = []; const lightCategories = ref<number[]>([]);
const generationSeries = { name: 'Generation', data: [] as number[] }; const generationSeries = ref({ name: 'Generation', data: [] as number[] });
const consumptionSeries = { name: 'Consumption', data: [] as number[] }; const consumptionSeries = ref({ name: 'Consumption', data: [] as number[] });
const lightSeries = { name: 'Average Light', data: [] as number[] }; const lightSeries = ref({ name: 'Average Light', data: [] as number[] });
const end = ref(new Date()); const end = ref(new Date());
const start = ref(subHours(end.value, 24)); const start = ref(subHours(end.value, 24));
@@ -28,30 +28,31 @@
const load = () => { const load = () => {
powerReady.value = false; powerReady.value = false;
powerCategories.length = 0;
generationSeries.data.length = 0;
consumptionSeries.data.length = 0;
lightReady.value = false; lightReady.value = false;
lightCategories.length = 0;
lightSeries.data.length = 0;
powerStore.getReadingHistoryGrouped(start.value, end.value, 15).then((groupedReadingsList) => { powerStore.getReadingHistoryGrouped(start.value, end.value, 15).then((groupedReadingsList) => {
groupedReadingsList.forEach((groupedReadings) => { powerCategories.value.length = 0;
powerCategories.push(new Date(groupedReadings.bucket).getTime()); generationSeries.value.data.length = 0;
consumptionSeries.value.data.length = 0;
generationSeries.data.push(groupedReadings.averageGeneration); groupedReadingsList.forEach((groupedReadings) => {
consumptionSeries.data.push(groupedReadings.averageConsumption); powerCategories.value.push(new Date(groupedReadings.bucket).getTime());
generationSeries.value.data.push(groupedReadings.averageGeneration);
consumptionSeries.value.data.push(groupedReadings.averageConsumption);
}); });
powerReady.value = true; powerReady.value = true;
}); });
weatherStore.getReadingValueHistoryGrouped(WeatherValueType.Light, start.value, end.value, 15).then((groupedReadingsList) => { weatherStore.getReadingValueHistoryGrouped(WeatherValueType.Light, start.value, end.value, 15).then((groupedReadingsList) => {
groupedReadingsList.forEach((groupedReadings) => { lightCategories.value.length = 0;
lightCategories.push(new Date(groupedReadings.bucket).getTime()); lightSeries.value.data.length = 0;
lightSeries.data.push(groupedReadings.averageValue); groupedReadingsList.forEach((groupedReadings) => {
lightCategories.value.push(new Date(groupedReadings.bucket).getTime());
lightSeries.value.data.push(groupedReadings.averageValue);
}); });
lightReady.value = true; lightReady.value = true;

View File

@@ -0,0 +1,81 @@
import WindDirectionNumber from './models/weather/wind-direction-number';
export function ConvertWindDirectionToDegrees(windDirection: WindDirectionNumber): number {
switch (windDirection) {
case WindDirectionNumber.None:
return -1;
case WindDirectionNumber.North:
return 0;
case WindDirectionNumber.East:
return 90;
case WindDirectionNumber.South:
return 180;
case WindDirectionNumber.West:
return 270;
case WindDirectionNumber.NorthEast:
return 45;
case WindDirectionNumber.SouthEast:
return 135;
case WindDirectionNumber.SouthWest:
return 225;
case WindDirectionNumber.NorthWest:
return 315;
case WindDirectionNumber.NorthNorthEast:
return 22.5;
case WindDirectionNumber.EastNorthEast:
return 67.5;
case WindDirectionNumber.EastSouthEast:
return 112.5;
case WindDirectionNumber.SouthSouthEast:
return 157.5;
case WindDirectionNumber.SouthSouthWest:
return 202.5;
case WindDirectionNumber.WestSouthWest:
return 247.5;
case WindDirectionNumber.WestNorthWest:
return 292.5;
case WindDirectionNumber.NorthNorthWest:
return 337.5;
}
return -1;
}
export function ConvertDegreesToShortLabel(degrees: number): string {
switch (degrees) {
case 0:
case 360:
return 'N';
case 90:
return 'E';
case 180:
return 'S';
case 270:
return 'W';
case 45:
return 'NE';
case 135:
return 'SE';
case 225:
return 'SW';
case 315:
return 'NW';
case 22.5:
return 'NNE';
case 67.5:
return 'ENE';
case 112.5:
return 'ESE';
case 157.5:
return 'SSE';
case 202.5:
return 'SSW';
case 247.5:
return 'WSW';
case 292.5:
return 'WNW';
case 337.5:
return 'NNW';
}
return '';
}

View File

@@ -17,7 +17,7 @@
"@/*": ["src/*"] "@/*": ["src/*"]
} }
}, },
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "typed-router.d.ts"],
"references": [{ "path": "./tsconfig.node.json" }], "references": [{ "path": "./tsconfig.node.json" }],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }