frontend-ota (#1)

Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2026-03-03 19:41:33 -05:00
parent 80114b1d9f
commit 9bce74e027
19 changed files with 843 additions and 75 deletions

View File

@@ -1,10 +1,12 @@
<script>
import { getSystemInfo, reboot } from "./lib/api.js";
import OTAUpdate from "./lib/OTAUpdate.svelte";
/** @type {'loading' | 'ok' | 'error' | 'rebooting'} */
let status = $state("loading");
let errorMsg = $state("");
let showRebootConfirm = $state(false);
let isRecovering = $state(false);
let systemInfo = $state({
chip: "—",
@@ -41,14 +43,17 @@
status = "ok";
errorMsg = "";
} catch (e) {
status = "error";
errorMsg = e.message || "Connection failed";
if (!isRecovering) {
status = "error";
errorMsg = e.message || "Connection failed";
}
}
}
async function handleReboot() {
showRebootConfirm = false;
status = "rebooting";
isRecovering = true;
try {
await reboot();
} catch (e) {
@@ -56,12 +61,27 @@
}
}
// Poll every 5 seconds
let pollInterval;
$effect(() => {
fetchInfo();
pollInterval = setInterval(fetchInfo, 5000);
return () => clearInterval(pollInterval);
});
// Resilient recovery polling: Only poll when we are waiting for a reboot
$effect(() => {
if (isRecovering) {
const interval = setInterval(async () => {
try {
const info = await getSystemInfo();
if (info) {
console.log("Device back online! Refreshing UI...");
window.location.reload();
}
} catch (e) {
// Still offline or rebooting, just keep waiting
console.log("Waiting for device...");
}
}, 2000);
return () => clearInterval(interval);
}
});
const infoItems = $derived([
@@ -77,8 +97,8 @@
<div class="w-full max-w-xl space-y-4">
<!-- Header -->
<div class="text-center mb-6">
<h1 class="text-2xl font-bold text-accent">Calendink Provider</h1>
<p class="text-text-secondary text-sm">ESP32-S3 System Dashboard</p>
<h1 class="text-2xl font-bold text-accent">Calendink Provider 🚀</h1>
<p class="text-text-secondary text-sm">ESP32-S3 System Dashboard v{__APP_VERSION__}</p>
</div>
<!-- Status Badge -->
@@ -146,11 +166,11 @@
</div>
</div>
<!-- Reboot Section -->
<!-- Device Control Section (Reboot) -->
<div class="bg-bg-card border border-border rounded-xl p-5">
<div class="flex items-center justify-between">
<div>
<h2 class="text-sm font-semibold text-text-primary">
<h2 class="text-sm font-semibold text-text-primary uppercase tracking-wider">
Device Control
</h2>
<p class="text-xs text-text-secondary mt-1">
@@ -170,6 +190,9 @@
</div>
</div>
<!-- Frontend Info & OTA Section -->
<OTAUpdate onReboot={() => (status = "rebooting")} />
<!-- Reboot Confirmation Modal -->
{#if showRebootConfirm}
<div
@@ -203,9 +226,5 @@
</div>
{/if}
<!-- Footer -->
<p class="text-center text-xs text-text-secondary/50 pt-2">
Auto-refreshes every 5s
</p>
</div>
</main>