Modify WebUI & system start flow for Mass production

This commit is contained in:
miketsai 2026-06-28 14:40:02 +08:00
parent 41c0a781f2
commit 49cdb5bbae
2 changed files with 126 additions and 2 deletions

20
tools/device/start.sh Normal file
View File

@ -0,0 +1,20 @@
#!/bin/sh
mkdir -p /tmp/venc/c0/;
mkdir -p /tmp/aenc/c0/;
mkdir -p /tmp/playback/c0/;
mkdir -p /tmp/twoway/c0/;
mkdir -p /tmp/sr/c0/;
mkdir -p /tmp/sdcard;
mkdir -p /tmp/canbus/c0/;
mount /dev/mmcblk0p1 /tmp/sdcard 2>/dev/null || true
export LD_LIBRARY_PATH=$(pwd)/lib;
cd ../plus/kp_firmware/kp_firmware_0/kp_firmware/bin
./rtsps -c stream_server_config.ini &
./kp_firmware_host_stream &
#./rtsps -c stream_server_config.ini > /dev/null 2>&1 &
#./kp_firmware_host_stream > /tmp/fw.log 2>&1 &
### Notice : Codec type AAC4, sample rate 8000, bit rate 32000, raw format, stereo, mic_in ###
#./tinyaenc_mmap -d "hw:0,0" -r 8000 -C 0 -b 32000 -t 0 -S 0 -i 0 &
#sleep 2;
#./volume_ctrl -i 0 -M 0 -v 96;
#./playback_example_mmap -d "hw:0,0" -r 8000 -c 2 -C 0 &

View File

