first commit

This commit is contained in:
mvbingham
2025-12-03 20:10:56 -05:00
commit 128f20501d
6 changed files with 1554 additions and 0 deletions

366
templates/dashboard.html Normal file
View File

@@ -0,0 +1,366 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lab Weather Dashboard</title>
<link
rel="stylesheet"
href="{{ url_for('static', filename='style.css') }}"
/>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
</head>
<body>
<div class="container">
<header>
<h1>MBTECH Binglab Envoro Dashboard</h1>
<p class="subtitle">Environmental Monitoring System</p>
</header>
<div class="current-readings">
<h2>Current Conditions</h2>
<div class="reading-cards">
<div class="card temperature-card">
<div class="card-icon">🌡️</div>
<div class="card-content">
<div class="card-value" id="current-temp">--</div>
<div class="card-label">Temperature (°C)</div>
<div class="card-sublabel" id="temp-raw" style="font-size: 0.85em; color: #888; margin-top: 4px;">Raw: --°C</div>
</div>
</div>
<div class="card pressure-card">
<div class="card-icon">🔽</div>
<div class="card-content">
<div class="card-value" id="current-pressure">
--
</div>
<div class="card-label">Pressure (hPa)</div>
</div>
</div>
<div class="card light-card">
<div class="card-icon">💡</div>
<div class="card-content">
<div class="card-value" id="current-light">--</div>
<div class="card-label">Light (lux)</div>
</div>
</div>
<div class="card color-card">
<div class="card-icon">🎨</div>
<div class="card-content">
<div class="color-swatch" id="color-swatch"></div>
<div class="card-label">Detected Color</div>
</div>
</div>
</div>
<div class="last-update">
Last update: <span id="last-update">--</span>
</div>
</div>
<div class="stats-section">
<h2>Today's Statistics</h2>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-title">Temperature</div>
<div class="stat-values">
<div class="stat-item">
<span class="stat-label">Min:</span>
<span class="stat-value" id="temp-min">--</span
>°C
</div>
<div class="stat-item">
<span class="stat-label">Max:</span>
<span class="stat-value" id="temp-max">--</span
>°C
</div>
<div class="stat-item">
<span class="stat-label">Avg:</span>
<span class="stat-value" id="temp-avg">--</span
>°C
</div>
</div>
</div>
<div class="stat-card">
<div class="stat-title">Pressure</div>
<div class="stat-values">
<div class="stat-item">
<span class="stat-label">Min:</span>
<span class="stat-value" id="pressure-min"
>--</span
>
hPa
</div>
<div class="stat-item">
<span class="stat-label">Max:</span>
<span class="stat-value" id="pressure-max"
>--</span
>
hPa
</div>
<div class="stat-item">
<span class="stat-label">Avg:</span>
<span class="stat-value" id="pressure-avg"
>--</span
>
hPa
</div>
</div>
</div>
<div class="stat-card">
<div class="stat-title">Light</div>
<div class="stat-values">
<div class="stat-item">
<span class="stat-label">Min:</span>
<span class="stat-value" id="light-min"
>--</span
>
lux
</div>
<div class="stat-item">
<span class="stat-label">Max:</span>
<span class="stat-value" id="light-max"
>--</span
>
lux
</div>
<div class="stat-item">
<span class="stat-label">Avg:</span>
<span class="stat-value" id="light-avg"
>--</span
>
lux
</div>
</div>
</div>
</div>
</div>
<div class="charts-section">
<h2>Historical Data</h2>
<div class="chart-container">
<canvas id="temperatureChart"></canvas>
</div>
<div class="chart-container">
<canvas id="pressureChart"></canvas>
</div>
<div class="chart-container">
<canvas id="lightChart"></canvas>
</div>
</div>
</div>
<script>
let tempChart, pressureChart, lightChart;
// Initialize charts
function initCharts() {
const commonOptions = {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 3,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
type: "category",
ticks: {
maxTicksLimit: 10,
},
},
y: {
beginAtZero: false,
},
},
};
tempChart = new Chart(
document.getElementById("temperatureChart"),
{
type: "line",
data: {
labels: [],
datasets: [
{
label: "Temperature (°C)",
data: [],
borderColor: "#ff6b6b",
backgroundColor: "rgba(255, 107, 107, 0.1)",
tension: 0.4,
fill: true,
},
],
},
options: commonOptions,
},
);
pressureChart = new Chart(
document.getElementById("pressureChart"),
{
type: "line",
data: {
labels: [],
datasets: [
{
label: "Pressure (hPa)",
data: [],
borderColor: "#4ecdc4",
backgroundColor: "rgba(78, 205, 196, 0.1)",
tension: 0.4,
fill: true,
},
],
},
options: commonOptions,
},
);
lightChart = new Chart(document.getElementById("lightChart"), {
type: "line",
data: {
labels: [],
datasets: [
{
label: "Light (lux)",
data: [],
borderColor: "#ffe66d",
backgroundColor: "rgba(255, 230, 109, 0.1)",
tension: 0.4,
fill: true,
},
],
},
options: commonOptions,
});
}
// Update current readings
async function updateCurrent() {
try {
const response = await fetch("/api/current");
const data = await response.json();
document.getElementById("current-temp").textContent =
data.temperature;
// Update raw temperature if available
if (data.temperature_raw !== undefined) {
document.getElementById("temp-raw").textContent =
`Raw: ${data.temperature_raw}°C`;
}
document.getElementById("current-pressure").textContent =
data.pressure;
document.getElementById("current-light").textContent =
data.light;
document.getElementById("last-update").textContent =
data.timestamp;
// Update color swatch if RGB data is available
if (data.rgb) {
const colorSwatch = document.getElementById("color-swatch");
colorSwatch.style.backgroundColor = `rgb(${data.rgb.r}, ${data.rgb.g}, ${data.rgb.b})`;
}
} catch (error) {
console.error("Error fetching current data:", error);
}
}
// Update statistics
async function updateStats() {
try {
const response = await fetch("/api/stats");
const data = await response.json();
if (data.temperature) {
document.getElementById("temp-min").textContent =
data.temperature.min;
document.getElementById("temp-max").textContent =
data.temperature.max;
document.getElementById("temp-avg").textContent =
data.temperature.avg;
}
if (data.pressure) {
document.getElementById("pressure-min").textContent =
data.pressure.min;
document.getElementById("pressure-max").textContent =
data.pressure.max;
document.getElementById("pressure-avg").textContent =
data.pressure.avg;
}
if (data.light) {
document.getElementById("light-min").textContent =
data.light.min;
document.getElementById("light-max").textContent =
data.light.max;
document.getElementById("light-avg").textContent =
data.light.avg;
}
} catch (error) {
console.error("Error fetching stats:", error);
}
}
// Update historical charts
async function updateHistory() {
try {
const response = await fetch("/api/history");
const data = await response.json();
if (data.length === 0) return;
const labels = data.map((d) => {
const date = new Date(d.timestamp);
return date.toLocaleTimeString("en-US", {
hour: "2-digit",
minute: "2-digit",
});
});
const temps = data.map((d) => d.temperature);
const pressures = data.map((d) => d.pressure);
const lights = data.map((d) => d.light);
tempChart.data.labels = labels;
tempChart.data.datasets[0].data = temps;
tempChart.update();
pressureChart.data.labels = labels;
pressureChart.data.datasets[0].data = pressures;
pressureChart.update();
lightChart.data.labels = labels;
lightChart.data.datasets[0].data = lights;
lightChart.update();
} catch (error) {
console.error("Error fetching history:", error);
}
}
// Initialize and start auto-refresh
initCharts();
updateCurrent();
updateStats();
updateHistory();
// Refresh current readings every 10 seconds
setInterval(updateCurrent, 10000);
// Refresh stats and history every 60 seconds
setInterval(() => {
updateStats();
updateHistory();
}, 60000);
</script>
</body>
</html>