← Controlar una salida digital del PLC desde Node-RED (rpiplc)
Mezclado industrial (HMI táctil)TouchBerry PiGPIOControl
Controlar una salida digital del PLC desde Node-RED (rpiplc) — ejemplo completo
Activa un relé desde un dashboard de Node-RED con rpiplc-digital-write, enclavamientos por software y apagado automático de seguridad en un Raspberry PLC.
Programa completo y ejecutable para el TouchBerry Pi (digital-output-q0-rpiplc-node-red.js): incluye cabecera de conexionado, requisitos y notas de integración.
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales
Vista de solo lectura.
/*
* COMPLETE EXAMPLE — Digital output Q0 from Node-RED (rpiplc-digital-write)
*
* Hardware: TouchBerry Pi (Raspberry Pi + Industrial Shields PLC, touch screen)
* Based on: industrial mixing project (Node-RED touch HMI)
*
* Requirements:
* - rpiplc node package for Node-RED (Industrial Shields), which gives
* direct access to the PLC I/O: rpiplc-digital-write, etc.
* - Q0.0 wired to the mixing machine contactor (with its thermal
* protection and hardware emergency stop downstream).
*
* Architecture:
* The "Force mixing" button on the dashboard does not drive the relay
* directly: it goes through an interlock function that checks the
* 'materials OK' LED (fed by MQTT) and the administrator session.
* Only then is output Q0 written, with an automatic safety
* shutdown in case the stop flow never arrives.
*
* Flow wiring:
*
* [mqtt in planta/Gk190-1/ready] ──> [function 1: storeReady]
*
* [ui-button "Start"] ─┐
* [ui-button "Stop"] ─┴─> [function 2: interlockQ0] ──> [rpiplc-digital-write]
* │
* └──(output 2)──> [ui-notification "Blocked"]
*
* [function 2 also] ──(trigger)──> the delayed shutdown is done with
* a deferred node.send() inside the function itself (see code).
*
* Node configuration:
* - rpiplc-digital-write: pin Q0.0; the value arrives in msg.payload (0/1).
* - ui-button "Start": payload = "ON" / ui-button "Stop": payload = "OFF".
*/
// ============================================================
// function 1: storeReady
// ------------------------------------------------------------
// Stores in the global context the last 'materials OK' state
// received over MQTT, so the interlock can check it.
// ============================================================
global.set("materialsOk", msg.payload == "1");
return msg; // continues to the dashboard LED
// ============================================================
// function 2: interlockQ0
// ------------------------------------------------------------
// Input: msg.payload = "ON" | "OFF" (dashboard buttons)
// Output 1 -> rpiplc-digital-write (msg.payload = 1 | 0)
// Output 2 -> ui-notification (command rejected)
//
// Interlock rules to switch on:
// 1. Materials OK (MQTT ready topic == "1")
// 2. Active administrator session for the manual override
// Stop (OFF) is ALWAYS accepted, unconditionally.
// ============================================================
const MAX_RUN_TIME_MS = 30 * 60 * 1000; // safety shutdown: 30 min
if (msg.payload === "OFF") {
// Stop is never blocked
const t = context.get("shutdownTimer");
if (t) { clearTimeout(t); context.set("shutdownTimer", null); }
global.set("q0State", false);
msg.payload = 0; // rpiplc-digital-write: Q0.0 = 0
return [msg, null];
}
if (msg.payload === "ON") {
// Interlock 1: materials ready
if (!global.get("materialsOk")) {
msg.payload = "Blocked: materials not OK";
return [null, msg];
}
// Interlock 2: valid administrator session
const last = global.get("lastAdminLoginDate");
const timeout = global.get("adminLoginTimeout") || 600000;
if (!(last && (new Date() - new Date(last)) < timeout)) {
msg.payload = "Blocked: log in as administrator";
return [null, msg];
}
// All good: switch Q0 on and arm the safety shutdown
global.set("q0State", true);
const prevTimer = context.get("shutdownTimer");
if (prevTimer) clearTimeout(prevTimer);
const timer = setTimeout(() => {
global.set("q0State", false);
context.set("shutdownTimer", null);
node.warn("Q0 safety shutdown after maximum run time");
node.send([{ payload: 0 }, null]); // forces Q0.0 = 0
}, MAX_RUN_TIME_MS);
context.set("shutdownTimer", timer);
msg.payload = 1; // rpiplc-digital-write: Q0.0 = 1
return [msg, null];
}
return [null, null]; // unknown payload: ignore
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales