mirror of
https://github.com/ckaczor/HomeMonitor.git
synced 2026-02-16 10:58:32 -05:00
Add dashboard pressure trend arrow
This commit is contained in:
5
Display/package-lock.json
generated
5
Display/package-lock.json
generated
@@ -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": {
|
"remove-trailing-separator": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"highcharts": "^7.2.0",
|
"highcharts": "^7.2.0",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"ngx-socket-io": "^3.0.1",
|
"ngx-socket-io": "^3.0.1",
|
||||||
|
"regression": "^2.0.1",
|
||||||
"rxjs": "~6.4.0",
|
"rxjs": "~6.4.0",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^1.10.0",
|
||||||
"zone.js": "~0.9.1"
|
"zone.js": "~0.9.1"
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { LaundryComponent } from './components/laundry/laundry.component';
|
|||||||
import { DashboardComponent } from './components/dashboard/dashboard.component';
|
import { DashboardComponent } from './components/dashboard/dashboard.component';
|
||||||
import { WeatherChartsComponent } from './components/weather/charts/weather-charts.component';
|
import { WeatherChartsComponent } from './components/weather/charts/weather-charts.component';
|
||||||
import { WeatherCurrentComponent } from './components/weather/current/weather-current.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: {} };
|
const config: SocketIoConfig = { url: '/api/laundry', options: {} };
|
||||||
|
|
||||||
@@ -30,7 +31,8 @@ const config: SocketIoConfig = { url: '/api/laundry', options: {} };
|
|||||||
LaundryComponent,
|
LaundryComponent,
|
||||||
DashboardComponent,
|
DashboardComponent,
|
||||||
WeatherChartsComponent,
|
WeatherChartsComponent,
|
||||||
WeatherCurrentComponent
|
WeatherCurrentComponent,
|
||||||
|
PressureTrendComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
|||||||
@@ -16,5 +16,8 @@
|
|||||||
<gridster-item [item]="dashboard[1]">
|
<gridster-item [item]="dashboard[1]">
|
||||||
<app-laundry></app-laundry>
|
<app-laundry></app-laundry>
|
||||||
</gridster-item>
|
</gridster-item>
|
||||||
|
<gridster-item [item]="dashboard[2]">
|
||||||
|
<app-pressure-trend></app-pressure-trend>
|
||||||
|
</gridster-item>
|
||||||
</gridster>
|
</gridster>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ export class DashboardComponent implements OnInit {
|
|||||||
|
|
||||||
const defaultLayout = [
|
const defaultLayout = [
|
||||||
{ cols: 3, rows: 2, y: 0, x: 0 },
|
{ 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) {
|
if (savedLayout == null) {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ export class WeatherChartsComponent implements OnInit {
|
|||||||
this.chart = new Chart({
|
this.chart = new Chart({
|
||||||
chart: {
|
chart: {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
zoomType: "x"
|
zoomType: 'x'
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
text: title
|
text: title
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<mat-icon id="pressure-arrow" *ngIf="pressureDifference !== null" [ngClass]="rotationClass()">arrow_right_alt</mat-icon>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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<PressureTrendComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [PressureTrendComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PressureTrendComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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<Array<number>> = [];
|
||||||
|
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Display/src/app/models/weather/weather-value-type.ts
Normal file
3
Display/src/app/models/weather/weather-value-type.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export enum WeatherValueType {
|
||||||
|
Pressure = 'Pressure'
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export class WeatherValue {
|
export class WeatherValue {
|
||||||
bucket: string;
|
timestamp: string;
|
||||||
averageValue: number;
|
value: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, BehaviorSubject } from 'rxjs';
|
import { Observable, BehaviorSubject } from 'rxjs';
|
||||||
import { HubConnectionBuilder, HubConnection } from '@aspnet/signalr';
|
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({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -10,7 +15,7 @@ export class WeatherService {
|
|||||||
private connection: HubConnection;
|
private connection: HubConnection;
|
||||||
private latestReading: BehaviorSubject<WeatherReading> = new BehaviorSubject<WeatherReading>(null);
|
private latestReading: BehaviorSubject<WeatherReading> = new BehaviorSubject<WeatherReading>(null);
|
||||||
|
|
||||||
constructor() {
|
constructor(private httpClient: HttpClient) {
|
||||||
this.connection = new HubConnectionBuilder()
|
this.connection = new HubConnectionBuilder()
|
||||||
.withUrl('/api/hub/weather')
|
.withUrl('/api/hub/weather')
|
||||||
.build();
|
.build();
|
||||||
@@ -25,4 +30,13 @@ export class WeatherService {
|
|||||||
getLatestReading(): Observable<WeatherReading> {
|
getLatestReading(): Observable<WeatherReading> {
|
||||||
return this.latestReading.asObservable();
|
return this.latestReading.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getReadingValueHistory(valueType: WeatherValueType, start: moment.Moment, end: moment.Moment): Promise<WeatherValue[]> {
|
||||||
|
const startString = start.toISOString();
|
||||||
|
const endString = end.toISOString();
|
||||||
|
|
||||||
|
const data = await this.httpClient.get<WeatherValue[]>(`/api/weather/readings/value-history?weatherValueType=${valueType}&start=${startString}&end=${endString}`).toPromise();
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user