feat(dashboard): integration API in data graph and data latest
This commit is contained in:
parent
59e89aee72
commit
581ca5f35c
|
|
@ -1,8 +1,13 @@
|
||||||
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
||||||
import { provideRouter } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)]
|
providers: [
|
||||||
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||||
|
provideRouter(routes),
|
||||||
|
provideHttpClient()
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,50 @@
|
||||||
import { Timestamp } from "rxjs";
|
export interface ParameterSensor {
|
||||||
|
hour: number;
|
||||||
|
|
||||||
|
//for DHT sensor
|
||||||
|
vicitemperature_avg?: number;
|
||||||
|
vicihumidity_avg?: number;
|
||||||
|
viciluminosity_avg?: number;
|
||||||
|
|
||||||
|
// for NPK1 & NPK2 sensor
|
||||||
|
soiltemperature_avg?: number;
|
||||||
|
soilhumidity_avg?: number;
|
||||||
|
soilconductivity_avg?: number;
|
||||||
|
soilph_avg?: number;
|
||||||
|
soilnitrogen_avg?: number;
|
||||||
|
soilphosphorus_avg?: number;
|
||||||
|
soilpotassium_avg?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiResponse {
|
||||||
|
data: {
|
||||||
|
dht?: ParameterSensor[];
|
||||||
|
npk1?: ParameterSensor[];
|
||||||
|
npk2?: ParameterSensor[];
|
||||||
|
};
|
||||||
|
statusCode: number;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DHTSensor {
|
||||||
|
lightIntensity: number;
|
||||||
|
temperature: number;
|
||||||
|
humidity: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NPKSensor {
|
||||||
|
temperature: number;
|
||||||
|
moisture: number;
|
||||||
|
conductivity: number;
|
||||||
|
ph: number;
|
||||||
|
nitrogen: number;
|
||||||
|
phosphorus: number;
|
||||||
|
potassium: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SensorData {
|
export interface SensorData {
|
||||||
id: Timestamp<number>;
|
dht: DHTSensor;
|
||||||
humidity: number;
|
npk1: NPKSensor;
|
||||||
temperature: number;
|
npk2: NPKSensor;
|
||||||
soil_moisture: number;
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,29 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { ApiResponse } from '../interface/sensor-data';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class ApiService {
|
export class ApiService {
|
||||||
private apiURL = 'https://jx027dj4-5000.asse.devtunnels.ms/api/sensor-data';
|
private baseUrl = 'https://jx027dj4-3333.asse.devtunnels.ms/api/sensor/';
|
||||||
|
|
||||||
constructor(private http: HttpClient) { }
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
get(){
|
getSensorData(sensor: string, metric: string, startDate: string, timeRange: string): Observable<ApiResponse> {
|
||||||
return this.http.get(this.apiURL);
|
const url = `${this.baseUrl}getData`;
|
||||||
|
const params = new HttpParams()
|
||||||
|
.set('range[start]', startDate)
|
||||||
|
.set('range[time_range]', timeRange)
|
||||||
|
.set('sensor', sensor)
|
||||||
|
.set('metric', metric);
|
||||||
|
|
||||||
|
return this.http.get<ApiResponse>(url, { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLatestData(): Observable<ApiResponse> {
|
||||||
|
const url = `${this.baseUrl}getLatest`;
|
||||||
|
return this.http.get<ApiResponse>(url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,43 +4,27 @@ import { SidebarComponent } from './layouts/sidebar/sidebar.component';
|
||||||
import { GaugeChartComponent } from './page/gauge-chart/gauge-chart.component';
|
import { GaugeChartComponent } from './page/gauge-chart/gauge-chart.component';
|
||||||
import { GraphComponent } from './page/graph/graph.component';
|
import { GraphComponent } from './page/graph/graph.component';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ApiService } from '../../cores/services/api.service';
|
||||||
|
import { SensorData } from '../../cores/interface/sensor-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [RouterOutlet, SidebarComponent, GaugeChartComponent, GraphComponent, CommonModule],
|
imports: [RouterOutlet, SidebarComponent, GaugeChartComponent, CommonModule, GraphComponent],
|
||||||
templateUrl: './dashboard.component.html',
|
templateUrl: './dashboard.component.html',
|
||||||
styleUrls: ['./dashboard.component.scss']
|
styleUrls: ['./dashboard.component.scss']
|
||||||
})
|
})
|
||||||
export class DashboardComponent implements OnInit {
|
export class DashboardComponent implements OnInit {
|
||||||
isLoaded: boolean = false;
|
isLoaded: boolean = false;
|
||||||
selectedButton: string = '';
|
selectedButton: string = '';
|
||||||
sensorData: any = {
|
sensorData: SensorData = {
|
||||||
dht: {
|
dht: { lightIntensity: 0, temperature: 0, humidity: 0 },
|
||||||
lightIntensity: '3539',
|
npk1: { temperature: 0, moisture: 0, conductivity: 0, ph: 0, nitrogen: 0, phosphorus: 0, potassium: 0 },
|
||||||
temperature: '27',
|
npk2: { temperature: 0, moisture: 0, conductivity: 0, ph: 0, nitrogen: 0, phosphorus: 0, potassium: 0 }
|
||||||
humidity: '80'
|
|
||||||
},
|
|
||||||
npk1: {
|
|
||||||
temperature: '28',
|
|
||||||
moisture: '99.9',
|
|
||||||
conductivity: '1.5',
|
|
||||||
ph: '8.51',
|
|
||||||
nitrogen: '500',
|
|
||||||
phosphorus: '500',
|
|
||||||
potassium: '500'
|
|
||||||
},
|
|
||||||
npk2: {
|
|
||||||
temperature: '28.6',
|
|
||||||
moisture: '99.8',
|
|
||||||
conductivity: '1.4',
|
|
||||||
ph: '8.55',
|
|
||||||
nitrogen: '510',
|
|
||||||
phosphorus: '512',
|
|
||||||
potassium: '500'
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constructor(private apiService: ApiService) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.selectedButton = 'dht';
|
this.selectedButton = 'dht';
|
||||||
this.loadData();
|
this.loadData();
|
||||||
|
|
@ -53,8 +37,48 @@ export class DashboardComponent implements OnInit {
|
||||||
|
|
||||||
loadData(): void {
|
loadData(): void {
|
||||||
this.isLoaded = true;
|
this.isLoaded = true;
|
||||||
setTimeout(() => {
|
|
||||||
this.isLoaded = false;
|
this.apiService.getLatestData().subscribe(
|
||||||
}, 1000);
|
(response) => {
|
||||||
|
const data = response.data;
|
||||||
|
if (data.dht && data.dht.length > 0) {
|
||||||
|
this.sensorData.dht = {
|
||||||
|
lightIntensity: data.dht[0].viciluminosity_avg ?? 0,
|
||||||
|
temperature: data.dht[0].vicitemperature_avg ?? 0,
|
||||||
|
humidity: data.dht[0].vicihumidity_avg ?? 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.npk1 && data.npk1.length > 0) {
|
||||||
|
this.sensorData.npk1 = {
|
||||||
|
temperature: data.npk1[0].soiltemperature_avg ?? 0,
|
||||||
|
moisture: data.npk1[0].soilhumidity_avg ?? 0,
|
||||||
|
conductivity: data.npk1[0].soilconductivity_avg ?? 0,
|
||||||
|
ph: data.npk1[0].soilph_avg ?? 0,
|
||||||
|
nitrogen: data.npk1[0].soilnitrogen_avg ?? 0,
|
||||||
|
phosphorus: data.npk1[0].soilphosphorus_avg ?? 0,
|
||||||
|
potassium: data.npk1[0].soilpotassium_avg ?? 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.npk2 && data.npk2.length > 0) {
|
||||||
|
this.sensorData.npk2 = {
|
||||||
|
temperature: data.npk2[0].soiltemperature_avg ?? 0,
|
||||||
|
moisture: data.npk2[0].soilhumidity_avg ?? 0,
|
||||||
|
conductivity: data.npk2[0].soilconductivity_avg ?? 0,
|
||||||
|
ph: data.npk2[0].soilph_avg ?? 0,
|
||||||
|
nitrogen: data.npk2[0].soilnitrogen_avg ?? 0,
|
||||||
|
phosphorus: data.npk2[0].soilphosphorus_avg ?? 0,
|
||||||
|
potassium: data.npk2[0].soilpotassium_avg ?? 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoaded = false;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error('Error fetching sensor data:', error);
|
||||||
|
this.isLoaded = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@
|
||||||
<option value="npk1">NPK 1</option>
|
<option value="npk1">NPK 1</option>
|
||||||
<option value="npk2">NPK 2</option>
|
<option value="npk2">NPK 2</option>
|
||||||
</select>
|
</select>
|
||||||
<select class="form-select" id="parameterSelect" (change)="updateChart()">
|
|
||||||
<option *ngFor="let parameter of parameters" [value]="parameter">{{ parameter }}</option>
|
<select class="form-select" id="parameterSelect" (change)="updateChart()" [(ngModel)]="selectedParameter">
|
||||||
</select>
|
<option *ngFor="let parameter of parameters" [value]="getParameterKey(parameter)">{{ parameter }}</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="isLoading" class="loading">
|
<div *ngIf="isLoading" class="loading">
|
||||||
|
|
@ -14,5 +15,3 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<canvas #myChart id="myChart"></canvas>
|
<canvas #myChart id="myChart"></canvas>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,107 @@
|
||||||
|
import { Component, OnInit, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
|
||||||
|
import { Chart, registerables } from 'chart.js';
|
||||||
|
import { ApiService } from '../../../../cores/services/api.service';
|
||||||
|
import { ApiResponse, ParameterSensor} from '../../../../cores/interface/sensor-data';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { Chart, LineController, LineElement, PointElement, LinearScale, Title, CategoryScale, Tooltip, Filler } from 'chart.js';
|
|
||||||
|
Chart.register(...registerables);
|
||||||
|
const parameterColors: { [key: string]: string } = {
|
||||||
|
vicitemperature_avg: '#8F5A62',
|
||||||
|
vicihumidity_avg: '#16423C',
|
||||||
|
viciluminosity_avg: '#DF9B55',
|
||||||
|
soiltemperature_avg: '#8F5A62',
|
||||||
|
soilhumidity_avg: '#54909c',
|
||||||
|
soilconductivity_avg: '#661311',
|
||||||
|
soilph_avg: '#664735',
|
||||||
|
soilnitrogen_avg: '#3a6635',
|
||||||
|
soilphosphorus_avg: '#3f3566',
|
||||||
|
soilpotassium_avg: '#5f3566',
|
||||||
|
};
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-graph',
|
selector: 'app-graph',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule],
|
imports: [CommonModule, FormsModule],
|
||||||
templateUrl: './graph.component.html',
|
templateUrl: './graph.component.html',
|
||||||
styleUrls: ['./graph.component.scss']
|
styleUrls: ['./graph.component.scss']
|
||||||
})
|
})
|
||||||
export class GraphComponent implements OnInit {
|
export class GraphComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||||
@ViewChild('myChart', { static: false }) chartElement!: ElementRef<HTMLCanvasElement>;
|
@ViewChild('myChart', { static: false }) chartElement!: ElementRef<HTMLCanvasElement>;
|
||||||
selectedSensor: string | null = null;
|
selectedSensor: string = '';
|
||||||
|
selectedParameter: string = '';
|
||||||
parameters: string[] = [];
|
parameters: string[] = [];
|
||||||
isLoading: boolean = true;
|
isLoading: boolean = true;
|
||||||
|
|
||||||
sensorParameters: { [key: string]: string[] } = {
|
sensorParameters: { [key: string]: string[] } = {
|
||||||
dht: ['Temperature', 'Humidity', 'Light'],
|
dht: ['vicitemperature_avg', 'vicihumidity_avg', 'viciluminosity_avg'],
|
||||||
npk1: ['Temperature', 'Moisture', 'Conductivity', 'ph', 'Nitrogen', 'Phosphorus', 'Potassium'],
|
npk1: ['soiltemperature_avg', 'soilhumidity_avg', 'soilconductivity_avg', 'soilph_avg', 'soilnitrogen_avg', 'soilphosphorus_avg', 'soilpotassium_avg'],
|
||||||
npk2: ['Temperature', 'Moisture', 'Conductivity', 'ph', 'Nitrogen', 'Phosphorus', 'Potassium']
|
npk2: ['soiltemperature_avg', 'soilhumidity_avg', 'soilconductivity_avg', 'soilph_avg', 'soilnitrogen_avg', 'soilphosphorus_avg', 'soilpotassium_avg'],
|
||||||
};
|
};
|
||||||
|
|
||||||
dhtData = {
|
parameterDisplayNames: { [key: string]: string } = {
|
||||||
humidity: [65, 59, 80, 81, 56, 55, 40, 41, 60, 65, 59, 80, 81, 56, 55, 40, 41, 60, 65, 59, 80, 81, 56, 55],
|
vicitemperature_avg: 'Temperature (°C)',
|
||||||
temperature: [22, 23, 25, 24, 26, 27, 28, 29, 25, 23, 22, 24, 26, 27, 28, 29, 29, 28, 28, 25, 25, 25, 26, 27],
|
vicihumidity_avg: 'Humidity (%)',
|
||||||
light: [200, 220, 230, 210, 250, 240, 260, 265, 270, 200, 220, 230, 210, 250, 240, 260, 265, 270, 275, 280, 285, 290, 295, 300]
|
viciluminosity_avg: 'Luminosity (lx)',
|
||||||
|
soiltemperature_avg: 'Soil Temperature (°C)',
|
||||||
|
soilhumidity_avg: 'Soil Humidity (%)',
|
||||||
|
soilconductivity_avg: 'Conductivity (mS/cm)',
|
||||||
|
soilph_avg: 'pH',
|
||||||
|
soilnitrogen_avg: 'Nitrogen (PPM)',
|
||||||
|
soilphosphorus_avg: 'Phosphorus (PPM)',
|
||||||
|
soilpotassium_avg: 'Potassium (PPM)',
|
||||||
};
|
};
|
||||||
|
|
||||||
npk1Data = {
|
chart: Chart | undefined;
|
||||||
temperature: [23, 24, 26, 27, 28, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 23, 24, 26, 27, 28, 29, 28, 27],
|
labelsHourly: string[] = [];
|
||||||
moisture: [30, 35, 32, 36, 34, 37, 33, 31, 32, 30, 35, 32, 36, 34, 37, 33, 31, 32, 30, 35, 32, 36, 34, 37],
|
private resizeListener!: () => void;
|
||||||
conductivity: [500, 550, 600, 520, 510, 530, 540, 580, 590, 500, 550, 600, 520, 510, 530, 540, 580, 590, 500, 550, 600, 520, 510, 530],
|
|
||||||
ph: [6.5, 6.7, 6.8, 7.0, 7.1, 6.9, 6.6, 6.8, 6.9, 6.5, 6.7, 6.8, 7.0, 7.1, 6.9, 6.6, 6.8, 6.9, 6.5, 6.7, 6.8, 7.0, 7.1, 6.9],
|
|
||||||
nitrogen: [300, 310, 320, 330, 340, 350, 355, 360, 365, 300, 310, 320, 330, 340, 350, 355, 360, 365, 300, 310, 320, 330, 340, 350],
|
|
||||||
phosphorus: [200, 210, 215, 220, 225, 220, 215, 210, 200, 210, 215, 220, 225, 220, 215, 210, 200, 210, 215, 220, 225, 220, 215, 210],
|
|
||||||
potassium: [180, 190, 200, 205, 210, 215, 220, 225, 230, 180, 190, 200, 205, 210, 215, 220, 225, 230, 180, 190, 200, 205, 210, 215],
|
|
||||||
};
|
|
||||||
|
|
||||||
npk2Data = {
|
constructor(private sensorService: ApiService) {}
|
||||||
temperature: [24, 25, 27, 28, 29, 28, 26, 25, 24, 23, 22, 21, 20, 19, 23, 24, 26, 27, 28, 29, 28, 26, 25, 24],
|
|
||||||
moisture: [31, 36, 33, 38, 35, 37, 34, 32, 33, 31, 36, 33, 38, 35, 37, 34, 32, 33, 31, 36, 33, 38, 35, 37],
|
|
||||||
conductivity: [520, 530, 540, 510, 550, 570, 580, 590, 600, 520, 530, 540, 510, 550, 570, 580, 590, 600, 520, 530, 540, 510, 550, 570],
|
|
||||||
ph: [6.6, 6.9, 7.1, 6.7, 6.8, 6.9, 6.6, 6.8, 6.9, 6.6, 6.9, 7.1, 6.7, 6.8, 6.9, 6.6, 6.8, 6.9, 6.6, 6.9, 7.1, 6.7, 6.8, 6.9],
|
|
||||||
nitrogen: [320, 330, 340, 350, 360, 400, 410, 420, 430, 320, 330, 340, 350, 360, 400, 410, 420, 430, 320, 330, 340, 350, 360, 400],
|
|
||||||
phosphorus: [210, 220, 225, 230, 235, 240, 245, 250, 255, 210, 220, 225, 230, 235, 240, 245, 250, 255, 210, 220, 225, 230, 235, 240],
|
|
||||||
potassium: [190, 195, 205, 210, 215, 220, 225, 230, 235, 190, 195, 205, 210, 215, 220, 225, 230, 235, 190, 195, 205, 210, 215, 220]
|
|
||||||
};
|
|
||||||
|
|
||||||
chart: any;
|
|
||||||
labelHourly = [
|
|
||||||
'01.00', '02.00', '03.00', '04.00', '05.00', '06.00', '07.00', '08.00',
|
|
||||||
'09.00', '10.00', '11.00', '12.00', '13.00', '14.00', '15.00', '16.00',
|
|
||||||
'17.00', '18.00', '19.00', '20.00', '21.00', '22.00', '23.00', '24.00'
|
|
||||||
];
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
Chart.register(LineController, LineElement, PointElement, LinearScale, Title, CategoryScale, Tooltip, Filler);
|
|
||||||
this.selectedSensor = 'dht';
|
this.selectedSensor = 'dht';
|
||||||
this.parameters = this.sensorParameters[this.selectedSensor];
|
this.updateParameters();
|
||||||
|
this.selectedParameter = 'vicitemperature_avg';
|
||||||
|
this.updateChart();
|
||||||
|
this.resizeListener = this.onResize.bind(this);
|
||||||
|
window.addEventListener('resize', this.resizeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
this.isLoading = true;
|
this.updateChart();
|
||||||
setTimeout(() => {
|
|
||||||
this.createChart(this.dhtData.temperature, 'Temperature', '#8F5A62', this.labelHourly);
|
|
||||||
this.isLoading = false;
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
if (this.chart) {
|
|
||||||
this.chart.destroy();
|
|
||||||
this.createChart(this.dhtData.temperature, 'Temperature', '#8F5A62', this.labelHourly);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
createChart(data: number[], label: string, borderColor: string, labels: string[]): void {
|
ngOnDestroy(): void {
|
||||||
|
window.removeEventListener('resize', this.resizeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
onResize(): void {
|
||||||
|
if (this.chart) {
|
||||||
|
this.chart.destroy();
|
||||||
|
this.updateChart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDataFromResponse(response: ApiResponse, sensor: string, parameter: string): { data: number[], labels: string[] } {
|
||||||
|
const sensorData = response.data[sensor as keyof typeof response.data];
|
||||||
|
|
||||||
|
const data: number[] = [];
|
||||||
|
const labels: string[] = [];
|
||||||
|
|
||||||
|
if (sensorData) {
|
||||||
|
sensorData.forEach(item => {
|
||||||
|
data.push(item[parameter as keyof ParameterSensor] ?? 0);
|
||||||
|
labels.push(`${item.hour}.00`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('No data found for sensor:', sensor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data, labels };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
createChart(data: number[], parameter: string, labels: string[]): void {
|
||||||
const canvas = this.chartElement.nativeElement;
|
const canvas = this.chartElement.nativeElement;
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
|
@ -84,17 +110,21 @@ export class GraphComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
|
const displayName = this.parameterDisplayNames[parameter] || parameter;
|
||||||
|
const borderColor = parameterColors[parameter] || '#000000';
|
||||||
|
const backgroundColor = `${borderColor}4D`;
|
||||||
|
|
||||||
this.chart = new Chart(ctx, {
|
this.chart = new Chart(ctx, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label,
|
label: displayName,
|
||||||
data,
|
data,
|
||||||
borderColor,
|
borderColor,
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
fill: true,
|
fill: true,
|
||||||
backgroundColor: borderColor + '4D',
|
backgroundColor,
|
||||||
tension: 0.5,
|
tension: 0.5,
|
||||||
pointRadius: 0,
|
pointRadius: 0,
|
||||||
pointHoverRadius: 0,
|
pointHoverRadius: 0,
|
||||||
|
|
@ -110,124 +140,72 @@ export class GraphComponent implements OnInit {
|
||||||
mode: 'nearest',
|
mode: 'nearest',
|
||||||
intersect: false,
|
intersect: false,
|
||||||
callbacks: {
|
callbacks: {
|
||||||
label: (tooltipItem: any) => {
|
label: (tooltipItem) => {
|
||||||
const datasetLabel = tooltipItem.dataset.label.toLowerCase();
|
const paramLabel = displayName;
|
||||||
const formattedValue = tooltipItem.formattedValue;
|
const value = tooltipItem.formattedValue;
|
||||||
|
return `${paramLabel}: ${value}`;
|
||||||
let unit = '';
|
}
|
||||||
switch (datasetLabel) {
|
}
|
||||||
case 'temperature':
|
|
||||||
unit = '°C';
|
|
||||||
break;
|
|
||||||
case 'light':
|
|
||||||
unit = 'lux';
|
|
||||||
break;
|
|
||||||
case 'moisture':
|
|
||||||
case 'humidity':
|
|
||||||
unit = '%';
|
|
||||||
break;
|
|
||||||
case 'conductivity':
|
|
||||||
unit = 'mS/cm';
|
|
||||||
break;
|
|
||||||
case 'nitrogen':
|
|
||||||
case 'phosphorus':
|
|
||||||
case 'potassium':
|
|
||||||
unit = 'NPM';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
unit = '';
|
|
||||||
}
|
|
||||||
return `${tooltipItem.dataset.label}: ${formattedValue} ${unit}`;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: { display: false }
|
||||||
display: false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: { grid: { display: false }, beginAtZero: true },
|
||||||
grid:{
|
y: { grid: { display: false }, beginAtZero: true }
|
||||||
display: false
|
|
||||||
},
|
|
||||||
beginAtZero: true
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
grid:{
|
|
||||||
display: false
|
|
||||||
},
|
|
||||||
beginAtZero: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getParameterKey(displayName: string): string {
|
||||||
|
return Object.keys(this.parameterDisplayNames).find(key => this.parameterDisplayNames[key] === displayName) || '';
|
||||||
|
}
|
||||||
|
|
||||||
onSensorChange(event: Event): void {
|
onSensorChange(event: Event): void {
|
||||||
const selectElement = event.target as HTMLSelectElement;
|
const select = event.target as HTMLSelectElement;
|
||||||
this.selectedSensor = selectElement.value;
|
this.selectedSensor = select.value;
|
||||||
this.parameters = this.sensorParameters[this.selectedSensor];
|
this.updateParameters();
|
||||||
|
if (this.selectedSensor === 'dht') {
|
||||||
const defaultParameter = this.parameters[0];
|
this.selectedParameter = 'vicitemperature_avg';
|
||||||
(document.getElementById('parameterSelect') as HTMLSelectElement).value = defaultParameter;
|
} else if (this.selectedSensor === 'npk1' || this.selectedSensor === 'npk2') {
|
||||||
|
this.selectedParameter = 'soiltemperature_avg';
|
||||||
|
}
|
||||||
this.updateChart();
|
this.updateChart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateParameters(): void {
|
||||||
|
this.parameters = this.sensorParameters[this.selectedSensor].map(param => this.parameterDisplayNames[param]);
|
||||||
|
this.selectedParameter = this.parameters[1];
|
||||||
|
}
|
||||||
|
|
||||||
updateChart(): void {
|
updateChart(): void {
|
||||||
this.isLoading= true;
|
this.isLoading = true;
|
||||||
setTimeout(() => {
|
|
||||||
const parameter = (document.getElementById('parameterSelect') as HTMLSelectElement).value.toLowerCase();
|
const today = new Date();
|
||||||
|
const year = today.getFullYear();
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(today.getDate()).padStart(2, '0');
|
||||||
|
|
||||||
|
const startDate = `${year}-${month}-${day}`;
|
||||||
|
const timeRange = 'HOURLY';
|
||||||
|
|
||||||
let newData: number[] | undefined;
|
this.sensorService.getSensorData(this.selectedSensor, this.selectedParameter, startDate, timeRange).subscribe(
|
||||||
let newLabel: string = '';
|
(response: ApiResponse) => {
|
||||||
let newColor: string = '';
|
if (response.statusCode === 200) {
|
||||||
|
const { data, labels } = this.getDataFromResponse(response, this.selectedSensor, this.selectedParameter);
|
||||||
const humidity = '#16423C';
|
this.createChart(data, this.selectedParameter, labels);
|
||||||
const temperature = '#8F5A62';
|
} else {
|
||||||
const light = '#DF9B55';
|
console.error('Error fetching data:', response.message);
|
||||||
const moisture = '#54909c';
|
}
|
||||||
const conductivity = '#661311';
|
this.isLoading = false;
|
||||||
const ph = '#664735';
|
},
|
||||||
const nitrogen = '#3a6635';
|
(error) => {
|
||||||
const phosphorus = '#3f3566';
|
console.error('API Error:', error);
|
||||||
const potassium = '#5f3566';
|
this.isLoading = false;
|
||||||
|
|
||||||
switch (this.selectedSensor) {
|
|
||||||
case 'dht':
|
|
||||||
newData = this.dhtData[parameter as keyof typeof this.dhtData];
|
|
||||||
newLabel = parameter.charAt(0).toUpperCase() + parameter.slice(1);
|
|
||||||
newColor = (parameter === 'humidity') ? humidity :
|
|
||||||
(parameter === 'temperature') ? temperature : light;
|
|
||||||
break;
|
|
||||||
case 'npk1':
|
|
||||||
newData = this.npk1Data[parameter as keyof typeof this.npk1Data];
|
|
||||||
newLabel = parameter.charAt(0).toUpperCase() + parameter.slice(1);
|
|
||||||
newColor = (parameter === 'temperature') ? temperature :
|
|
||||||
(parameter === 'moisture') ? moisture :
|
|
||||||
(parameter === 'conductivity') ? conductivity :
|
|
||||||
(parameter === 'ph') ? ph :
|
|
||||||
(parameter === 'nitrogen') ? nitrogen :
|
|
||||||
(parameter === 'phosphorus') ? phosphorus : potassium;
|
|
||||||
break;
|
|
||||||
case 'npk2':
|
|
||||||
newData = this.npk2Data[parameter as keyof typeof this.npk2Data];
|
|
||||||
newLabel = parameter.charAt(0).toUpperCase() + parameter.slice(1);
|
|
||||||
newColor = (parameter === 'temperature') ? temperature :
|
|
||||||
(parameter === 'moisture') ? moisture :
|
|
||||||
(parameter === 'conductivity') ? conductivity :
|
|
||||||
(parameter === 'ph') ? ph :
|
|
||||||
(parameter === 'nitrogen') ? nitrogen :
|
|
||||||
(parameter === 'phosphorus') ? phosphorus : potassium;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error('Sensor tidak ditemukan');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
this.createChart(newData, newLabel, newColor, this.labelHourly);
|
);
|
||||||
this.isLoading=false;
|
|
||||||
}, 2000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user