doppelt senden unterbinden. CSV
This commit is contained in:
21
docker-compose.yaml
Executable file
21
docker-compose.yaml
Executable file
@@ -0,0 +1,21 @@
|
||||
services:
|
||||
appRobotHoming:
|
||||
image: node:20-bullseye
|
||||
container_name: appRobot_Homing
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- /home/chk/Documents/appRobotHoming:/app
|
||||
environment:
|
||||
- WSS_VIDEO_DRIVER=wss://localhost:8448
|
||||
- WSS_URL=wss://appRobot_Driver:2095
|
||||
- HTTPS_PORT=2093
|
||||
ports:
|
||||
- "2093:2093"
|
||||
depends_on:
|
||||
- appRobotDriver
|
||||
command: >
|
||||
/bin/bash -lc "npm ci || npm install && node server/server.js"
|
||||
networks:
|
||||
- default
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -19,12 +19,42 @@
|
||||
}catch(e){ connEl.textContent = 'unbekannt'; connEl.className = 'badge'; }
|
||||
}
|
||||
|
||||
function processDataShortenPosition(data){
|
||||
if(data?.text){
|
||||
try{
|
||||
let obj = JSON.parse(data.text);
|
||||
if(obj?.position){
|
||||
obj.position.x = parseFloat(obj.position.x.toFixed(3));
|
||||
obj.position.y = parseFloat(obj.position.y.toFixed(3));
|
||||
obj.position.z = parseFloat(obj.position.z.toFixed(3));
|
||||
obj.position.a = parseFloat(obj.position.a.toFixed(3));
|
||||
obj.position.b = parseFloat(obj.position.b.toFixed(3));
|
||||
obj.position.c = parseFloat(obj.position.c.toFixed(3));
|
||||
}
|
||||
if(obj?.motorCounts){
|
||||
obj.motorCounts.x = parseFloat(obj.motorCounts.x.toFixed(3));
|
||||
obj.motorCounts.y = parseFloat(obj.motorCounts.y.toFixed(3));
|
||||
obj.motorCounts.z = parseFloat(obj.motorCounts.z.toFixed(3));
|
||||
obj.motorCounts.a = parseFloat(obj.motorCounts.a.toFixed(3));
|
||||
obj.motorCounts.b = parseFloat(obj.motorCounts.b.toFixed(3));
|
||||
obj.motorCounts.c = parseFloat(obj.motorCounts.c.toFixed(3));
|
||||
if(obj.motorCounts.e !== undefined) obj.motorCounts.e = parseFloat(obj.motorCounts.e.toFixed(3));
|
||||
}
|
||||
return "text: " + JSON.stringify(obj);
|
||||
}catch(e){
|
||||
return "text: " + data.text;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
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 ?? ''}`);
|
||||
if (p.level === 'msg' && p.data?.text !== 'Ping') append(`WSS → ${processDataShortenPosition(p.data)}`);
|
||||
//if (p.level === 'msg') append(`WSS → ${processDataShortenPosition(p.data)}`);
|
||||
else if (p.level === 'tx') append(`TX → ${JSON.stringify(p.data)}`);
|
||||
else append(`${p.level?.toUpperCase?.()}: ${p.message}`);
|
||||
}catch{ append(ev.data); }
|
||||
@@ -60,7 +90,47 @@
|
||||
});
|
||||
}
|
||||
|
||||
async function loadLatestSnapshot() {
|
||||
try {
|
||||
const res = await fetch('/api/latest-snapshot');
|
||||
if (!res.ok) throw new Error('Fehler beim Laden des Snapshots');
|
||||
let data;
|
||||
if (res.headers.get('content-type')?.includes('application/json')) {
|
||||
data = await res.json();
|
||||
} else {
|
||||
const csvData = await res.text();
|
||||
// Fallback: filename aus dem Pfad oder unbekannt, mtime jetzt
|
||||
data = { filename: 'latest.csv', mtime: new Date().toISOString(), content: csvData };
|
||||
}
|
||||
const infoEl = document.getElementById('snapshot-info');
|
||||
const tableEl = document.getElementById('snapshot-table');
|
||||
|
||||
// Info anzeigen
|
||||
const mtime = new Date(data.mtime).toLocaleString();
|
||||
infoEl.textContent = `Datei: ${data.filename} | Erstellt: ${mtime}`;
|
||||
|
||||
// CSV parsen und Tabelle bauen
|
||||
const lines = data.content.trim().split('\n');
|
||||
if (lines.length === 0) {
|
||||
tableEl.innerHTML = '<tr><td>Keine Daten</td></tr>';
|
||||
return;
|
||||
}
|
||||
const headers = lines[0].split(',');
|
||||
let html = '<thead><tr>' + headers.map(h => `<th>${h.trim()}</th>`).join('') + '</tr></thead><tbody>';
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const cells = lines[i].split(',');
|
||||
html += '<tr>' + cells.map(c => `<td>${c.trim()}</td>`).join('') + '</tr>';
|
||||
}
|
||||
html += '</tbody>';
|
||||
tableEl.innerHTML = html;
|
||||
} catch (err) {
|
||||
document.getElementById('snapshot-info').textContent = 'Fehler: ' + err.message;
|
||||
document.getElementById('snapshot-table').innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
bindButtons();
|
||||
connectSSE();
|
||||
refreshStatus();
|
||||
loadLatestSnapshot();
|
||||
})();
|
||||
|
||||
@@ -33,6 +33,12 @@
|
||||
<label for="log">Ausgabe</label>
|
||||
<textarea id="log" readonly></textarea>
|
||||
</section>
|
||||
|
||||
<section class="snapshot">
|
||||
<label for="snapshot-content">Neuester Snapshot</label>
|
||||
<div id="snapshot-info"></div>
|
||||
<table id="snapshot-table"></table>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
|
||||
@@ -7,10 +7,15 @@ h1{ margin:0; font-size:20px; }
|
||||
.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; }
|
||||
main{ display:grid; grid-template-columns:1fr; gap:16px; padding:16px; max-width:1400px; 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; }
|
||||
.snapshot{ display:flex; flex-direction:column; gap:8px; }
|
||||
#snapshot-info{ font-size:14px; color:var(--muted); }
|
||||
#snapshot-table{ width:100%; border-collapse:collapse; background:#0b1220; color:var(--fg); border:1px solid #1f2937; border-radius:8px; overflow:hidden; }
|
||||
#snapshot-table th, #snapshot-table td{ padding:4px 8px; border:1px solid #334155; text-align:left; font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size:12px; }
|
||||
#snapshot-table th{ background:#1e293b; }
|
||||
footer{ padding:12px 24px; border-top:1px solid #1f2937; color:var(--muted); }
|
||||
|
||||
@@ -149,6 +149,7 @@ app.post('/api/send', (req, res) => {
|
||||
console.log(`G0 ${arrayMsg[1].toUpperCase()} F1000 gesendet`);
|
||||
}
|
||||
*/
|
||||
return res.json({ ok: true, sent: msg.payload});
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -186,6 +187,35 @@ app.get('/api/events', (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
// Neuester Snapshot-Endpunkt
|
||||
app.get('/api/latest-snapshot', (req, res) => {
|
||||
const snapshotsDir = path.join(path.resolve('public'), 'snapshots');
|
||||
fs.readdir(snapshotsDir, (err, files) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: 'Fehler beim Lesen des Snapshots-Verzeichnisses' });
|
||||
}
|
||||
const csvFiles = files.filter(file => file.endsWith('.csv')).map(file => ({
|
||||
name: file,
|
||||
path: path.join(snapshotsDir, file),
|
||||
mtime: fs.statSync(path.join(snapshotsDir, file)).mtime
|
||||
})).sort((a, b) => b.mtime - a.mtime);
|
||||
if (csvFiles.length === 0) {
|
||||
return res.status(404).json({ error: 'Keine CSV-Dateien gefunden' });
|
||||
}
|
||||
const latestFile = csvFiles[0];
|
||||
fs.readFile(latestFile.path, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: 'Fehler beim Lesen der Datei' });
|
||||
}
|
||||
res.json({
|
||||
filename: latestFile.name,
|
||||
mtime: latestFile.mtime.toISOString(),
|
||||
content: data
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Statisches Frontend
|
||||
app.use('/', express.static(path.resolve('public')));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user