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