update model
This commit is contained in:
+183
-67
@@ -2549,7 +2549,14 @@ function updateSeatTwin(actuatorState) {
|
||||
}
|
||||
|
||||
const REFERENCE_VEHICLE_ROOT = "/assets/models/byd-tang/";
|
||||
const REFERENCE_VEHICLE_URL = `${REFERENCE_VEHICLE_ROOT}byd-tang-2024.fbx`;
|
||||
const REFERENCE_VEHICLE_ASSET_VERSION = "77a0fae7";
|
||||
const REFERENCE_VEHICLE_LOAD_TIMEOUT_MS = 30000;
|
||||
|
||||
function referenceVehicleAssetUrl(fileName) {
|
||||
return `${REFERENCE_VEHICLE_ROOT}${encodeURIComponent(fileName)}?v=${REFERENCE_VEHICLE_ASSET_VERSION}`;
|
||||
}
|
||||
|
||||
const REFERENCE_VEHICLE_URL = referenceVehicleAssetUrl("byd-tang-2024.fbx");
|
||||
|
||||
function referenceMaterialDescriptor(material) {
|
||||
const textureNames = [
|
||||
@@ -3643,73 +3650,92 @@ function loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback) {
|
||||
reject(new Error("FBXLoader is unavailable"));
|
||||
return;
|
||||
}
|
||||
let settled = false;
|
||||
const settle = (callback, value) => {
|
||||
if (settled) return false;
|
||||
settled = true;
|
||||
window.clearTimeout(timeoutId);
|
||||
callback(value);
|
||||
return true;
|
||||
};
|
||||
const timeoutId = window.setTimeout(() => {
|
||||
settle(
|
||||
reject,
|
||||
new Error(`Reference vehicle load timed out after ${REFERENCE_VEHICLE_LOAD_TIMEOUT_MS} ms`),
|
||||
);
|
||||
}, REFERENCE_VEHICLE_LOAD_TIMEOUT_MS);
|
||||
const manager = new THREE.LoadingManager();
|
||||
manager.setURLModifier((url) => {
|
||||
const cleanUrl = String(url).replaceAll("\\", "/");
|
||||
const cleanUrl = String(url).replaceAll("\\", "/").split(/[?#]/, 1)[0];
|
||||
const fileName = decodeURIComponent(cleanUrl.split("/").pop() || "");
|
||||
if (!/\.(png|jpe?g)$/i.test(fileName)) return url;
|
||||
return `${REFERENCE_VEHICLE_ROOT}${encodeURIComponent(fileName)}`;
|
||||
return referenceVehicleAssetUrl(fileName);
|
||||
});
|
||||
const loader = new FBXLoaderClass(manager);
|
||||
loader.setResourcePath(REFERENCE_VEHICLE_ROOT);
|
||||
loader.load(
|
||||
REFERENCE_VEHICLE_URL,
|
||||
(vehicle) => {
|
||||
const normalized = normalizeReferenceVehicle(THREE, vehicle);
|
||||
const driverCushion = measureReferenceDriverCushion(THREE, vehicle);
|
||||
const passengerCushion = measureReferencePassengerCushion(THREE, vehicle);
|
||||
const removedFrontSeatTriangles = carveReferenceFrontSeats(THREE, vehicle);
|
||||
const referenceWindowPanes = extractReferenceWindowPanes(THREE, vehicle);
|
||||
const report = configureReferenceVehicleModel(THREE, vehicle);
|
||||
styleReferencePassiveGlass(THREE, vehicle);
|
||||
const passiveRearExterior = styleReferencePassiveRearExterior(THREE, vehicle);
|
||||
const referenceFrontLampMeshes = collectReferenceFrontLampMeshes(vehicle);
|
||||
emphasizeReferenceWindowPanes(THREE, referenceWindowPanes);
|
||||
const referenceFrontLampMaterials = emphasizeReferenceFrontLampMeshes(
|
||||
THREE,
|
||||
referenceFrontLampMeshes,
|
||||
);
|
||||
const referenceFrontLampHighlights = createReferenceFrontLampHighlights(
|
||||
THREE,
|
||||
referenceFrontLampMeshes,
|
||||
);
|
||||
const referenceFrontLampLensOutlines = createReferenceFrontLampLensOutlines(
|
||||
THREE,
|
||||
vehicle,
|
||||
);
|
||||
vehicleSystems.referenceWindowPanes = referenceWindowPanes;
|
||||
vehicleSystems.referenceFrontLampMaterials = referenceFrontLampMaterials;
|
||||
vehicleSystems.referenceFrontLampMeshes = referenceFrontLampMeshes;
|
||||
vehicleSystems.referenceFrontLampHighlights = referenceFrontLampHighlights;
|
||||
vehicleSystems.referenceFrontLampLensOutlines = referenceFrontLampLensOutlines;
|
||||
applyTwinVehicleTheme(vehicleSystems);
|
||||
vehicle.name = "REFERENCE_VEHICLE_OUTLINE";
|
||||
vehicle.userData.twinRole = "reference_vehicle";
|
||||
vehicle.traverse((object) => object.layers.set(1));
|
||||
scene.add(vehicle);
|
||||
vehicleSystems.fallbackExteriorObjects.forEach((object) => {
|
||||
object.visible = false;
|
||||
});
|
||||
vehicleSystems.fallbackInteriorObjects.forEach((object) => {
|
||||
object.visible = false;
|
||||
});
|
||||
console.info("[vehicle-twin] reference vehicle model loaded", JSON.stringify({
|
||||
meshes: report.meshes,
|
||||
size: normalized.size.toArray().map((value) => Number(value.toFixed(3))),
|
||||
removedFrontSeatTriangles,
|
||||
windowPanes: Object.fromEntries(
|
||||
Object.entries(referenceWindowPanes).map(([key, value]) => [key, value.length]),
|
||||
),
|
||||
frontLampMaterials: referenceFrontLampMaterials.length,
|
||||
frontLampMeshes: referenceFrontLampMeshes.length,
|
||||
frontLampHighlights: referenceFrontLampHighlights.length,
|
||||
frontLampLensOutlines: referenceFrontLampLensOutlines.length,
|
||||
rearLampMeshes: passiveRearExterior.rearLampMeshes.length,
|
||||
rearBumperMeshes: passiveRearExterior.rearBumperMeshes.length,
|
||||
driverCushion,
|
||||
passengerCushion,
|
||||
}));
|
||||
resolve({ vehicle, report, normalized, driverCushion, passengerCushion });
|
||||
if (settled) return;
|
||||
try {
|
||||
const normalized = normalizeReferenceVehicle(THREE, vehicle);
|
||||
const driverCushion = measureReferenceDriverCushion(THREE, vehicle);
|
||||
const passengerCushion = measureReferencePassengerCushion(THREE, vehicle);
|
||||
const removedFrontSeatTriangles = carveReferenceFrontSeats(THREE, vehicle);
|
||||
const referenceWindowPanes = extractReferenceWindowPanes(THREE, vehicle);
|
||||
const report = configureReferenceVehicleModel(THREE, vehicle);
|
||||
styleReferencePassiveGlass(THREE, vehicle);
|
||||
const passiveRearExterior = styleReferencePassiveRearExterior(THREE, vehicle);
|
||||
const referenceFrontLampMeshes = collectReferenceFrontLampMeshes(vehicle);
|
||||
emphasizeReferenceWindowPanes(THREE, referenceWindowPanes);
|
||||
const referenceFrontLampMaterials = emphasizeReferenceFrontLampMeshes(
|
||||
THREE,
|
||||
referenceFrontLampMeshes,
|
||||
);
|
||||
const referenceFrontLampHighlights = createReferenceFrontLampHighlights(
|
||||
THREE,
|
||||
referenceFrontLampMeshes,
|
||||
);
|
||||
const referenceFrontLampLensOutlines = createReferenceFrontLampLensOutlines(
|
||||
THREE,
|
||||
vehicle,
|
||||
);
|
||||
vehicleSystems.referenceWindowPanes = referenceWindowPanes;
|
||||
vehicleSystems.referenceFrontLampMaterials = referenceFrontLampMaterials;
|
||||
vehicleSystems.referenceFrontLampMeshes = referenceFrontLampMeshes;
|
||||
vehicleSystems.referenceFrontLampHighlights = referenceFrontLampHighlights;
|
||||
vehicleSystems.referenceFrontLampLensOutlines = referenceFrontLampLensOutlines;
|
||||
applyTwinVehicleTheme(vehicleSystems);
|
||||
vehicle.name = "REFERENCE_VEHICLE_OUTLINE";
|
||||
vehicle.userData.twinRole = "reference_vehicle";
|
||||
vehicle.traverse((object) => object.layers.set(1));
|
||||
scene.add(vehicle);
|
||||
vehicleSystems.fallbackExteriorObjects.forEach((object) => {
|
||||
object.visible = false;
|
||||
});
|
||||
vehicleSystems.fallbackInteriorObjects.forEach((object) => {
|
||||
object.visible = false;
|
||||
});
|
||||
console.info("[vehicle-twin] reference vehicle model loaded", JSON.stringify({
|
||||
meshes: report.meshes,
|
||||
size: normalized.size.toArray().map((value) => Number(value.toFixed(3))),
|
||||
removedFrontSeatTriangles,
|
||||
windowPanes: Object.fromEntries(
|
||||
Object.entries(referenceWindowPanes).map(([key, value]) => [key, value.length]),
|
||||
),
|
||||
frontLampMaterials: referenceFrontLampMaterials.length,
|
||||
frontLampMeshes: referenceFrontLampMeshes.length,
|
||||
frontLampHighlights: referenceFrontLampHighlights.length,
|
||||
frontLampLensOutlines: referenceFrontLampLensOutlines.length,
|
||||
rearLampMeshes: passiveRearExterior.rearLampMeshes.length,
|
||||
rearBumperMeshes: passiveRearExterior.rearBumperMeshes.length,
|
||||
driverCushion,
|
||||
passengerCushion,
|
||||
}));
|
||||
settle(resolve, { vehicle, report, normalized, driverCushion, passengerCushion });
|
||||
} catch (error) {
|
||||
settle(reject, error);
|
||||
}
|
||||
},
|
||||
(event) => {
|
||||
if (!fallback || !event.total) return;
|
||||
@@ -3717,7 +3743,7 @@ function loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback) {
|
||||
const label = fallback.querySelector("span");
|
||||
if (label) label.textContent = `正在加载整车参考模型 · ${progress}%`;
|
||||
},
|
||||
reject,
|
||||
(error) => settle(reject, error),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -3726,7 +3752,33 @@ function initSeatTwin() {
|
||||
const canvas = $("#seatTwinCanvas");
|
||||
const stage = $("#seatTwin");
|
||||
const fallback = $("#twinFallback");
|
||||
if (!canvas || !stage) return;
|
||||
if (!canvas || !stage || state.seatTwin) return;
|
||||
const stageHasLayout = () => {
|
||||
const bounds = stage.getBoundingClientRect();
|
||||
return stage.isConnected && bounds.width >= 2 && bounds.height >= 2;
|
||||
};
|
||||
if (!stageHasLayout()) {
|
||||
if (stage.dataset.twinInitPending === "true") return;
|
||||
stage.dataset.twinInitPending = "true";
|
||||
let pendingObserver = null;
|
||||
const retryInitialization = () => {
|
||||
if (!stageHasLayout()) return;
|
||||
pendingObserver?.disconnect();
|
||||
window.removeEventListener("resize", scheduleRetry);
|
||||
window.removeEventListener("cognitive-agent:module-change", scheduleRetry);
|
||||
delete stage.dataset.twinInitPending;
|
||||
initSeatTwin();
|
||||
};
|
||||
const scheduleRetry = () => window.requestAnimationFrame(retryInitialization);
|
||||
if (window.ResizeObserver) {
|
||||
pendingObserver = new ResizeObserver(retryInitialization);
|
||||
pendingObserver.observe(stage);
|
||||
}
|
||||
window.addEventListener("resize", scheduleRetry);
|
||||
window.addEventListener("cognitive-agent:module-change", scheduleRetry);
|
||||
scheduleRetry();
|
||||
return;
|
||||
}
|
||||
if (!window.THREE) {
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>3D 引擎加载失败,精确状态仍可用</span>';
|
||||
@@ -3735,7 +3787,16 @@ function initSeatTwin() {
|
||||
}
|
||||
|
||||
const THREE = window.THREE;
|
||||
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, powerPreference: "high-performance" });
|
||||
let renderer;
|
||||
try {
|
||||
renderer = new THREE.WebGLRenderer({ canvas, antialias: true, powerPreference: "high-performance" });
|
||||
} catch (error) {
|
||||
console.error("[vehicle-twin] failed to initialize WebGL", error);
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>3D 渲染器初始化失败,状态数据仍可用</span>';
|
||||
refreshIcons();
|
||||
return;
|
||||
}
|
||||
renderer.autoClear = false;
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
|
||||
if ("outputColorSpace" in renderer) renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
@@ -3883,6 +3944,7 @@ function initSeatTwin() {
|
||||
applyTwinSceneTheme(state.seatTwin);
|
||||
});
|
||||
|
||||
canvas.dataset.referenceModelState = "loading";
|
||||
loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback)
|
||||
.then(({ vehicle, report, normalized, driverCushion, passengerCushion }) => {
|
||||
if (!state.seatTwin) return;
|
||||
@@ -3920,11 +3982,12 @@ function initSeatTwin() {
|
||||
.toArray()
|
||||
.map((value) => value.toFixed(2))
|
||||
.join("x");
|
||||
canvas.dataset.referenceModelLoaded = "true";
|
||||
canvas.dataset.referenceModelState = "loaded";
|
||||
fallback.hidden = true;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("[vehicle-twin] failed to load reference vehicle model", error);
|
||||
canvas.dataset.referenceModelState = "failed";
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>实车模型加载失败,已切换轻量回退模型</span>';
|
||||
refreshIcons();
|
||||
@@ -3940,17 +4003,64 @@ function initSeatTwin() {
|
||||
});
|
||||
}
|
||||
|
||||
let stageWasVisible = false;
|
||||
function resize() {
|
||||
const width = Math.max(1, canvas.clientWidth);
|
||||
const height = Math.max(1, canvas.clientHeight);
|
||||
const width = Math.max(1, Math.round(stage.clientWidth));
|
||||
const height = Math.max(1, Math.round(stage.clientHeight));
|
||||
renderer.setSize(width, height, false);
|
||||
camera.aspect = width / height;
|
||||
camera.updateProjectionMatrix();
|
||||
state.seatTwin.narrowViewport = width < 600;
|
||||
}
|
||||
|
||||
new ResizeObserver(resize).observe(stage);
|
||||
resize();
|
||||
function synchronizeTwinViewport({ reset = false } = {}) {
|
||||
if (!stageHasLayout()) {
|
||||
stageWasVisible = false;
|
||||
return false;
|
||||
}
|
||||
resize();
|
||||
if (reset || !stageWasVisible) resetView();
|
||||
stageWasVisible = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const scheduleViewportSync = () => {
|
||||
window.requestAnimationFrame(() => window.requestAnimationFrame(() => {
|
||||
synchronizeTwinViewport();
|
||||
}));
|
||||
};
|
||||
if (window.ResizeObserver) {
|
||||
const stageObserver = new ResizeObserver(() => synchronizeTwinViewport());
|
||||
stageObserver.observe(stage);
|
||||
state.seatTwin.resizeObserver = stageObserver;
|
||||
}
|
||||
window.addEventListener("resize", scheduleViewportSync);
|
||||
window.addEventListener("cognitive-agent:module-change", scheduleViewportSync);
|
||||
canvas.addEventListener("webglcontextlost", (event) => {
|
||||
event.preventDefault();
|
||||
canvas.dataset.contextLost = "true";
|
||||
fallback.hidden = false;
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>3D 上下文已中断,正在等待恢复</span>';
|
||||
refreshIcons();
|
||||
});
|
||||
canvas.addEventListener("webglcontextrestored", () => {
|
||||
delete canvas.dataset.contextLost;
|
||||
synchronizeTwinViewport({ reset: true });
|
||||
const modelState = canvas.dataset.referenceModelState;
|
||||
fallback.hidden = modelState === "loaded";
|
||||
if (modelState === "loading") {
|
||||
fallback.classList.remove("error");
|
||||
fallback.innerHTML = '<i data-lucide="loader-circle"></i><span>正在加载整车参考模型</span>';
|
||||
refreshIcons();
|
||||
} else if (modelState === "failed") {
|
||||
fallback.classList.add("error");
|
||||
fallback.innerHTML = '<i data-lucide="triangle-alert"></i><span>实车模型加载失败,已切换轻量回退模型</span>';
|
||||
refreshIcons();
|
||||
window.setTimeout(() => { fallback.hidden = true; }, 3200);
|
||||
}
|
||||
});
|
||||
synchronizeTwinViewport({ reset: true });
|
||||
stage.addEventListener("pointerdown", (event) => {
|
||||
state.seatTwin.dragging = true;
|
||||
state.seatTwin.pointer = { x: event.clientX, y: event.clientY };
|
||||
@@ -4052,6 +4162,12 @@ function initSeatTwin() {
|
||||
function animate(timestamp = 0) {
|
||||
const twin = state.seatTwin;
|
||||
if (!twin) return;
|
||||
if (!stageHasLayout() || canvas.dataset.contextLost === "true") {
|
||||
stageWasVisible = false;
|
||||
window.requestAnimationFrame(animate);
|
||||
return;
|
||||
}
|
||||
if (!stageWasVisible) synchronizeTwinViewport({ reset: true });
|
||||
Object.values(twin.models).forEach((model) => {
|
||||
Object.keys(model.positions).forEach((axis) => {
|
||||
const delta = model.targets[axis] - model.positions[axis];
|
||||
@@ -6556,7 +6672,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
initJointTwinLayout();
|
||||
initResultWorkspace();
|
||||
refreshIcons();
|
||||
initSeatTwin();
|
||||
window.requestAnimationFrame(initSeatTwin);
|
||||
$("#requestForm").addEventListener("submit", submitRequest);
|
||||
$("#utterance").addEventListener("keydown", (event) => {
|
||||
if (event.key === "Enter" && !event.shiftKey && !event.isComposing) {
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
<script src="/vendor/three/0.147.0/fflate.min.js" defer></script>
|
||||
<script src="/vendor/three/0.147.0/FBXLoader.js" defer></script>
|
||||
<script src="/network.js?v=android-pad-1" defer></script>
|
||||
<script src="/app.js?v=dual-seat-80" defer></script>
|
||||
<script src="/app.js?v=dual-seat-81" defer></script>
|
||||
<script type="module" src="/gesture-control.js?v=android-pad-7"></script>
|
||||
<script src="/pwa.js?v=android-pad-1" defer></script>
|
||||
<script src="/console-v2.js?v=desktop-refactor-35" defer></script>
|
||||
<script src="/self-extension.js?v=extension-20" defer></script>
|
||||
<script src="/self-calibration.js?v=calibration-6" defer></script>
|
||||
<script src="/self-repair.js?v=repair-20" defer></script>
|
||||
<script src="/self-repair-seat3d.js?v=repair-18" defer></script>
|
||||
<script src="/self-repair-seat3d.js?v=repair-19" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
|
||||
@@ -1,6 +1,33 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function viewerHasLayout(viewer) {
|
||||
const bounds = viewer.getBoundingClientRect();
|
||||
return viewer.isConnected && bounds.width >= 2 && bounds.height >= 2;
|
||||
}
|
||||
|
||||
function deferSeat3dUntilVisible(viewer, options) {
|
||||
if (viewer.dataset.seat3dPending === "true") return;
|
||||
viewer.dataset.seat3dPending = "true";
|
||||
let observer = null;
|
||||
const retry = () => {
|
||||
if (!viewerHasLayout(viewer)) return;
|
||||
observer?.disconnect();
|
||||
window.removeEventListener("resize", scheduleRetry);
|
||||
window.removeEventListener("cognitive-agent:module-change", scheduleRetry);
|
||||
delete viewer.dataset.seat3dPending;
|
||||
initSeat3d(options);
|
||||
};
|
||||
const scheduleRetry = () => window.requestAnimationFrame(retry);
|
||||
if (window.ResizeObserver) {
|
||||
observer = new ResizeObserver(retry);
|
||||
observer.observe(viewer);
|
||||
}
|
||||
window.addEventListener("resize", scheduleRetry);
|
||||
window.addEventListener("cognitive-agent:module-change", scheduleRetry);
|
||||
scheduleRetry();
|
||||
}
|
||||
|
||||
function initSeat3d(options) {
|
||||
const {
|
||||
canvasId,
|
||||
@@ -15,6 +42,10 @@
|
||||
const canvas = document.getElementById(canvasId);
|
||||
const viewer = document.getElementById(viewerId);
|
||||
if (!canvas || !viewer || viewer.dataset.seat3dInitialized === "true") return;
|
||||
if (!viewerHasLayout(viewer)) {
|
||||
deferSeat3dUntilVisible(viewer, options);
|
||||
return;
|
||||
}
|
||||
viewer.dataset.seat3dInitialized = "true";
|
||||
|
||||
const markReady = (fallback = false) => {
|
||||
@@ -387,6 +418,24 @@
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
let viewerWasVisible = false;
|
||||
function synchronizeViewport({ reset = false } = {}) {
|
||||
if (!viewerHasLayout(viewer)) {
|
||||
viewerWasVisible = false;
|
||||
return false;
|
||||
}
|
||||
resize();
|
||||
if (reset || !viewerWasVisible) resetOrbit();
|
||||
viewerWasVisible = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const scheduleViewportSync = () => {
|
||||
window.requestAnimationFrame(() => window.requestAnimationFrame(() => {
|
||||
synchronizeViewport();
|
||||
}));
|
||||
};
|
||||
|
||||
function onHealingState(event) {
|
||||
const detail = event.detail || {};
|
||||
(detail.axes || []).forEach((axis) => {
|
||||
@@ -404,6 +453,11 @@
|
||||
|
||||
function animate() {
|
||||
window.requestAnimationFrame(animate);
|
||||
if (!viewerHasLayout(viewer) || canvas.dataset.contextLost === "true") {
|
||||
viewerWasVisible = false;
|
||||
return;
|
||||
}
|
||||
if (!viewerWasVisible) synchronizeViewport({ reset: true });
|
||||
for (let index = 0; index < current.axes.length; index += 1) {
|
||||
current.axes[index] += (desired.axes[index] - current.axes[index]) * 0.055;
|
||||
}
|
||||
@@ -486,10 +540,23 @@
|
||||
window.addEventListener(stateEvent, onHealingState);
|
||||
window.addEventListener(resetEvent, resetOrbit);
|
||||
|
||||
if (window.ResizeObserver) new ResizeObserver(resize).observe(viewer);
|
||||
window.addEventListener("resize", resize);
|
||||
resize();
|
||||
resetOrbit();
|
||||
if (window.ResizeObserver) {
|
||||
const resizeObserver = new ResizeObserver(() => synchronizeViewport());
|
||||
resizeObserver.observe(viewer);
|
||||
}
|
||||
window.addEventListener("resize", scheduleViewportSync);
|
||||
window.addEventListener("cognitive-agent:module-change", scheduleViewportSync);
|
||||
canvas.addEventListener("webglcontextlost", (event) => {
|
||||
event.preventDefault();
|
||||
canvas.dataset.contextLost = "true";
|
||||
viewer.classList.add("context-lost");
|
||||
});
|
||||
canvas.addEventListener("webglcontextrestored", () => {
|
||||
delete canvas.dataset.contextLost;
|
||||
viewer.classList.remove("context-lost");
|
||||
synchronizeViewport({ reset: true });
|
||||
});
|
||||
synchronizeViewport({ reset: true });
|
||||
animate();
|
||||
window.requestAnimationFrame(() => markReady());
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v116";
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v117";
|
||||
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
||||
const RUNTIME_CACHE = `${CACHE_VERSION}-runtime`;
|
||||
const APP_SHELL = [
|
||||
@@ -6,7 +6,7 @@ const APP_SHELL = [
|
||||
"/index.html",
|
||||
"/styles.css?v=dual-seat-9",
|
||||
"/network.js?v=android-pad-1",
|
||||
"/app.js?v=dual-seat-80",
|
||||
"/app.js?v=dual-seat-81",
|
||||
"/gesture-control.js?v=android-pad-7",
|
||||
"/pwa.js?v=android-pad-1",
|
||||
"/console-v2.css?v=desktop-refactor-106",
|
||||
@@ -17,8 +17,8 @@ const APP_SHELL = [
|
||||
"/self-calibration.js?v=calibration-6",
|
||||
"/self-repair.css?v=repair-21",
|
||||
"/self-repair.js?v=repair-20",
|
||||
"/self-repair-seat3d.js?v=repair-18",
|
||||
"/assets/models/n7_seat.glb",
|
||||
"/self-repair-seat3d.js?v=repair-19",
|
||||
"/assets/models/n7_seat.glb?v=e7f50f03",
|
||||
"/manifest.webmanifest",
|
||||
"/icons/app-icon-192.png",
|
||||
"/icons/app-icon-512.png",
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
9136
|
||||
@@ -1,61 +0,0 @@
|
||||
id: k-c78dff
|
||||
name: K歌模式
|
||||
aliases:
|
||||
- K歌模式
|
||||
- K歌
|
||||
description: 用户固化的长期模式配置。
|
||||
icon: bookmark
|
||||
scope:
|
||||
vehicle_ids:
|
||||
- denza_n7
|
||||
operations:
|
||||
- domain: ambient_light
|
||||
capability: ambient_light.set_power
|
||||
target_scope: vehicle
|
||||
operation: activate
|
||||
parameters:
|
||||
state: 'on'
|
||||
reason: 开启氛围灯以营造K歌场景。
|
||||
- domain: ambient_light
|
||||
capability: ambient_light.set_illumination
|
||||
target_scope: vehicle
|
||||
operation: set
|
||||
parameters:
|
||||
color_hex: '#B84DFF'
|
||||
brightness_pct: 65
|
||||
reason: 使用明快紫色和中高亮度营造活跃舞台氛围。
|
||||
- domain: climate
|
||||
capability: climate.set_power
|
||||
target_scope: vehicle
|
||||
operation: activate
|
||||
parameters:
|
||||
state: 'on'
|
||||
reason: 空调当前关闭,需先开启以维持K歌时的座舱舒适度。
|
||||
- domain: climate
|
||||
capability: climate.set_temperature
|
||||
target_scope: driver
|
||||
operation: set
|
||||
parameters:
|
||||
temperature_c: 24
|
||||
reason: 采用舒适且保守的座舱温度。
|
||||
- domain: climate
|
||||
capability: climate.set_fan_level
|
||||
target_scope: vehicle
|
||||
operation: set
|
||||
parameters:
|
||||
level: 2
|
||||
reason: 采用低风量,兼顾通风并减少对歌声的干扰。
|
||||
- domain: climate
|
||||
capability: climate.set_ac
|
||||
target_scope: vehicle
|
||||
operation: activate
|
||||
parameters:
|
||||
state: 'on'
|
||||
reason: 启用制冷除湿以维持多人演唱时的舒适度。
|
||||
- domain: climate
|
||||
capability: climate.set_cycle_mode
|
||||
target_scope: vehicle
|
||||
operation: set
|
||||
parameters:
|
||||
mode: internal
|
||||
reason: 采用内循环以稳定座舱温度并减少外部噪声和气味。
|
||||
@@ -0,0 +1,46 @@
|
||||
id: mode-ceff921663
|
||||
name: 躺平模式
|
||||
aliases:
|
||||
- 躺平模式
|
||||
- 躺平
|
||||
description: 用户固化的长期模式配置。
|
||||
icon: bookmark
|
||||
scope:
|
||||
vehicle_ids:
|
||||
- denza_n7
|
||||
operations:
|
||||
- domain: seat
|
||||
capability: seat.set_longitudinal_position
|
||||
target_scope: passenger
|
||||
operation: set
|
||||
parameters:
|
||||
position_pct: 90
|
||||
reason: 用户固化的座椅位置模式动作。
|
||||
- domain: seat
|
||||
capability: seat.set_cushion_tilt
|
||||
target_scope: passenger
|
||||
operation: set
|
||||
parameters:
|
||||
position_pct: 40
|
||||
reason: 用户固化的座椅位置模式动作。
|
||||
- domain: seat
|
||||
capability: seat.set_backrest_recline
|
||||
target_scope: passenger
|
||||
operation: set
|
||||
parameters:
|
||||
position_pct: 80
|
||||
reason: 用户固化的座椅位置模式动作。
|
||||
- domain: seat
|
||||
capability: seat.set_legrest_height
|
||||
target_scope: passenger
|
||||
operation: set
|
||||
parameters:
|
||||
position_pct: 75
|
||||
reason: 用户固化的座椅位置模式动作。
|
||||
- domain: seat
|
||||
capability: seat.set_legrest_extension
|
||||
target_scope: passenger
|
||||
operation: set
|
||||
parameters:
|
||||
position_pct: 80
|
||||
reason: 用户固化的座椅位置模式动作。
|
||||
@@ -243,7 +243,7 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
if path.startswith("/api/requests/"):
|
||||
self._serve_request(path.removeprefix("/api/requests/"))
|
||||
return
|
||||
self._serve_static(path)
|
||||
self._serve_static(path, parsed_url.query)
|
||||
|
||||
def do_POST(self) -> None: # noqa: N802 - stdlib handler API
|
||||
path = unquote(urlparse(self.path).path)
|
||||
@@ -942,17 +942,24 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
return
|
||||
self._json(json.loads(result_path.read_text(encoding="utf-8")))
|
||||
|
||||
def _serve_static(self, path: str) -> None:
|
||||
def _serve_static(self, path: str, query: str = "") -> None:
|
||||
relative_path = "index.html" if path in {"", "/"} else path.lstrip("/")
|
||||
self._serve_static_file(relative_path)
|
||||
versioned = bool(parse_qs(query).get("v"))
|
||||
self._serve_static_file(relative_path, versioned=versioned)
|
||||
|
||||
def _serve_static_file(self, relative_path: str) -> None:
|
||||
def _serve_static_file(self, relative_path: str, *, versioned: bool = False) -> None:
|
||||
candidate = (STATIC_ROOT / relative_path).resolve()
|
||||
try:
|
||||
candidate.relative_to(STATIC_ROOT.resolve())
|
||||
except ValueError:
|
||||
self._json({"error": "not_found"}, HTTPStatus.NOT_FOUND)
|
||||
return
|
||||
if not candidate.is_file() and (
|
||||
Path(relative_path).suffix
|
||||
or relative_path.startswith(("assets/", "vendor/", "icons/"))
|
||||
):
|
||||
self._json({"error": "not_found"}, HTTPStatus.NOT_FOUND)
|
||||
return
|
||||
if not candidate.is_file():
|
||||
candidate = STATIC_ROOT / "index.html"
|
||||
content_type, _ = mimetypes.guess_type(candidate.name)
|
||||
@@ -972,8 +979,12 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
)
|
||||
self.send_header("Content-Length", str(len(content)))
|
||||
cache_control = "no-cache"
|
||||
if relative_path.startswith(("vendor/", "assets/", "icons/")):
|
||||
if relative_path.startswith(("vendor/", "icons/")) or (
|
||||
relative_path.startswith("assets/") and versioned
|
||||
):
|
||||
cache_control = "public, max-age=31536000, immutable"
|
||||
elif relative_path.startswith("assets/"):
|
||||
cache_control = "no-cache"
|
||||
elif candidate.name in {"index.html", "login.html", "service-worker.js"}:
|
||||
cache_control = "no-cache"
|
||||
self.send_header("Cache-Control", cache_control)
|
||||
|
||||
@@ -177,7 +177,7 @@ operations:
|
||||
def test_static_console_and_runtime_endpoint(self) -> None:
|
||||
with self.opener.open(f"{self.base_url}/", timeout=3) as response:
|
||||
html = response.read().decode("utf-8")
|
||||
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-80", timeout=3) as response:
|
||||
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-81", timeout=3) as response:
|
||||
app_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/gesture-control.js?v=android-pad-7", timeout=3
|
||||
@@ -199,6 +199,10 @@ operations:
|
||||
f"{self.base_url}/self-extension.css?v=extension-18", timeout=3
|
||||
) as response:
|
||||
extension_styles = response.read().decode("utf-8").replace("\r\n", "\n")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/service-worker.js", timeout=3
|
||||
) as response:
|
||||
service_worker = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/api/extension/health", timeout=3
|
||||
) as response:
|
||||
@@ -219,7 +223,7 @@ operations:
|
||||
self.assertIn("CMD 0x431 · FB 0x41A · CH1", html)
|
||||
self.assertIn("CMD 0x431 · FB 0x388 · CH1", html)
|
||||
self.assertNotIn("透明车体 · 实体设备", html)
|
||||
self.assertIn('src="/app.js?v=dual-seat-80"', html)
|
||||
self.assertIn('src="/app.js?v=dual-seat-81"', html)
|
||||
self.assertIn('href="/styles.css?v=dual-seat-9"', html)
|
||||
self.assertIn('src="/gesture-control.js?v=android-pad-7"', html)
|
||||
self.assertNotIn('class="vehicle-system-hud"', html)
|
||||
@@ -438,6 +442,23 @@ operations:
|
||||
self.assertIn("function createReferenceFrontLampHighlights", app_script)
|
||||
self.assertIn("referenceFrontLampMaterials", app_script)
|
||||
self.assertIn("targets.windowPositions", app_script)
|
||||
self.assertIn(
|
||||
'const REFERENCE_VEHICLE_ASSET_VERSION = "77a0fae7"', app_script
|
||||
)
|
||||
self.assertIn(
|
||||
"const REFERENCE_VEHICLE_LOAD_TIMEOUT_MS = 30000", app_script
|
||||
)
|
||||
self.assertIn(
|
||||
'referenceVehicleAssetUrl("byd-tang-2024.fbx")', app_script
|
||||
)
|
||||
self.assertIn("const stageHasLayout = () =>", app_script)
|
||||
self.assertIn("window.requestAnimationFrame(initSeatTwin)", app_script)
|
||||
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
|
||||
self.assertIn('"cognitive-agent:module-change"', app_script)
|
||||
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v117"', service_worker)
|
||||
self.assertIn(
|
||||
'"/assets/models/n7_seat.glb?v=e7f50f03"', service_worker
|
||||
)
|
||||
self.assertIn("hardware_access_required", app_script)
|
||||
self.assertIn('button.setAttribute("aria-label", "关闭摄像头")', gesture_script)
|
||||
self.assertIn("function refreshCameraAvailability", gesture_script)
|
||||
@@ -647,7 +668,7 @@ operations:
|
||||
) as response:
|
||||
extension_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/app.js?v=dual-seat-80", timeout=3
|
||||
f"{self.base_url}/app.js?v=dual-seat-81", timeout=3
|
||||
) as response:
|
||||
app_script = response.read().decode("utf-8")
|
||||
|
||||
|
||||
@@ -147,6 +147,18 @@ class TestSelfCalibrationApi:
|
||||
model = response.read()
|
||||
content_type = response.headers["Content-Type"]
|
||||
content_security_policy = response.headers["Content-Security-Policy"]
|
||||
unversioned_cache_control = response.headers["Cache-Control"]
|
||||
with urllib.request.urlopen(
|
||||
f"{self.base_url}/assets/models/n7_seat.glb?v=e7f50f03",
|
||||
timeout=3,
|
||||
) as response:
|
||||
versioned_model_prefix = response.read(4)
|
||||
versioned_cache_control = response.headers["Cache-Control"]
|
||||
with pytest.raises(urllib.error.HTTPError) as missing_model:
|
||||
urllib.request.urlopen(
|
||||
f"{self.base_url}/assets/models/missing-seat.glb?v=missing",
|
||||
timeout=3,
|
||||
)
|
||||
|
||||
assert 'href="/self-calibration.css?v=calibration-10"' in html
|
||||
assert 'src="/self-calibration.js?v=calibration-6"' in html
|
||||
@@ -173,6 +185,10 @@ class TestSelfCalibrationApi:
|
||||
assert '["self-calibration", "self-repair"].includes(module)' in console_script
|
||||
assert 'setRole("admin", { allowModuleTransition: true })' in console_script
|
||||
assert len(model) == 845_992
|
||||
assert versioned_model_prefix == model[:4]
|
||||
assert content_type.startswith("model/gltf-binary")
|
||||
assert unversioned_cache_control == "no-cache"
|
||||
assert versioned_cache_control == "public, max-age=31536000, immutable"
|
||||
assert missing_model.value.code == 404
|
||||
assert "img-src 'self' data: blob:;" in content_security_policy
|
||||
assert "connect-src 'self' blob:;" in content_security_policy
|
||||
|
||||
@@ -154,7 +154,7 @@ class TestSelfRepairApi:
|
||||
) as response:
|
||||
styles = response.read().decode("utf-8")
|
||||
with urllib.request.urlopen(
|
||||
f"{self.base_url}/self-repair-seat3d.js?v=repair-18", timeout=3
|
||||
f"{self.base_url}/self-repair-seat3d.js?v=repair-19", timeout=3
|
||||
) as response:
|
||||
seat3d = response.read().decode("utf-8")
|
||||
with urllib.request.urlopen(
|
||||
@@ -168,7 +168,7 @@ class TestSelfRepairApi:
|
||||
assert 'SELF-REPAIR' in script
|
||||
assert 'padding: var(--v2-module-title-block) 0 0' in styles
|
||||
assert 'margin-inline: var(--v2-module-title-inline)' in styles
|
||||
assert 'src="/self-repair-seat3d.js?v=repair-18"' in html
|
||||
assert 'src="/self-repair-seat3d.js?v=repair-19"' in html
|
||||
assert "量产故障注入" in script
|
||||
assert "运行与自修复日志" in script
|
||||
assert "启动座椅运行" in script
|
||||
@@ -203,6 +203,11 @@ class TestSelfRepairApi:
|
||||
assert 'viewer.addEventListener("pointerdown"' in seat3d
|
||||
assert 'window.addEventListener("pointermove"' in seat3d
|
||||
assert "window.addEventListener(resetEvent" in seat3d
|
||||
assert "function viewerHasLayout(viewer)" in seat3d
|
||||
assert "function deferSeat3dUntilVisible(viewer, options)" in seat3d
|
||||
assert "if (!viewerHasLayout(viewer))" in seat3d
|
||||
assert 'window.addEventListener("cognitive-agent:module-change"' in seat3d
|
||||
assert 'canvas.addEventListener("webglcontextlost"' in seat3d
|
||||
assert '["self-calibration", "self-repair"].includes(module)' in console_script
|
||||
assert 'roleSelect.disabled = ui.activeModule === "self-repair"' in console_script
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"heartbeat_epoch": 1786612896.954201, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1,3 @@
|
||||
BRIDGE_VERSION = 'runtime-test-v1'
|
||||
def run_bridge(transport=None, stop_event=None):
|
||||
stop_event.wait(2.0)
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786612902.0072305, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786612902.0072305, "0x302": 1786612902.0072305, "0x303": 1786612902.0072305, "0x304": 1786612902.0072305, "0x305": 1786612902.0072305, "0x306": 1786612902.0072305, "0x307": 1786612902.0072305}}
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786612902.1554296, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786612902.1554296, "0x302": 1786612902.1554296, "0x303": 1786612902.1554296, "0x304": 1786612902.1554296, "0x305": 1786612902.1554296, "0x306": 1786612902.1554296, "0x307": 1786612902.1554296}}
|
||||
@@ -0,0 +1 @@
|
||||
{"heartbeat_epoch": 1786614297.8563914, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1,3 @@
|
||||
BRIDGE_VERSION = 'runtime-test-v1'
|
||||
def run_bridge(transport=None, stop_event=None):
|
||||
stop_event.wait(2.0)
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786614302.9093528, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786614302.9093528, "0x302": 1786614302.9093528, "0x303": 1786614302.9093528, "0x304": 1786614302.9093528, "0x305": 1786614302.9093528, "0x306": 1786614302.9093528, "0x307": 1786614302.9093528}}
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786614303.057585, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786614303.057585, "0x302": 1786614303.057585, "0x303": 1786614303.057585, "0x304": 1786614303.057585, "0x305": 1786614303.057585, "0x306": 1786614303.057585, "0x307": 1786614303.057585}}
|
||||
@@ -0,0 +1 @@
|
||||
{"heartbeat_epoch": 1786614211.5981486, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1,3 @@
|
||||
BRIDGE_VERSION = 'runtime-test-v1'
|
||||
def run_bridge(transport=None, stop_event=None):
|
||||
stop_event.wait(2.0)
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786614216.6407876, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786614216.6407876, "0x302": 1786614216.6407876, "0x303": 1786614216.6407876, "0x304": 1786614216.6407876, "0x305": 1786614216.6407876, "0x306": 1786614216.6407876, "0x307": 1786614216.6407876}}
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786614216.7809346, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786614216.7809346, "0x302": 1786614216.7809346, "0x303": 1786614216.7809346, "0x304": 1786614216.7809346, "0x305": 1786614216.7809346, "0x306": 1786614216.7809346, "0x307": 1786614216.7809346}}
|
||||
@@ -0,0 +1 @@
|
||||
{"heartbeat_epoch": 1786628979.608127, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
BRIDGE_VERSION = 'runtime-test-v1'
|
||||
def run_bridge(transport=None, stop_event=None):
|
||||
stop_event.wait(2.0)
|
||||
+1
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786628984.6589825, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786628984.6589825, "0x302": 1786628984.6589825, "0x303": 1786628984.6589825, "0x304": 1786628984.6589825, "0x305": 1786628984.6589825, "0x306": 1786628984.6589825, "0x307": 1786628984.6589825}}
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786628984.8052018, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786628984.8052018, "0x302": 1786628984.8052018, "0x303": 1786628984.8052018, "0x304": 1786628984.8052018, "0x305": 1786628984.8052018, "0x306": 1786628984.8052018, "0x307": 1786628984.8052018}}
|
||||
@@ -0,0 +1 @@
|
||||
{"heartbeat_epoch": 1786608369.3573637, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1,3 @@
|
||||
BRIDGE_VERSION = 'runtime-test-v1'
|
||||
def run_bridge(transport=None, stop_event=None):
|
||||
stop_event.wait(2.0)
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786608374.4077742, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786608374.4077742, "0x302": 1786608374.4077742, "0x303": 1786608374.4077742, "0x304": 1786608374.4077742, "0x305": 1786608374.4077742, "0x306": 1786608374.4077742, "0x307": 1786608374.4077742}}
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786608374.5544136, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786608374.5544136, "0x302": 1786608374.5544136, "0x303": 1786608374.5544136, "0x304": 1786608374.5544136, "0x305": 1786608374.5544136, "0x306": 1786608374.5544136, "0x307": 1786608374.5544136}}
|
||||
@@ -0,0 +1 @@
|
||||
{"heartbeat_epoch": 1786607635.6544752, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1,3 @@
|
||||
BRIDGE_VERSION = 'runtime-test-v1'
|
||||
def run_bridge(transport=None, stop_event=None):
|
||||
stop_event.wait(2.0)
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786607640.7259998, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786607640.7259998, "0x302": 1786607640.7259998, "0x303": 1786607640.7259998, "0x304": 1786607640.7259998, "0x305": 1786607640.7259998, "0x306": 1786607640.7259998, "0x307": 1786607640.7259998}}
|
||||
@@ -0,0 +1 @@
|
||||
{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786607640.8686898, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786607640.8686898, "0x302": 1786607640.8686898, "0x303": 1786607640.8686898, "0x304": 1786607640.8686898, "0x305": 1786607640.8686898, "0x306": 1786607640.8686898, "0x307": 1786607640.8686898}}
|
||||
Reference in New Issue
Block a user