|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Pump Prediction</title>
|
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
|
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
|
|
<style>
|
|
body { background-color: #f4f8f4; }
|
|
.card { border-radius: 15px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); }
|
|
.card-header { background-color: #28a745; color: white; font-weight: bold; text-align: center; font-size: 1.5rem; }
|
|
.status-card { text-align: center; }
|
|
.status-label { font-size: 1.2rem; color: #555; }
|
|
.status-text { font-size: 2rem; font-weight: bold; padding: 10px 20px; border-radius: 8px; display: inline-block; transition: all 0.3s ease; }
|
|
.status-text.on { color: #28a745; background-color: #e9f5e9; border: 2px solid #28a745; }
|
|
.status-text.off { color: #dc3545; background-color: #f8d7da; border: 2px solid #dc3545; }
|
|
.chart-container { width: 100%; height: 400px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container my-4">
|
|
<div class="card">
|
|
<div class="card-header">Live Irrigation Status</div>
|
|
<div class="card-body">
|
|
<div class="row text-center mb-4">
|
|
<div class="col-md-6">
|
|
<div class="status-label">Current Pump Status</div>
|
|
<div id="pumpStatus" class="status-text off">Loading...</div>
|
|
</div>
|
|
<div class="col-md-6 mt-3 mt-md-0">
|
|
<div class="status-label">Time Elapsed</div>
|
|
<div id="time-counter" class="status-text" style="color: #5a2d0c; background-color: #f0e6e0; border-color: #5a2d0c;">0 seconds</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-6 mb-4">
|
|
<div class="card h-100">
|
|
<div class="card-body">
|
|
<div id="gauge" class="chart-container"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6 mb-4">
|
|
<div class="card h-100">
|
|
<div class="card-body">
|
|
<div id="graph1" class="chart-container"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6 mb-4">
|
|
<div class="card h-100">
|
|
<div class="card-body">
|
|
<div id="graph2" class="chart-container"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6 mb-4">
|
|
<div class="card h-100">
|
|
<div class="card-body">
|
|
<div id="graph3" class="chart-container"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let alertSound;
|
|
|
|
function initializeAudio() {
|
|
if (!alertSound) {
|
|
alertSound = new Audio('{{ url_for("static", filename="alarn_tune.mp3") }}');
|
|
console.log("Audio initialized.");
|
|
}
|
|
}
|
|
document.body.addEventListener('click', initializeAudio, { once: true });
|
|
|
|
function fetchPumpStatus() {
|
|
fetch('/update_pump_status')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const statusElement = document.getElementById('pumpStatus');
|
|
const newStatus = data.pump_status;
|
|
const oldStatus = statusElement.innerText;
|
|
|
|
statusElement.innerText = newStatus;
|
|
statusElement.className = 'status-text ' + (newStatus === 'On' ? 'on' : 'off');
|
|
|
|
if (newStatus === 'Off' && oldStatus === 'On' && alertSound) {
|
|
alertSound.play().catch(e => console.error("Audio play failed:", e));
|
|
}
|
|
});
|
|
}
|
|
|
|
function fetchGraphData() {
|
|
fetch('/update_graph')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.length === 0) return;
|
|
|
|
const time = data.map((_, i) => i * 2);
|
|
const soilMoisture = data.map(entry => entry[0]);
|
|
const pumpStatus = data.map(entry => entry[1]);
|
|
const currentSoilMoisture = soilMoisture[soilMoisture.length - 1];
|
|
|
|
|
|
const responsiveLayout = { margin: { t: 40, b: 50, l: 50, r: 20 }, autosize: true };
|
|
|
|
Plotly.react('gauge', getGaugeData(currentSoilMoisture), { ...responsiveLayout, title: 'Soil Moisture' });
|
|
Plotly.react('graph1', getPumpStatusData(time, pumpStatus), { ...responsiveLayout, title: 'Pump Status vs. Time', yaxis: { tickvals: [-1, 1], ticktext: ['Off', 'On'], range: [-1.5, 1.5] }});
|
|
Plotly.react('graph2', getSoilMoistureData(time, soilMoisture), { ...responsiveLayout, title: 'Soil Moisture vs. Time' });
|
|
Plotly.react('graph3', getMoistureVsStatusData(soilMoisture, pumpStatus), { ...responsiveLayout, title: 'Pump Status vs. Soil Moisture', yaxis: { tickvals: [-1, 1], ticktext: ['Off', 'On'], range: [-1.5, 1.5] }});
|
|
});
|
|
}
|
|
|
|
|
|
const getGaugeData = value => [{ type: "indicator", mode: "gauge+number", value: value, gauge: { axis: { range: [0, 100] }, steps: [{ range: [0, 30], color: "#ea4335" },{ range: [30, 60], color: "#fbbc05" },{ range: [60, 100], color: "#34a853" }]}}];
|
|
const getPumpStatusData = (x, y) => [{ x, y, mode: 'lines+markers', type: 'scatter', line: { color: '#4285f4' } }];
|
|
const getSoilMoistureData = (x, y) => [{ x, y, mode: 'lines+markers', type: 'scatter', line: { color: '#34a853' } }];
|
|
const getMoistureVsStatusData = (x, y) => [{ x, y, mode: 'lines', type: 'scatter', line: { color: '#ea4335' } }];
|
|
|
|
let timeCounter = 0;
|
|
setInterval(() => { document.getElementById('time-counter').innerText = `${++timeCounter} seconds`; }, 1000);
|
|
setInterval(fetchPumpStatus, 2000);
|
|
setInterval(fetchGraphData, 2000);
|
|
</script>
|
|
</body>
|
|
</html> |