SLM config now sync to SLMM, SLMM caches configs for speed

This commit is contained in:
serversdwn
2026-01-07 18:33:58 +00:00
parent 6d34e543fe
commit c30d7fac22
12 changed files with 1893 additions and 124 deletions

View File

@@ -140,32 +140,73 @@
<canvas id="liveChart"></canvas>
</div>
<!-- Device Info -->
<div class="mt-4 grid grid-cols-2 gap-4 text-sm">
<div>
<span class="text-gray-600 dark:text-gray-400">Battery:</span>
<span class="font-medium text-gray-900 dark:text-white ml-2">
{% if current_status and current_status.battery_level %}{{ current_status.battery_level }}%{% else %}--{% endif %}
</span>
</div>
<div>
<span class="text-gray-600 dark:text-gray-400">Power:</span>
<span class="font-medium text-gray-900 dark:text-white ml-2">
{% if current_status and current_status.power_source %}{{ current_status.power_source }}{% else %}--{% endif %}
</span>
</div>
<div>
<span class="text-gray-600 dark:text-gray-400">Weighting:</span>
<span class="font-medium text-gray-900 dark:text-white ml-2">
{% if unit.slm_frequency_weighting %}{{ unit.slm_frequency_weighting }}{% else %}--{% endif %} /
{% if unit.slm_time_weighting %}{{ unit.slm_time_weighting }}{% else %}--{% endif %}
</span>
</div>
<div>
<span class="text-gray-600 dark:text-gray-400">SD Remaining:</span>
<span class="font-medium text-gray-900 dark:text-white ml-2">
{% if current_status and current_status.sd_remaining_mb %}{{ current_status.sd_remaining_mb }} MB{% else %}--{% endif %}
</span>
<!-- Device Status Cards -->
<div class="mt-6">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">Device Status</h3>
<div class="grid grid-cols-4 gap-4">
<!-- Battery Status -->
<div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between mb-2">
<span class="text-xs text-gray-600 dark:text-gray-400">Battery</span>
<svg class="w-4 h-4 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
<path d="M6 2a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V4a2 2 0 00-2-2H6zm0 2h8v12H6V4zm7 2a1 1 0 011 1v6a1 1 0 11-2 0V7a1 1 0 011-1z"/>
</svg>
</div>
<div id="battery-level" class="text-2xl font-bold text-gray-900 dark:text-white">
{% if current_status and current_status.battery_level %}{{ current_status.battery_level }}%{% else %}--{% endif %}
</div>
<div class="mt-2 bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div id="battery-bar" class="bg-green-500 h-2 rounded-full transition-all"
style="width: {% if current_status and current_status.battery_level %}{{ current_status.battery_level }}%{% else %}0%{% endif %}">
</div>
</div>
</div>
<!-- Power Source -->
<div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between mb-2">
<span class="text-xs text-gray-600 dark:text-gray-400">Power</span>
<svg class="w-4 h-4 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z" clip-rule="evenodd"/>
</svg>
</div>
<div id="power-source" class="text-lg font-semibold text-gray-900 dark:text-white">
{% if current_status and current_status.power_source %}{{ current_status.power_source }}{% else %}--{% endif %}
</div>
</div>
<!-- SD Card Space -->
<div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between mb-2">
<span class="text-xs text-gray-600 dark:text-gray-400">SD Card</span>
<svg class="w-4 h-4 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
<path d="M3 4a2 2 0 012-2h10a2 2 0 012 2v12a2 2 0 01-2 2H5a2 2 0 01-2-2V4zm2 0v12h10V4H5z"/>
</svg>
</div>
<div id="sd-remaining" class="text-lg font-semibold text-gray-900 dark:text-white">
{% if current_status and current_status.sd_remaining_mb %}{{ current_status.sd_remaining_mb }} MB{% else %}--{% endif %}
</div>
<div id="sd-ratio" class="text-xs text-gray-500 dark:text-gray-400">
{% if current_status and current_status.sd_free_ratio %}{{ current_status.sd_free_ratio }}% free{% else %}--{% endif %}
</div>
</div>
<!-- Last Update -->
<div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between mb-2">
<span class="text-xs text-gray-600 dark:text-gray-400">Last Update</span>
<svg class="w-4 h-4 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"/>
</svg>
</div>
<div id="last-update" class="text-xs font-medium text-gray-700 dark:text-gray-300">
Just now
</div>
<div id="auto-refresh-indicator" class="mt-2 flex items-center text-xs text-green-600 dark:text-green-400">
<span class="w-2 h-2 bg-green-500 rounded-full mr-1 animate-pulse"></span>
Auto-refresh: 30s
</div>
</div>
</div>
</div>
</div>
@@ -429,6 +470,94 @@ async function controlUnit(unitId, action) {
}
}
// Auto-refresh status every 30 seconds
let refreshInterval;
const REFRESH_INTERVAL_MS = 30000; // 30 seconds
const unit_id = '{{ unit.id }}';
function updateDeviceStatus() {
fetch(`/api/slmm/${unit_id}/live`)
.then(response => response.json())
.then(result => {
if (result.status === 'ok' && result.data) {
const data = result.data;
// Update battery
if (document.getElementById('battery-level')) {
const batteryLevel = data.battery_level || '--';
document.getElementById('battery-level').textContent = batteryLevel === '--' ? '--' : `${batteryLevel}%`;
// Update battery bar
const batteryBar = document.getElementById('battery-bar');
if (batteryBar && batteryLevel !== '--') {
const level = parseInt(batteryLevel);
batteryBar.style.width = `${level}%`;
// Color based on level
if (level > 50) {
batteryBar.className = 'bg-green-500 h-2 rounded-full transition-all';
} else if (level > 20) {
batteryBar.className = 'bg-yellow-500 h-2 rounded-full transition-all';
} else {
batteryBar.className = 'bg-red-500 h-2 rounded-full transition-all';
}
}
}
// Update power source
if (document.getElementById('power-source')) {
document.getElementById('power-source').textContent = data.power_source || '--';
}
// Update SD card info
if (document.getElementById('sd-remaining')) {
const sdRemaining = data.sd_remaining_mb || '--';
document.getElementById('sd-remaining').textContent = sdRemaining === '--' ? '--' : `${sdRemaining} MB`;
}
if (document.getElementById('sd-ratio')) {
const sdRatio = data.sd_free_ratio || '--';
document.getElementById('sd-ratio').textContent = sdRatio === '--' ? '--' : `${sdRatio}% free`;
}
// Update last update timestamp
if (document.getElementById('last-update')) {
const now = new Date();
document.getElementById('last-update').textContent = now.toLocaleTimeString();
}
}
})
.catch(error => {
console.error('Failed to refresh device status:', error);
// Update last update with error indicator
if (document.getElementById('last-update')) {
document.getElementById('last-update').textContent = 'Update failed';
}
});
}
// Start auto-refresh
function startAutoRefresh() {
// Initial update
updateDeviceStatus();
// Set up interval
refreshInterval = setInterval(updateDeviceStatus, REFRESH_INTERVAL_MS);
console.log('Auto-refresh started (30s interval)');
}
// Stop auto-refresh
function stopAutoRefresh() {
if (refreshInterval) {
clearInterval(refreshInterval);
refreshInterval = null;
console.log('Auto-refresh stopped');
}
}
// Start auto-refresh when page loads
document.addEventListener('DOMContentLoaded', startAutoRefresh);
// Cleanup on page unload
window.addEventListener('beforeunload', function() {
if (window.currentWebSocket) {