2024-10-11 03:45:32 +00:00
|
|
|
import { Component, OnInit, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
|
|
|
|
|
import { Chart, registerables } from 'chart.js';
|
2024-10-16 10:13:13 +00:00
|
|
|
import { SensorService } from '../../../../cores/services/sensor.service';
|
2024-10-11 03:45:32 +00:00
|
|
|
import { ApiResponse, ParameterSensor} from '../../../../cores/interface/sensor-data';
|
2024-09-27 03:34:34 +00:00
|
|
|
import { CommonModule } from '@angular/common';
|
2024-10-11 03:45:32 +00:00
|
|
|
import { FormsModule } from '@angular/forms';
|
|
|
|
|
|
|
|
|
|
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',
|
|
|
|
|
};
|
|
|
|
|
|
2024-09-17 06:50:34 +00:00
|
|
|
@Component({
|
|
|
|
|
selector: 'app-graph',
|
|
|
|
|
standalone: true,
|
2024-10-11 03:45:32 +00:00
|
|
|
imports: [CommonModule, FormsModule],
|
2024-09-17 06:50:34 +00:00
|
|
|
templateUrl: './graph.component.html',
|
2024-09-27 03:34:34 +00:00
|
|
|
styleUrls: ['./graph.component.scss']
|
2024-09-17 06:50:34 +00:00
|
|
|
})
|
2024-10-11 03:45:32 +00:00
|
|
|
export class GraphComponent implements OnInit, AfterViewInit, OnDestroy {
|
2024-10-08 03:07:28 +00:00
|
|
|
@ViewChild('myChart', { static: false }) chartElement!: ElementRef<HTMLCanvasElement>;
|
2024-10-11 03:45:32 +00:00
|
|
|
selectedSensor: string = '';
|
|
|
|
|
selectedParameter: string = '';
|
2024-10-08 03:07:28 +00:00
|
|
|
parameters: string[] = [];
|
2024-10-11 03:45:32 +00:00
|
|
|
isLoading: boolean = true;
|
2024-09-17 06:50:34 +00:00
|
|
|
|
2024-09-27 03:34:34 +00:00
|
|
|
sensorParameters: { [key: string]: string[] } = {
|
2024-10-11 03:45:32 +00:00
|
|
|
dht: ['vicitemperature_avg', 'vicihumidity_avg', 'viciluminosity_avg'],
|
|
|
|
|
npk1: ['soiltemperature_avg', 'soilhumidity_avg', 'soilconductivity_avg', 'soilph_avg', 'soilnitrogen_avg', 'soilphosphorus_avg', 'soilpotassium_avg'],
|
|
|
|
|
npk2: ['soiltemperature_avg', 'soilhumidity_avg', 'soilconductivity_avg', 'soilph_avg', 'soilnitrogen_avg', 'soilphosphorus_avg', 'soilpotassium_avg'],
|
2024-09-27 03:34:34 +00:00
|
|
|
};
|
2024-09-17 06:50:34 +00:00
|
|
|
|
2024-10-11 03:45:32 +00:00
|
|
|
parameterDisplayNames: { [key: string]: string } = {
|
|
|
|
|
vicitemperature_avg: 'Temperature (°C)',
|
|
|
|
|
vicihumidity_avg: 'Humidity (%)',
|
|
|
|
|
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)',
|
2024-09-27 03:34:34 +00:00
|
|
|
};
|
2024-09-17 06:50:34 +00:00
|
|
|
|
2024-10-11 03:45:32 +00:00
|
|
|
chart: Chart | undefined;
|
|
|
|
|
labelsHourly: string[] = [];
|
|
|
|
|
private resizeListener!: () => void;
|
2024-09-17 06:50:34 +00:00
|
|
|
|
2024-10-16 10:13:13 +00:00
|
|
|
constructor(private sensorService: SensorService) {}
|
2024-09-17 06:50:34 +00:00
|
|
|
|
|
|
|
|
ngOnInit(): void {
|
2024-09-27 03:34:34 +00:00
|
|
|
this.selectedSensor = 'dht';
|
2024-10-11 03:45:32 +00:00
|
|
|
this.updateParameters();
|
|
|
|
|
this.selectedParameter = 'vicitemperature_avg';
|
|
|
|
|
this.updateChart();
|
|
|
|
|
this.resizeListener = this.onResize.bind(this);
|
|
|
|
|
window.addEventListener('resize', this.resizeListener);
|
2024-09-17 06:50:34 +00:00
|
|
|
}
|
2024-10-11 03:45:32 +00:00
|
|
|
|
2024-10-08 03:07:28 +00:00
|
|
|
ngAfterViewInit(): void {
|
2024-10-11 03:45:32 +00:00
|
|
|
this.updateChart();
|
2024-10-08 03:07:28 +00:00
|
|
|
}
|
2024-09-17 06:50:34 +00:00
|
|
|
|
2024-10-11 03:45:32 +00:00
|
|
|
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 {
|
2024-10-08 03:07:28 +00:00
|
|
|
const canvas = this.chartElement.nativeElement;
|
2024-09-17 06:50:34 +00:00
|
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
|
|
|
|
|
|
if (this.chart) {
|
2024-09-27 03:34:34 +00:00
|
|
|
this.chart.destroy();
|
2024-09-17 06:50:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ctx) {
|
2024-10-11 03:45:32 +00:00
|
|
|
const displayName = this.parameterDisplayNames[parameter] || parameter;
|
|
|
|
|
const borderColor = parameterColors[parameter] || '#000000';
|
|
|
|
|
const backgroundColor = `${borderColor}4D`;
|
|
|
|
|
|
2024-09-17 06:50:34 +00:00
|
|
|
this.chart = new Chart(ctx, {
|
|
|
|
|
type: 'line',
|
|
|
|
|
data: {
|
|
|
|
|
labels: labels,
|
|
|
|
|
datasets: [{
|
2024-10-11 03:45:32 +00:00
|
|
|
label: displayName,
|
2024-09-17 06:50:34 +00:00
|
|
|
data,
|
|
|
|
|
borderColor,
|
|
|
|
|
borderWidth: 1.5,
|
2024-09-27 06:53:18 +00:00
|
|
|
fill: true,
|
2024-10-11 03:45:32 +00:00
|
|
|
backgroundColor,
|
2024-09-27 03:34:34 +00:00
|
|
|
tension: 0.5,
|
2024-09-27 06:53:18 +00:00
|
|
|
pointRadius: 0,
|
|
|
|
|
pointHoverRadius: 0,
|
2024-09-17 06:50:34 +00:00
|
|
|
pointBackgroundColor: borderColor,
|
|
|
|
|
}]
|
|
|
|
|
},
|
|
|
|
|
options: {
|
|
|
|
|
responsive: true,
|
|
|
|
|
maintainAspectRatio: false,
|
|
|
|
|
plugins: {
|
|
|
|
|
tooltip: {
|
2024-09-27 03:34:34 +00:00
|
|
|
enabled: true,
|
|
|
|
|
mode: 'nearest',
|
|
|
|
|
intersect: false,
|
2024-09-27 04:11:34 +00:00
|
|
|
callbacks: {
|
2024-10-11 03:45:32 +00:00
|
|
|
label: (tooltipItem) => {
|
|
|
|
|
const paramLabel = displayName;
|
|
|
|
|
const value = tooltipItem.formattedValue;
|
|
|
|
|
return `${paramLabel}: ${value}`;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-17 06:50:34 +00:00
|
|
|
},
|
2024-10-11 03:45:32 +00:00
|
|
|
legend: { display: false }
|
2024-09-27 03:34:34 +00:00
|
|
|
},
|
|
|
|
|
scales: {
|
2024-10-11 03:45:32 +00:00
|
|
|
x: { grid: { display: false }, beginAtZero: true },
|
|
|
|
|
y: { grid: { display: false }, beginAtZero: true }
|
2024-09-17 06:50:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-11 03:45:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
getParameterKey(displayName: string): string {
|
|
|
|
|
return Object.keys(this.parameterDisplayNames).find(key => this.parameterDisplayNames[key] === displayName) || '';
|
|
|
|
|
}
|
2024-09-27 03:34:34 +00:00
|
|
|
|
|
|
|
|
onSensorChange(event: Event): void {
|
2024-10-11 03:45:32 +00:00
|
|
|
const select = event.target as HTMLSelectElement;
|
|
|
|
|
this.selectedSensor = select.value;
|
|
|
|
|
this.updateParameters();
|
|
|
|
|
if (this.selectedSensor === 'dht') {
|
|
|
|
|
this.selectedParameter = 'vicitemperature_avg';
|
|
|
|
|
} else if (this.selectedSensor === 'npk1' || this.selectedSensor === 'npk2') {
|
|
|
|
|
this.selectedParameter = 'soiltemperature_avg';
|
|
|
|
|
}
|
2024-09-27 03:34:34 +00:00
|
|
|
this.updateChart();
|
|
|
|
|
}
|
2024-09-17 06:50:34 +00:00
|
|
|
|
2024-10-11 03:45:32 +00:00
|
|
|
|
|
|
|
|
updateParameters(): void {
|
|
|
|
|
this.parameters = this.sensorParameters[this.selectedSensor].map(param => this.parameterDisplayNames[param]);
|
|
|
|
|
this.selectedParameter = this.parameters[1];
|
|
|
|
|
}
|
2024-09-17 06:50:34 +00:00
|
|
|
|
|
|
|
|
updateChart(): void {
|
2024-10-11 03:45:32 +00:00
|
|
|
this.isLoading = true;
|
|
|
|
|
|
|
|
|
|
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');
|
2024-10-08 03:07:28 +00:00
|
|
|
|
2024-10-16 10:13:13 +00:00
|
|
|
const startEnd= `${year}-${month}-${day}`;
|
2024-10-11 03:45:32 +00:00
|
|
|
const timeRange = 'HOURLY';
|
|
|
|
|
|
2024-10-16 10:13:13 +00:00
|
|
|
this.sensorService.getSensorData(this.selectedSensor, this.selectedParameter, startEnd, timeRange).subscribe(
|
2024-10-11 03:45:32 +00:00
|
|
|
(response: ApiResponse) => {
|
|
|
|
|
if (response.statusCode === 200) {
|
|
|
|
|
const { data, labels } = this.getDataFromResponse(response, this.selectedSensor, this.selectedParameter);
|
|
|
|
|
this.createChart(data, this.selectedParameter, labels);
|
|
|
|
|
} else {
|
|
|
|
|
console.error('Error fetching data:', response.message);
|
|
|
|
|
}
|
|
|
|
|
this.isLoading = false;
|
|
|
|
|
},
|
|
|
|
|
(error) => {
|
|
|
|
|
console.error('API Error:', error);
|
|
|
|
|
this.isLoading = false;
|
2024-10-08 03:07:28 +00:00
|
|
|
}
|
2024-10-11 03:45:32 +00:00
|
|
|
);
|
2024-09-17 06:50:34 +00:00
|
|
|
}
|
|
|
|
|
}
|