Smart Garden Monitor

Plot Status

Alerts

    Soil Moisture Trend (Last 24h)

    Manage Your Garden Plots

    Manage Sensor Readings

    Add New Reading

    Sensor Log

    TimePlotMoistureTempActions

    No data yet.

    `; } card.classList.add(statusClass); plotsGrid.appendChild(card); }); if(alertCount === 0) alertsList.innerHTML = '
  • ✅ No urgent alerts. All systems normal.
  • '; // Chart const twentyFourHoursAgo = dateFns.subHours(currentTime, 24); const trendData = state.sensorLog.filter(l => l.timestamp >= twentyFourHoursAgo); const datasets = state.plots.map((plot, i) => { const colors = ['#2980b9', '#27ae60', '#f39c12']; return { label: plot.name, data: trendData.filter(l => l.plotId === plot.id).map(l => ({ x: l.timestamp, y: l.soilMoisture })), borderColor: colors[i % colors.length], tension: 0.1 } }); charts.moisture = new Chart(document.getElementById('moistureChart').getContext('2d'), { type: 'line', data: { datasets }, options: { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'hour' } }, y: { title: { display: true, text: 'Soil Moisture (%)' } } } } }); }; const renderManagementTab = () => { // Render Plots Management Table const plotManager = document.getElementById('plots-manager'); let plotTable = ``; state.plots.forEach(p => { plotTable += ``; }); plotManager.innerHTML = plotTable + '
    Plot NamePlant TypeMoisture Min/MaxActions
    ${p.name}${p.plantType}${p.settings.minMoisture}% / ${p.settings.maxMoisture}%
    '; // Render Log Table const logBody = document.getElementById('log-tbody'); logBody.innerHTML = ''; state.sensorLog.sort((a,b)=>b.timestamp-a.timestamp).forEach(log => { const plot = state.plots.find(p => p.id === log.plotId); const row = document.createElement('tr'); row.innerHTML = `${log.timestamp.toLocaleString()}${plot?.name || 'N/A'}${log.soilMoisture}%${log.temperature}°C `; logBody.appendChild(row); }); // Populate dropdown logForm.plot.innerHTML = state.plots.map(p => ``).join(''); }; // --- EVENT LISTENERS --- plotForm.addEventListener('submit', (e) => { e.preventDefault(); const newPlot = { id: Date.now(), name: document.getElementById('plot-name').value, plantType: document.getElementById('plant-type').value, settings: { minMoisture: parseInt(document.getElementById('min-moisture').value), maxMoisture: parseInt(document.getElementById('max-moisture').value) } }; state.plots.push(newPlot); saveState(); renderAll(); plotForm.reset(); }); logForm.form.addEventListener('submit', (e) => { e.preventDefault(); const newLog = { id: Date.now(), timestamp: new Date(logForm.timestamp.value), plotId: parseInt(logForm.plot.value), soilMoisture: parseInt(logForm.moisture.value), temperature: parseInt(logForm.temp.value) }; state.sensorLog.push(newLog); saveState(); renderAll(); logForm.form.reset(); }); window.handleDelete = (stateKey, id) => { if(confirm(`Are you sure you want to delete this ${stateKey === 'plots' ? 'plot' : 'log entry'}?`)) { state[stateKey] = state[stateKey].filter(item => item.id !== id); saveState(); renderAll(); } }; window.gardenSwitchTab = (evt, tabName) => { document.querySelectorAll('#garden-dashboard-container .garden-tab-content').forEach(tc => tc.style.display = 'none'); document.querySelectorAll('#garden-dashboard-container .garden-tab-button').forEach(tl => tl.classList.remove('active')); document.getElementById(tabName).style.display = 'block'; if (tabName === 'data') renderAll(); // Rerender management tab when clicked }; // --- INITIALIZATION --- loadState(); renderAll(); });
    Scroll to Top