@ -46,6 +46,7 @@ DEPLOY_SRC = SCRIPT_DIR / "tools" / "device" / "deploy.sh"
DEMO_RTSP_SRC = SCRIPT_DIR / "tools" / "device" / "demo_rtsp.sh"
DEMO_HDMI_SRC = SCRIPT_DIR / "tools" / "device" / "demo_hdmi.sh"
DEMO_RTSP_HDMI_SRC = SCRIPT_DIR / "tools" / "device" / "demo_rtsp_hdmi.sh"
START_SH_SRC = SCRIPT_DIR / "tools" / "device" / "start.sh"
NEF_DIR = SCRIPT_DIR / "nef"
KCURL_SRC = Path("/home/user/Documents/GOFACE/奧創雲/kCurl-1.1.1-release/kCurl-linux-armv7")
CONFIG_FILE = SCRIPT_DIR / ".web_config.json"
@ -93,6 +94,7 @@ def prepare_build_dir():
(DEMO_RTSP_SRC, "demo_rtsp.sh"),
(DEMO_HDMI_SRC, "demo_hdmi.sh"),
(DEMO_RTSP_HDMI_SRC, "demo_rtsp_hdmi.sh"),
(START_SH_SRC, "start.sh"),
]:
if Path(src).exists():
shutil.copy2(src, BUILD_DIR / name)
@ -521,6 +523,9 @@ def api_deploy_run():
("Pushing deploy.sh to device...",
f"wget -q {base}/deploy.sh -O /tmp/deploy.sh && chmod +x /tmp/deploy.sh && echo 'deploy.sh OK'",
False, 30),
("Updating start.sh...",
f"wget -q {base}/start.sh -O /mnt/flash/vienna/start.sh && chmod +x /mnt/flash/vienna/start.sh && echo 'start.sh OK'",
False, 30),
("Downloading kCurl (event upload tool)...",
f"wget -q {base}/kCurl -O {bd}/kCurl && chmod +x {bd}/kCurl && echo 'kCurl OK'",
False, 30),
@ -562,6 +567,89 @@ def api_deploy_run():
return Response(generate(), mimetype="text/event-stream",
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"})
# ── API: deploy binary only (SSE) ────────────────────────────────────────────
@app.route("/api/deploy/binary")
def api_deploy_binary():
cfg = load_config()
kl_ip = request.args.get("ip", cfg["kl630_ip"])
h_ip = request.args.get("host_ip", cfg["host_ip"])
port = int(request.args.get("port", cfg["port"]))
base = f"http://{h_ip}:{port}"
fw = FW_PATH_DEVICE
bd = BIN_DIR_DEVICE
out_rtsp = request.args.get("out_rtsp", "1") == "1"
out_hdmi = request.args.get("out_hdmi", "0") == "1"
if out_hdmi and not out_rtsp:
start_cmd = f"cd {bd} && nohup sh ./ini/demo_hdmi.sh > /tmp/fw.log 2>&1 &"
elif out_rtsp and out_hdmi:
start_cmd = f"cd {bd} && nohup sh ./ini/demo_rtsp_hdmi.sh > /tmp/fw.log 2>&1 &"
else:
start_cmd = f"cd {bd} && nohup sh ./ini/demo_rtsp.sh > /tmp/fw.log 2>&1 &"
def generate():
yield sse(f"Connecting to {kl_ip}:23...")
try:
tn = _telnet_connect(kl_ip)
_drain_shell(tn)
yield sse("Connected.", "ok")
yield sse("Stopping firmware...")
for ln in _telnet_run(tn, "killall -9 kp_firmware_host_stream 2>/dev/null; killall -9 rtsps 2>/dev/null; sleep 1; rm -f /dev/shm/*", timeout=15):
yield sse(ln)
yield sse("Downloading binary...")
for ln in _telnet_run(tn, f"wget -q {base}/kp_firmware_host_stream -O {fw} && chmod +x {fw} && ls -lh {fw}", timeout=60):
yield sse(ln, "ok")
yield sse("Restarting firmware...")
for ln in _telnet_run_bg(tn, start_cmd):
if ln.strip(): yield sse(ln.strip())
ok, lines = _verify_firmware_running(tn)
for ln in lines:
yield sse(ln, "ok" if ok else "warn")
if ok:
yield sse("Binary updated and firmware running.", "ok")
else:
yield sse("Firmware may not have started — check /tmp/fw.log", "warn")
tn.close()
except Exception as e:
yield sse(f"Telnet error: {e}", "error")
yield sse_done()
return Response(generate(), mimetype="text/event-stream",
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"})
# ── API: deploy start.sh only (SSE) ──────────────────────────────────────────
@app.route("/api/deploy/startsh")
def api_deploy_startsh():
cfg = load_config()
kl_ip = request.args.get("ip", cfg["kl630_ip"])
h_ip = request.args.get("host_ip", cfg["host_ip"])
port = int(request.args.get("port", cfg["port"]))
base = f"http://{h_ip}:{port}"
def generate():
yield sse(f"Connecting to {kl_ip}:23...")
try:
tn = _telnet_connect(kl_ip)
_drain_shell(tn)
yield sse("Connected.", "ok")
yield sse("Updating start.sh...")
for ln in _telnet_run(tn, f"wget -q {base}/start.sh -O /mnt/flash/vienna/start.sh && chmod +x /mnt/flash/vienna/start.sh && echo 'start.sh OK'", timeout=30):
yield sse(ln, "ok")
tn.close()
yield sse("start.sh updated. Takes effect on next reboot.", "ok")
except Exception as e:
yield sse(f"Telnet error: {e}", "error")
yield sse_done()
return Response(generate(), mimetype="text/event-stream",
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"})
# ── API: SPI setup via Telnet (SSE) ─────────────────────────────────────────
@app.route("/api/spi_setup/run")
def api_spi_setup_run():
@ -1693,6 +1781,14 @@ input:checked+.slider:before{transform:translateX(16px);background:#fff}
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="5 12 12 5 19 12"/><line x1="12" y1="5" x2="12" y2="19"/></svg>
Deploy to KL630
</button>
<button class="btn btn-ghost" id="btn-deploy-binary" onclick="runAction('deploy_binary')">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="4" y="2" width="16" height="20" rx="2"/><line x1="8" y1="10" x2="16" y2="10"/><line x1="8" y1="14" x2="16" y2="14"/></svg>
Update Binary
</button>
<button class="btn btn-ghost" id="btn-deploy-startsh" onclick="runAction('deploy_startsh')">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
Update start.sh
</button>
<button class="btn btn-warn" id="btn-bt-setup" onclick="runAction('bt_setup')">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6.5 6.5l11 11M17.5 6.5l-11 11"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z"/></svg>
BT 初始化
@ -1864,8 +1960,16 @@ function runAction(action) {
'&out_hdmi=' + (document.getElementById('out-hdmi').checked ? 1 : 0),
autostart_read: '/api/autostart/read?ip=' + encodeURIComponent(cfg.kl630_ip),
mount_sd: '/api/mount_sd?ip=' + encodeURIComponent(cfg.kl630_ip),
deploy_binary: '/api/deploy/binary?ip=' + encodeURIComponent(cfg.kl630_ip) +
'&host_ip=' + encodeURIComponent(cfg.host_ip) +
'&port=' + encodeURIComponent(cfg.port) +
'&out_rtsp=' + (document.getElementById('out-rtsp').checked ? 1 : 0) +
'&out_hdmi=' + (document.getElementById('out-hdmi').checked ? 1 : 0),
deploy_startsh: '/api/deploy/startsh?ip=' + encodeURIComponent(cfg.kl630_ip) +
'&host_ip=' + encodeURIComponent(cfg.host_ip) +
'&port=' + encodeURIComponent(cfg.port),
};
const labels = { compile:'Compile', deploy:'Deploy to KL630', bt_setup:'BT 初始化', spi_setup:'SPI 初始化', autostart:'Write Autostart', autostart_read:'Read Autostart', mount_sd:'Mount SD' };
const labels = { compile:'Compile', deploy:'Deploy to KL630', bt_setup:'BT 初始化', spi_setup:'SPI 初始化', autostart:'Write Autostart', autostart_read:'Read Autostart', mount_sd:'Mount SD', deploy_binary:'Update Binary', deploy_startsh:'Update start.sh' };
appendLog('\\n── ' + labels[action] + ' ' + ''.repeat(40), 'prompt');
setLogStatus('Running...');
@ -1961,7 +2065,7 @@ function appendLog(text, kind) {
}
function clearLog() { document.getElementById('log').textContent = ''; setLogStatus(''); }
function setLogStatus(s) { document.getElementById('log-status').textContent = s; }
function setBtns(disabled){ ['btn-compile','btn-deploy','btn-bt-setup','btn-spi-setup','btn-autostart','btn-autostart-read','btn-mount-sd','btn-model-apply'].forEach(id => document.getElementById(id).disabled = disabled); }
function setBtns(disabled){ ['btn-compile','btn-deploy','btn-bt-setup','btn-spi-setup','btn-autostart','btn-autostart-read','btn-mount-sd','btn-model-apply','btn-deploy-binary','btn-deploy-startsh'].forEach(id => document.getElementById(id).disabled = disabled); }
// Terminal
// by mars