Initial commit: appRobotHoming
This commit is contained in:
66
public/client.js
Executable file
66
public/client.js
Executable file
@@ -0,0 +1,66 @@
|
||||
(function(){
|
||||
const logEl = document.getElementById('log');
|
||||
const connEl = document.getElementById('conn');
|
||||
|
||||
function append(line){
|
||||
const now = new Date().toISOString();
|
||||
logEl.value += `[${now}] ${line}
|
||||
`;
|
||||
logEl.scrollTop = logEl.scrollHeight;
|
||||
}
|
||||
|
||||
async function refreshStatus(){
|
||||
try{
|
||||
const res = await fetch('/api/status');
|
||||
const st = await res.json();
|
||||
if (st.connected){ connEl.textContent = 'verbunden'; connEl.className = 'badge ok'; }
|
||||
else if (st.lastError){ connEl.textContent = 'fehler'; connEl.className = 'badge err'; }
|
||||
else { connEl.textContent = 'getrennt'; connEl.className = 'badge warn'; }
|
||||
}catch(e){ connEl.textContent = 'unbekannt'; connEl.className = 'badge'; }
|
||||
}
|
||||
|
||||
function connectSSE(){
|
||||
const es = new EventSource('/api/events');
|
||||
es.onmessage = (ev)=>{
|
||||
try{
|
||||
const p = JSON.parse(ev.data);
|
||||
if (p.level === 'msg') append(`WSS → ${p.data?.text ?? ''}`);
|
||||
else if (p.level === 'tx') append(`TX → ${JSON.stringify(p.data)}`);
|
||||
else append(`${p.level?.toUpperCase?.()}: ${p.message}`);
|
||||
}catch{ append(ev.data); }
|
||||
};
|
||||
es.onerror = ()=>{
|
||||
append('SSE Fehler/unterbrochen. Versuche neu zu verbinden…');
|
||||
setTimeout(connectSSE, 2000);
|
||||
};
|
||||
}
|
||||
|
||||
function bindButtons(){
|
||||
document.querySelectorAll('button[data-cmd]').forEach(btn =>{
|
||||
btn.addEventListener('click', async () =>{
|
||||
const cmd = btn.getAttribute('data-cmd');
|
||||
|
||||
let payload = null;
|
||||
const payloadSelector = btn.getAttribute('data-payload');
|
||||
if (payloadSelector) {
|
||||
const field = document.querySelector(payloadSelector);
|
||||
if (field) payload = field.value;
|
||||
}
|
||||
|
||||
try{
|
||||
const res = await fetch('/api/send', {
|
||||
method:'POST', headers:{ 'Content-Type':'application/json' },
|
||||
body: JSON.stringify({ cmd, payload })
|
||||
});
|
||||
const data = await res.json();
|
||||
if(!res.ok){ append(`FEHLER ${res.status}: ${data.error || 'Unbekannt'}`); }
|
||||
else { append(`Sende: ${cmd}`); }
|
||||
}catch(err){ append('FEHLER: ' + (err?.message || err)); }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bindButtons();
|
||||
connectSSE();
|
||||
refreshStatus();
|
||||
})();
|
||||
44
public/index.html
Executable file
44
public/index.html
Executable file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>appRobotHoming</title>
|
||||
<link rel="stylesheet" href="/styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>appRobotHoming</h1>
|
||||
<div id="status">Status: <span class="badge" id="conn">…</span></div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="controls">
|
||||
<button data-cmd="HOME">HOME</button>
|
||||
<button data-cmd="STOP">STOP</button>
|
||||
<button data-cmd="STATUS">STATUS</button>
|
||||
<button data-cmd="RESET">RESET</button>
|
||||
<button data-cmd="PING">PING</button>
|
||||
<input
|
||||
id="gcodePayload"
|
||||
type="text"
|
||||
placeholder="G-Code / Motorbefehl"
|
||||
style="width: 220px; padding: 10px; border-radius: 8px; border: 1px solid #334155; background: #0b1220; color: #e2e8f0;"
|
||||
/>
|
||||
<button data-cmd="GCODEMOTOR" data-payload="#gcodePayload">GCodeMotor</button>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="log">
|
||||
<label for="log">Ausgabe</label>
|
||||
<textarea id="log" readonly></textarea>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<small>HTTPS + WSS Relay • ©</small>
|
||||
</footer>
|
||||
|
||||
<script src="/client.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
16
public/styles.css
Executable file
16
public/styles.css
Executable file
@@ -0,0 +1,16 @@
|
||||
:root{ --bg:#0f172a; --fg:#e2e8f0; --muted:#94a3b8; --accent:#38bdf8; --ok:#22c55e; --warn:#f59e0b; --err:#ef4444; }
|
||||
*{ box-sizing:border-box; }
|
||||
body{ margin:0; font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif; background:var(--bg); color:var(--fg); }
|
||||
header{ display:flex; justify-content:space-between; align-items:center; padding:16px 24px; border-bottom:1px solid #1f2937; }
|
||||
h1{ margin:0; font-size:20px; }
|
||||
.badge{ padding:2px 8px; border-radius:999px; background:#334155; }
|
||||
.badge.ok{ background: #064e3b; color:#a7f3d0; }
|
||||
.badge.warn{ background:#3f1b00; color:#fdba74; }
|
||||
.badge.err{ background:#3f0d0d; color:#fecaca; }
|
||||
main{ display:grid; grid-template-columns:1fr; gap:16px; padding:16px; max-width:900px; margin:0 auto; }
|
||||
.controls{ display:flex; gap:12px; flex-wrap:wrap; }
|
||||
.controls button{ background:#1e293b; color:var(--fg); border:1px solid #334155; padding:10px 16px; border-radius:8px; cursor:pointer; }
|
||||
.controls button:hover{ border-color: var(--accent); }
|
||||
.log{ display:flex; flex-direction:column; gap:8px; }
|
||||
#log{ width:100%; height:360px; background:#0b1220; color:var(--fg); border:1px solid #1f2937; border-radius:8px; padding:8px; font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size:12px; }
|
||||
footer{ padding:12px 24px; border-top:1px solid #1f2937; color:var(--muted); }
|
||||
Reference in New Issue
Block a user