From 7c062dbc04ec620d8e2fd079b340a051b354d8d0 Mon Sep 17 00:00:00 2001 From: Chris Kaczor Date: Sun, 6 Oct 2019 19:59:13 -0400 Subject: [PATCH] Add dashboard pressure trend arrow --- Display/package-lock.json | 5 ++ Display/package.json | 1 + Display/src/app/app.module.ts | 4 +- .../dashboard/dashboard.component.html | 3 + .../dashboard/dashboard.component.ts | 3 +- .../charts/weather-charts.component.ts | 2 +- .../pressure-trend.component.html | 1 + .../pressure-trend.component.scss | 22 +++++++ .../pressure-trend.component.spec.ts | 25 ++++++++ .../pressure-trend.component.ts | 64 +++++++++++++++++++ .../app/models/weather/weather-value-type.ts | 3 + .../src/app/models/weather/weather-value.ts | 4 +- .../app/services/weather/weather.service.ts | 18 +++++- 13 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 Display/src/app/components/weather/pressure-trend/pressure-trend.component.html create mode 100644 Display/src/app/components/weather/pressure-trend/pressure-trend.component.scss create mode 100644 Display/src/app/components/weather/pressure-trend/pressure-trend.component.spec.ts create mode 100644 Display/src/app/components/weather/pressure-trend/pressure-trend.component.ts create mode 100644 Display/src/app/models/weather/weather-value-type.ts diff --git a/Display/package-lock.json b/Display/package-lock.json index 25a981e..9786584 100644 --- a/Display/package-lock.json +++ b/Display/package-lock.json @@ -9507,6 +9507,11 @@ } } }, + "regression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz", + "integrity": "sha1-jSnD6CJKEIUMNeM36FqLL6w7DIc=" + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", diff --git a/Display/package.json b/Display/package.json index 4041164..fe3b2db 100644 --- a/Display/package.json +++ b/Display/package.json @@ -29,6 +29,7 @@ "highcharts": "^7.2.0", "moment": "^2.24.0", "ngx-socket-io": "^3.0.1", + "regression": "^2.0.1", "rxjs": "~6.4.0", "tslib": "^1.10.0", "zone.js": "~0.9.1" diff --git a/Display/src/app/app.module.ts b/Display/src/app/app.module.ts index cf97fdb..9d1af00 100644 --- a/Display/src/app/app.module.ts +++ b/Display/src/app/app.module.ts @@ -20,6 +20,7 @@ import { LaundryComponent } from './components/laundry/laundry.component'; import { DashboardComponent } from './components/dashboard/dashboard.component'; import { WeatherChartsComponent } from './components/weather/charts/weather-charts.component'; import { WeatherCurrentComponent } from './components/weather/current/weather-current.component'; +import { PressureTrendComponent } from './components/weather/pressure-trend/pressure-trend.component'; const config: SocketIoConfig = { url: '/api/laundry', options: {} }; @@ -30,7 +31,8 @@ const config: SocketIoConfig = { url: '/api/laundry', options: {} }; LaundryComponent, DashboardComponent, WeatherChartsComponent, - WeatherCurrentComponent + WeatherCurrentComponent, + PressureTrendComponent ], imports: [ BrowserModule, diff --git a/Display/src/app/components/dashboard/dashboard.component.html b/Display/src/app/components/dashboard/dashboard.component.html index 2d4911e..792fac1 100644 --- a/Display/src/app/components/dashboard/dashboard.component.html +++ b/Display/src/app/components/dashboard/dashboard.component.html @@ -16,5 +16,8 @@ + + + diff --git a/Display/src/app/components/dashboard/dashboard.component.ts b/Display/src/app/components/dashboard/dashboard.component.ts index 3c86865..f17c11d 100644 --- a/Display/src/app/components/dashboard/dashboard.component.ts +++ b/Display/src/app/components/dashboard/dashboard.component.ts @@ -62,7 +62,8 @@ export class DashboardComponent implements OnInit { const defaultLayout = [ { cols: 3, rows: 2, y: 0, x: 0 }, - { cols: 2, rows: 1, y: 0, x: 3 } + { cols: 2, rows: 1, y: 0, x: 3 }, + { cols: 1, rows: 1, y: 0, x: 5 } ]; if (savedLayout == null) { diff --git a/Display/src/app/components/weather/charts/weather-charts.component.ts b/Display/src/app/components/weather/charts/weather-charts.component.ts index 6352177..6cb667e 100644 --- a/Display/src/app/components/weather/charts/weather-charts.component.ts +++ b/Display/src/app/components/weather/charts/weather-charts.component.ts @@ -135,7 +135,7 @@ export class WeatherChartsComponent implements OnInit { this.chart = new Chart({ chart: { type: 'line', - zoomType: "x" + zoomType: 'x' }, title: { text: title diff --git a/Display/src/app/components/weather/pressure-trend/pressure-trend.component.html b/Display/src/app/components/weather/pressure-trend/pressure-trend.component.html new file mode 100644 index 0000000..500a69d --- /dev/null +++ b/Display/src/app/components/weather/pressure-trend/pressure-trend.component.html @@ -0,0 +1 @@ +arrow_right_alt diff --git a/Display/src/app/components/weather/pressure-trend/pressure-trend.component.scss b/Display/src/app/components/weather/pressure-trend/pressure-trend.component.scss new file mode 100644 index 0000000..2866c31 --- /dev/null +++ b/Display/src/app/components/weather/pressure-trend/pressure-trend.component.scss @@ -0,0 +1,22 @@ +#pressure-arrow { + position: relative; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(3); +} + +.down-high { + transform: translate(-50%, -50%) scale(3) rotate(60deg) !important; +} + +.down-low { + transform: translate(-50%, -50%) scale(3) rotate(25deg) !important; +} + +.up-high { + transform: translate(-50%, -50%) scale(3) rotate(-60deg) !important; +} + +.up-low { + transform: translate(-50%, -50%) scale(3) rotate(-25deg) !important; +} diff --git a/Display/src/app/components/weather/pressure-trend/pressure-trend.component.spec.ts b/Display/src/app/components/weather/pressure-trend/pressure-trend.component.spec.ts new file mode 100644 index 0000000..502e742 --- /dev/null +++ b/Display/src/app/components/weather/pressure-trend/pressure-trend.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PressureTrendComponent } from './pressure-trend.component'; + +describe('PressureTrendComponent', () => { + let component: PressureTrendComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PressureTrendComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PressureTrendComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Display/src/app/components/weather/pressure-trend/pressure-trend.component.ts b/Display/src/app/components/weather/pressure-trend/pressure-trend.component.ts new file mode 100644 index 0000000..e5a4f61 --- /dev/null +++ b/Display/src/app/components/weather/pressure-trend/pressure-trend.component.ts @@ -0,0 +1,64 @@ +import { Component, OnInit } from '@angular/core'; +import { WeatherService } from 'src/app/services/weather/weather.service'; +import { WeatherValueType } from 'src/app/models/weather/weather-value-type'; +import { WeatherValue } from 'src/app/models/weather/weather-value'; + +import * as moment from 'moment'; +import * as regression from 'regression'; + +@Component({ + selector: 'app-pressure-trend', + templateUrl: './pressure-trend.component.html', + styleUrls: ['./pressure-trend.component.scss'] +}) +export class PressureTrendComponent implements OnInit { + public pressureDifference: number = null; + + constructor(private weatherService: WeatherService) { } + + ngOnInit() { + this.update(); + + setInterval(this.update, 60000); + } + + async update() { + const end: moment.Moment = moment(); + const start: moment.Moment = moment(end).subtract(3, 'hours'); + + const weatherData = await this.weatherService.getReadingValueHistory(WeatherValueType.Pressure, start, end); + + if (!weatherData) { + return; + } + + const points: Array> = []; + + weatherData.forEach((weatherValue: WeatherValue) => { + const point = [moment(weatherValue.timestamp).unix(), weatherValue.value / 100]; + points.push(point); + }); + + const result = regression.linear(points, { precision: 10 }); + + const regressionPoints = result.points; + + this.pressureDifference = regressionPoints[regressionPoints.length - 1][1] - regressionPoints[0][1]; + } + + rotationClass(): string { + if (!this.pressureDifference) { + return ''; + } else if (Math.abs(this.pressureDifference) <= 1.0) { + return ''; + } else if (this.pressureDifference > 1.0 && this.pressureDifference <= 2.0) { + return 'up-low'; + } else if (this.pressureDifference > 2.0) { + return 'up-high'; + } else if (this.pressureDifference < -1.0 && this.pressureDifference >= -2.0) { + return 'down-low'; + } else if (this.pressureDifference < -2.0) { + return 'down-high'; + } + } +} diff --git a/Display/src/app/models/weather/weather-value-type.ts b/Display/src/app/models/weather/weather-value-type.ts new file mode 100644 index 0000000..ab7baf3 --- /dev/null +++ b/Display/src/app/models/weather/weather-value-type.ts @@ -0,0 +1,3 @@ +export enum WeatherValueType { + Pressure = 'Pressure' +} diff --git a/Display/src/app/models/weather/weather-value.ts b/Display/src/app/models/weather/weather-value.ts index 7c2094d..b71ea18 100644 --- a/Display/src/app/models/weather/weather-value.ts +++ b/Display/src/app/models/weather/weather-value.ts @@ -1,4 +1,4 @@ export class WeatherValue { - bucket: string; - averageValue: number; + timestamp: string; + value: number; } diff --git a/Display/src/app/services/weather/weather.service.ts b/Display/src/app/services/weather/weather.service.ts index 942796a..c7229c9 100644 --- a/Display/src/app/services/weather/weather.service.ts +++ b/Display/src/app/services/weather/weather.service.ts @@ -1,7 +1,12 @@ import { Injectable } from '@angular/core'; import { Observable, BehaviorSubject } from 'rxjs'; import { HubConnectionBuilder, HubConnection } from '@aspnet/signalr'; -import { WeatherReading } from '../../models/weather/weather-reading'; +import { WeatherReading } from 'src/app/models/weather/weather-reading'; +import { WeatherValue } from 'src/app/models/weather/weather-value'; +import { HttpClient } from '@angular/common/http'; + +import * as moment from 'moment'; +import { WeatherValueType } from 'src/app/models/weather/weather-value-type'; @Injectable({ providedIn: 'root' @@ -10,7 +15,7 @@ export class WeatherService { private connection: HubConnection; private latestReading: BehaviorSubject = new BehaviorSubject(null); - constructor() { + constructor(private httpClient: HttpClient) { this.connection = new HubConnectionBuilder() .withUrl('/api/hub/weather') .build(); @@ -25,4 +30,13 @@ export class WeatherService { getLatestReading(): Observable { return this.latestReading.asObservable(); } + + async getReadingValueHistory(valueType: WeatherValueType, start: moment.Moment, end: moment.Moment): Promise { + const startString = start.toISOString(); + const endString = end.toISOString(); + + const data = await this.httpClient.get(`/api/weather/readings/value-history?weatherValueType=${valueType}&start=${startString}&end=${endString}`).toPromise(); + + return data; + } }