sensorgraph-june23
Mon Jun 23 2025 11:50:08 GMT+0000 (Coordinated Universal Time)
Saved by @AKAMAY001
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Line } from 'react-chartjs-2';
import 'chart.js/auto';
const SensorGraph = () => {
const [chartData, setChartData] = useState(null);
const [allData, setAllData] = useState([]);
const [selectedSensor, setSelectedSensor] = useState('All');
const [showTimestamps, setShowTimestamps] = useState(true);
const [showForecast, setShowForecast] = useState(false);
const [forecastData, setForecastData] = useState([]);
const [avgRainfall, setAvgRainfall] = useState(0);
const [currentWaterLevel, setCurrentWaterLevel] = useState(0);
const [last24hFlow, setLast24hFlow] = useState(0);
const variable = 'rainfall_mm'; // forecasting variable
const updateChart = (data, sensorFilter, forecastOverlay = []) => {
const filteredData = sensorFilter === 'All'
? data
: data.filter(entry => entry.sensor_id === sensorFilter);
const timestamps = filteredData.map(entry => entry.timestamp);
const rainfall = filteredData.map(entry => entry.rainfall_mm);
const waterLevel = filteredData.map(entry => entry.water_level_cm);
const flowRate = filteredData.map(entry => entry.flow_rate_lps);
// Stats
const avgRain = (rainfall.reduce((a, b) => a + b, 0) / rainfall.length || 0).toFixed(2);
const currWater = waterLevel[waterLevel.length - 1] || 0;
const now = new Date();
const past24h = new Date(now.getTime() - 24 * 60 * 60 * 1000);
const flowLast24h = filteredData.filter(entry => new Date(entry.timestamp) > past24h)
.map(e => e.flow_rate_lps);
const sumFlow = (flowLast24h.reduce((a, b) => a + b, 0) / flowLast24h.length || 0).toFixed(2);
setAvgRainfall(avgRain);
setCurrentWaterLevel(currWater.toFixed(2));
setLast24hFlow(sumFlow);
const datasets = [
{
label: 'Rainfall',
data: rainfall,
borderColor: 'blue',
backgroundColor: 'rgba(0, 0, 255, 0.1)',
tension: 0.4,
pointRadius: 3,
fill: true,
unit: ' mm'
},
{
label: 'Water Level',
data: waterLevel,
borderColor: 'green',
backgroundColor: 'rgba(0, 128, 0, 0.1)',
tension: 0.4,
pointRadius: 3,
fill: true,
unit: ' cm'
},
{
label: 'Flow Rate',
data: flowRate,
borderColor: 'orange',
backgroundColor: 'rgba(255, 165, 0, 0.1)',
tension: 0.4,
pointRadius: 3,
fill: true,
unit: ' lps'
}
];
if (forecastOverlay.length > 0) {
datasets.push({
label: 'Forecasted Rainfall',
data: forecastOverlay.map(d => d.value),
borderColor: 'purple',
borderDash: [6, 4],
backgroundColor: 'rgba(128, 0, 128, 0.1)',
tension: 0.4,
pointRadius: 2,
fill: false,
unit: ' mm'
});
const combinedLabels = [...timestamps, ...forecastOverlay.map(d => d.timestamp)];
setChartData({ labels: combinedLabels, datasets });
} else {
setChartData({ labels: timestamps, datasets });
}
};
const fetchForecast = async () => {
try {
const res = await axios.get(`http://localhost:5000/api/forecast?sensor_id=${selectedSensor}&variable=${variable}`);
setForecastData(res.data.forecast);
updateChart(allData, selectedSensor, res.data.forecast);
} catch (err) {
console.error("Forecast error:", err);
}
};
useEffect(() => {
axios.get('http://localhost:5000/get-sensor-data')
.then((res) => setAllData(res.data))
.catch(err => console.error("Error fetching sensor data:", err));
}, []);
useEffect(() => {
if (allData.length > 0) {
if (showForecast) {
fetchForecast();
} else {
updateChart(allData, selectedSensor);
}
}
}, [allData, selectedSensor, showForecast]);
const chartOptions = {
responsive: true,
plugins: {
tooltip: {
callbacks: {
label: function (context) {
const label = context.dataset.label || '';
const value = context.raw;
const unit = context.dataset.unit || '';
return `${label}: ${value}${unit}`;
}
}
},
legend: {
position: 'top',
labels: { font: { size: 14 } }
},
title: {
display: true,
text: 'SuDS Performance Over Time',
font: { size: 20 }
}
},
scales: {
x: {
ticks: {
display: showTimestamps,
maxRotation: 45,
minRotation: 20,
font: { size: 12 }
}
},
y: {
beginAtZero: true,
ticks: { font: { size: 12 } }
}
}
};
return (
<div style={{
backgroundColor: '#f4f7fa',
minHeight: '100vh',
padding: '40px',
fontFamily: 'Segoe UI, sans-serif'
}}>
<div style={{
backgroundColor: '#ffffff',
padding: '30px',
borderRadius: '12px',
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.1)',
maxWidth: '1000px',
margin: '0 auto'
}}>
<h1 style={{
fontSize: '24px',
marginBottom: '20px',
textAlign: 'center',
color: '#333'
}}>
SuDS Sensor Data Dashboard
</h1>
{/* Controls */}
<div style={{ textAlign: 'center', marginBottom: '10px' }}>
<label style={{ fontWeight: 'bold', marginRight: 10 }}>Sensor ID:</label>
<select
value={selectedSensor}
onChange={(e) => {
setSelectedSensor(e.target.value);
setForecastData([]);
}}
style={{
padding: '6px 12px',
fontSize: '14px',
borderRadius: '6px',
border: '1px solid #ccc',
marginRight: '10px'
}}
>
<option value="All">All Sensors</option>
{[...new Set(allData.map(d => d.sensor_id))].map((id, idx) => (
<option key={idx} value={id}>{id}</option>
))}
</select>
<button onClick={() => setShowTimestamps(prev => !prev)}
style={{
padding: '6px 12px',
fontSize: '14px',
borderRadius: '6px',
backgroundColor: '#007bff',
color: '#fff',
marginRight: '10px',
border: 'none'
}}>
{showTimestamps ? 'Hide Timestamps' : 'Show Timestamps'}
</button>
<button onClick={() => setShowForecast(prev => !prev)}
style={{
padding: '6px 12px',
fontSize: '14px',
borderRadius: '6px',
backgroundColor: showForecast ? '#6c757d' : '#28a745',
color: '#fff',
border: 'none'
}}>
{showForecast ? 'Hide Forecast' : 'Show Forecast'}
</button>
</div>
{/* Summary Stats */}
<div style={{ display: 'flex', justifyContent: 'space-around', marginBottom: '20px' }}>
<div style={{ background: '#e3f2fd', padding: '10px 20px', borderRadius: '8px' }}>
<strong>Avg Rainfall:</strong> {avgRainfall} mm
</div>
<div style={{ background: '#e8f5e9', padding: '10px 20px', borderRadius: '8px' }}>
<strong>Current Water Level:</strong> {currentWaterLevel} cm
</div>
<div style={{ background: '#fff8e1', padding: '10px 20px', borderRadius: '8px' }}>
<strong>Last 24h Flow:</strong> {last24hFlow} lps
</div>
</div>
{/* Chart */}
{chartData ? (
<Line data={chartData} options={chartOptions} />
) : (
<p style={{ textAlign: 'center', color: '#888' }}>Loading chart...</p>
)}
</div>
</div>
);
};
export default SensorGraph;



Comments