Emergency Stop

This commit is contained in:
chk
2026-06-12 18:16:15 +02:00
parent 6fc6605080
commit 59d4cf7df4
17 changed files with 1098 additions and 540 deletions

View File

@@ -77,6 +77,80 @@ function createInfoServer(httpsOptions, sharedState, robot, GCode, senders, opti
// ── Robot-Config-Service ─────────────────────────────────────────────────
robotConfigService.register(app, { apiKey: options.apiKey });
// ── Power Status (Shelly) ────────────────────────────────────────────────
//
// GET /api/power-status
// Fragt den Shelly-Controller nach dem aktuellen Schaltzustand.
// Antwort: { ok, armed: bool, voltage?, power? }
// armed:true → output:true → Strom AN → Roboter bestromt ("armed")
// armed:false → output:false → Strom AUS → Roboter stromlos
app.get('/api/power-status', async (req, res) => {
const shelly = senders.find(({ instance }) => typeof instance.getArmed === 'function');
if (!shelly) {
return res.json({ ok: false, armed: false, error: 'no shelly configured' });
}
const result = await shelly.instance.getArmed();
res.json(result);
});
// ── Emergency Stop ───────────────────────────────────────────────────────
//
// POST /api/emergency-stop
// Ruft auf allen Sendern emergencyStop() auf (parallel).
// FluidNC-Sender: sendet '!' (Feed Hold).
// Shelly-Sender: schaltet Strom ab.
// Aufruf vom Framework (Kopfzeile-Button): POST https://<host>:2098/api/emergency-stop
//
// POST /api/power-on
// Schaltet Strom über Shelly wieder ein (nach NotAus-Restart).
//
// POST /api/alarm-unlock
// Sendet '$X' an alle FluidNC-Controller (entsperrt ALARM-Zustand nach Strom-Neustart).
// Nur aufrufen, nachdem Roboterstellung manuell geprüft wurde.
app.post('/api/emergency-stop', async (req, res) => {
const settled = await Promise.allSettled(
senders.map(({ name, instance }) =>
instance.emergencyStop().then(r => ({ name, ...r }))
)
);
const results = settled.map((r, i) =>
r.status === 'fulfilled'
? r.value
: { name: senders[i].name, ok: false, error: r.reason?.message }
);
console.log(`[EmergencyStop] triggered at ${new Date().toISOString()}`);
res.json({ ok: results.every(r => r.ok || r.skipped), at: new Date().toISOString(), results });
});
app.post('/api/power-on', async (req, res) => {
const shellyEntries = senders.filter(({ instance }) =>
typeof instance.powerOn === 'function'
);
const settled = await Promise.allSettled(
shellyEntries.map(({ name, instance }) => instance.powerOn().then(r => ({ name, ...r })))
);
const results = settled.map(r =>
r.status === 'fulfilled' ? r.value : { ok: false, error: r.reason?.message }
);
res.json({ ok: results.length > 0 && results.every(r => r.ok), at: new Date().toISOString(), results });
});
app.post('/api/alarm-unlock', async (req, res) => {
const settled = await Promise.allSettled(
senders.map(({ name, instance }) =>
instance.alarmUnlock().then(r => ({ name, ...r }))
)
);
const results = settled.map((r, i) =>
r.status === 'fulfilled'
? r.value
: { name: senders[i].name, ok: false, error: r.reason?.message }
);
res.json({ ok: results.every(r => r.ok || r.skipped), at: new Date().toISOString(), results });
});
// ── 404 ──────────────────────────────────────────────────────────────────
app.use((req, res) => res.status(404).end('Not found'));