
Tank Level Control
OpenPLC, Modbus TCP e Ignition: dalla logica Ladder a uno scenario operatore verificabile.
Questo caso studio non riguarda una singola schermata. Ho costruito il percorso dei dati di una pompa: comandi e feedback in OPC UA, modello di processo nel Gateway, snapshot in SQLite e stato visibile all'operatore in Perspective.
Ho iniziato dai tag e dal comportamento della pompa. Poi ho spostato la persistenza nelle Named Queries e verificato che SQL mostrasse lo stesso processo con una differenza temporale comprensibile. Solo dopo ho costruito la schermata dove stato live e ultimo record del database sono vicini.
L'obiettivo pratico era avviare la pompa, vedere cambiare i valori, salvarli nella cronologia e completare un fault controllato con recovery. È un prototipo didattico, non un sistema produttivo o safety-certified.

Ho iniziato da un dispositivo OPC UA programmabile. Contiene comandi, stati, valori di processo e contatori. Il Gateway Timer legge le richieste una volta al secondo, calcola la risposta della pompa e scrive solo il feedback effettivo.
Per prima cosa mi sono connesso all'endpoint OPC UA e ho verificato il namespace. Questo stabilisce da dove Ignition legge i dati e quali node path usa il progetto.
Con il browsing ho verificato la struttura di Pump_01 e fissato i node per comandi, stati, valori di processo e contatori. StartRequest resta una richiesta, non lo stato reale della pompa.
Le subscriptions aggiornano Running, FaultActive, velocità, pressione, temperatura e portata. Il modello Gateway li calcola e sia HMI sia SQL logger leggono gli stessi valori.
Dopo il modello ho aggiunto un secondo Gateway Timer. Salva uno snapshot in SQLite ogni cinque secondi. Le Named Queries restituiscono l'ultima riga per il pannello SQL e gli ultimi dieci minuti di cronologia per la tabella.
Ogni riga salva tempo, Pump_01, stato, velocità, pressione, temperatura e portata. Il database registra quindi un fatto di processo, non lo stato di una schermata.
GetLatestPumpSnapshot restituisce lo snapshot persistito più recente per un pannello dedicato. Non è una copia dei tag live: è il risultato di una scrittura in SQLite.
GetPumpHistoryWindow restituisce le righe recenti, dalla più nuova. Durante un ramp una piccola differenza dal valore live è attesa, perché SQL scrive ogni cinque secondi.
CREATE TABLE IF NOT EXISTS process_snapshot (
id INTEGER PRIMARY KEY AUTOINCREMENT,
captured_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
equipment_id TEXT NOT NULL,
running INTEGER NOT NULL,
fault_active INTEGER NOT NULL,
speed_actual REAL NOT NULL,
pressure_bar REAL NOT NULL,
temperature_c REAL NOT NULL,
flow_m3h REAL NOT NULL
);
INSERT INTO process_snapshot (
equipment_id,
running,
fault_active,
speed_actual,
pressure_bar,
temperature_c,
flow_m3h
) VALUES (
:equipment_id,
:running,
:fault_active,
:speed_actual,
:pressure_bar,
:temperature_c,
:flow_m3h
);
SELECT
id, captured_at, equipment_id, running, fault_active,
speed_actual, pressure_bar, temperature_c, flow_m3h
FROM process_snapshot
WHERE equipment_id = :equipment_id
ORDER BY id DESC
LIMIT 1;
SELECT
captured_at, running, fault_active, speed_actual,
pressure_bar, temperature_c, flow_m3h
FROM process_snapshot
WHERE equipment_id = :equipment_id
AND captured_at >= datetime(
'now',
'-' || :lookback_minutes || ' minutes'
)
ORDER BY captured_at DESC;
-- equipment_id: String (Pump_01)
-- lookback_minutes: Int4 (10)
Quando comunicazione e persistenza sono diventate stabili, ho costruito la schermata operatore. Comandi, stato OPC UA live, ultimo record SQL e cronologia sono insieme, così si può verificare il percorso completo dal comando al risultato persistito.
Dopo STOP, la schermata mostra STOPPED. Velocità, pressione e portata tornano a zero, la temperatura scende verso l'ambiente e SQL conserva tutta la traccia di cooldown.
Dopo l'inserimento del setpoint e START, la pompa passa a RUNNING e accelera verso il target. SQL mostra la variazione di velocità, pressione, temperatura e portata.
Alla condizione di trip, il modello arresta la pompa e persiste la transizione al cooldown in fault. Quando si è raffreddata, RESET permette un nuovo avvio.
Cosa dimostra questo progetto:

OpenPLC, Modbus TCP e Ignition: dalla logica Ladder a uno scenario operatore verificabile.

OpenPLC, Ignition Perspective e SQLite: eventi, KPI e cause dei fermi macchina organizzati in modo chiaro.

OpenPLC e Ignition: logica Ladder, macchina a stati in Structured Text, feedback dei sensori e cicli normali verificabili.