Firmware update modal added
This commit is contained in:
parent
a326853d45
commit
f9c7ab2b50
8 changed files with 1020 additions and 2 deletions
|
|
@ -1,6 +1,12 @@
|
|||
import { useEffect } from "preact/hooks";
|
||||
import { $websocket } from "./WebSocketAtom";
|
||||
import { stateSetters } from "./AppProviderStore";
|
||||
import {
|
||||
stateSetters,
|
||||
LITTLEFS_VERSION,
|
||||
type UpdateInfo,
|
||||
type UpdateStatus,
|
||||
type UpdateTarget,
|
||||
} from "./AppProviderStore";
|
||||
import {
|
||||
$scanned_wifi_networks,
|
||||
$current_network_configuration,
|
||||
|
|
@ -11,6 +17,7 @@ import {
|
|||
authmodeToSecurity,
|
||||
ConnectionMode,
|
||||
} from "./NetworkManagerStore";
|
||||
import { send_webinterface_version } from "./ota_update_components/OtaCommands";
|
||||
|
||||
export { $websocket } from "./WebSocketAtom";
|
||||
|
||||
|
|
@ -113,6 +120,71 @@ function onOpen() {
|
|||
setTimeout(() => {
|
||||
request_network_config();
|
||||
}, 100);
|
||||
|
||||
// Inform the firmware which webinterface version this bundle was built with.
|
||||
// The firmware uses this as update_info_s3_webinterface.currentVersion for the
|
||||
// OTA check, so independent FS-only updates work correctly. See
|
||||
// set_webinterface_version handler in websocket_server.cpp.
|
||||
setTimeout(() => {
|
||||
console.log("[OTA] sending LITTLEFS_VERSION=", LITTLEFS_VERSION);
|
||||
send_webinterface_version(LITTLEFS_VERSION);
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// Map FW status strings (target_update_status_t -> getStatusString in
|
||||
// update_notifier.cpp) to the web app's UpdateStatus union.
|
||||
function mapStatus(s: string | undefined): UpdateStatus {
|
||||
switch (s) {
|
||||
case "no_update":
|
||||
case "started":
|
||||
case "in_progress":
|
||||
case "completed":
|
||||
case "error":
|
||||
case "restarting":
|
||||
case "waiting":
|
||||
return s;
|
||||
default:
|
||||
console.warn("[OTA] unknown status string from FW:", s);
|
||||
return "no_update";
|
||||
}
|
||||
}
|
||||
|
||||
function isUpdateTarget(s: string | undefined): s is UpdateTarget {
|
||||
return s === "s3_firmware" || s === "s3_webinterface";
|
||||
}
|
||||
|
||||
// Translate an `update_progress` frame into atom updates + drive the modal
|
||||
// state machine. Called from onMessage.
|
||||
function handleUpdateProgress(target: UpdateTarget, progress: number, status: UpdateStatus, errorMsg?: string) {
|
||||
console.log(`[OTA] progress: target=${target} progress=${progress} status=${status}`,
|
||||
errorMsg ? `error=${errorMsg}` : "");
|
||||
if (target === "s3_firmware") {
|
||||
stateSetters.setS3FirmwareProgress(progress, status);
|
||||
} else {
|
||||
stateSetters.setS3WebinterfaceProgress(progress, status);
|
||||
}
|
||||
if (status === "error") {
|
||||
if (errorMsg) stateSetters.setUpdateErrorFor(target, errorMsg);
|
||||
stateSetters.setUpdateState("error");
|
||||
} else if (status === "restarting") {
|
||||
stateSetters.setUpdateState("restarting");
|
||||
} else if (status === "started" || status === "in_progress") {
|
||||
stateSetters.setUpdateState("updating");
|
||||
} else if (status === "completed") {
|
||||
// Completion of one target doesn't necessarily mean the whole sequence is
|
||||
// done — the firmware sends per-target completed frames and a final
|
||||
// restart frame when the firmware part lands. We let device_restarting /
|
||||
// a separate aggregate trigger flip to 'success'.
|
||||
if (target === "s3_firmware") {
|
||||
// FW always restarts after its own update → next frame will be
|
||||
// device_restarting. Mark as restarting now so the success popup picks
|
||||
// up the right copy.
|
||||
stateSetters.setUpdateState("restarting");
|
||||
} else {
|
||||
// Web-only successful update: no restart, switch straight to success.
|
||||
stateSetters.setUpdateState("success");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onMessage(message: MessageEvent) {
|
||||
|
|
@ -181,6 +253,52 @@ function onMessage(message: MessageEvent) {
|
|||
$network_config_error.set({ reason, failed_ssid: failedSsid, connection_mode: connectionMode });
|
||||
} else if (dataFromServer.message_type === "error_popup") {
|
||||
console.warn(`[error_popup] ${dataFromServer.error ?? dataFromServer.message ?? "(no detail)"}`);
|
||||
} else if (dataFromServer.message_type === "update_information") {
|
||||
// Server-side response to FIRMWARE_UPDATE_CMD_REQUEST_AVAILABLE_UPDATES.
|
||||
// Shape: { update_available: { s3_firmware?: {...}, s3_webinterface?: {...} }, changelog }
|
||||
console.log("[OTA] update_information received", dataFromServer);
|
||||
const ua = dataFromServer.update_available ?? {};
|
||||
const updates: UpdateInfo[] = [
|
||||
{
|
||||
target: "s3_webinterface",
|
||||
label: "Webinterface",
|
||||
currentVersion: ua.s3_webinterface?.current_version ?? LITTLEFS_VERSION,
|
||||
newVersion: ua.s3_webinterface?.new_version ?? "",
|
||||
updateAvailable: !!ua.s3_webinterface?.updateAvailable,
|
||||
},
|
||||
{
|
||||
target: "s3_firmware",
|
||||
label: "S3 Firmware",
|
||||
currentVersion: ua.s3_firmware?.current_version ?? "",
|
||||
newVersion: ua.s3_firmware?.new_version ?? "",
|
||||
updateAvailable: !!ua.s3_firmware?.updateAvailable,
|
||||
},
|
||||
];
|
||||
stateSetters.setAvailableUpdates(updates);
|
||||
stateSetters.setUpdateChangelog(dataFromServer.changelog ?? "");
|
||||
if (updates.some((u) => u.updateAvailable)) {
|
||||
console.log("[OTA] updates available — opening UpdaterModal");
|
||||
stateSetters.setUpdaterModalOpen(true);
|
||||
} else {
|
||||
console.log("[OTA] no updates available");
|
||||
}
|
||||
} else if (dataFromServer.message_type === "update_progress") {
|
||||
if (!isUpdateTarget(dataFromServer.target)) {
|
||||
console.warn("[OTA] update_progress with unknown target:", dataFromServer.target);
|
||||
} else {
|
||||
handleUpdateProgress(
|
||||
dataFromServer.target,
|
||||
Number(dataFromServer.progress ?? 0),
|
||||
mapStatus(dataFromServer.status),
|
||||
dataFromServer.error,
|
||||
);
|
||||
}
|
||||
} else if (dataFromServer.message_type === "update_in_progress") {
|
||||
console.log("[OTA] update_in_progress=", dataFromServer.in_progress, "target=", dataFromServer.target);
|
||||
stateSetters.setUpdateInProgress(!!dataFromServer.in_progress);
|
||||
} else if (dataFromServer.message_type === "device_restarting") {
|
||||
console.log("[OTA] device_restarting received — FW is rebooting");
|
||||
stateSetters.setUpdateState("restarting");
|
||||
} else {
|
||||
// Unbekannter Nachrichtentyp - korrektes Feld protokollieren
|
||||
console.warn(`[${new Date().toISOString()}] Unbekannter Nachrichtentyp: ${dataFromServer.message_type ?? "undefined"}`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue