
Part Production Cell — MES & OEE
OpenPLC, Ignition Perspective and SQLite: order in events, KPIs and downtime causes.
This educational case shows a vertical slice between ERP, MES and SCADA. Odoo remains the owner of the manufacturing order and final confirmation. MES adds admission, execution identity and outbox. Ignition runs the SFC and remains the source of line facts.
I followed one order through the full loop: the operator starts it from Odoo, Node-RED picks up the release, MES admits one execution, and Ignition receives the command over OPC UA. The completion then returns to ERP as a verified result.
The real task was not only to send a command. The important part was keeping ownership clear: ERP does not write line tags, Node-RED does not invent production facts, and Odoo cannot close the order before MES returns a result.
ERP, MES and SCADA solve different tasks. Odoo knows the order, product, BoM and final confirmation. MES knows which execution was accepted and which result still needs to return. Ignition knows line state, SFC and runtime tags. Node-RED connects the systems, but does not become the owner of production facts.
Odoo stores the Manufacturing Order, BoM, quantity, components and final ERP confirmation. It does not write line tags or decide what happened inside the SFC.
MES DB creates a durable execution, protects the line from a second active order and stores completion until it is delivered to ERP.
Ignition SFC runs the Line01 runtime and writes state, good/reject counters and material consumption. These facts are not calculated in Node-RED.
After Start in Odoo, the order becomes queued for MES. Node-RED picks up the next release and builds a stable request identity. MES DB admits only one active execution for the line, so a repeated poll does not turn into a second production order.
WH/MO/00032 moves to In Progress. The MES block shows that the order is queued for release.
Flow 10 picks up the next queued order from Odoo and builds a canonical MES request with stable identity.
MES accepts the execution, checks whether the line is busy and publishes a Start command only for the accepted order.
Node-RED writes command fields to Ignition only after MES admission. RequestSequence is written last, so the Gateway script sees a complete payload. Ignition checks the order, execution, product, quantity and current line state. Only then does the SFC start runtime.
Node-RED writes CommandId, WorkOrderId, MesExecutionId, ProductCode and TargetGoodQty into Ignition command tags.
RequestSequence is written last. It is the boundary that tells Ignition the command is ready for validation.
Ignition SFC writes STARTING, RUNNING, COMPLETED, good count, reject count and consumption facts. Node-RED only observes.
cmdPaths = [
"[default]Line01/Cmd/Start/CommandId",
"[default]Line01/Cmd/Start/WorkOrderId",
"[default]Line01/Cmd/Start/MesExecutionId",
"[default]Line01/Cmd/Start/ProductCode",
"[default]Line01/Cmd/Start/TargetGoodQty",
]
values = system.tag.readBlocking(cmdPaths)
# RequestSequence is the commit boundary.
# When it changes, the full command payload is already written.
if requestSequence <= previousAckSequence:
return
chartInstanceId = system.sfc.startChart(
"Line01_DemoExecution",
chartParameters,
)
Ignition publishes completion after CompletionSequence changes. MES stores the production facts and creates a row for ERP outbox. A separate Node-RED flow delivers the pending result to Odoo and marks it as delivered only after a successful ERP response.
Flow 30 sees a new CompletionSequence over OPC UA and publishes a production-completed event.
MES DB stores completion and creates an erp_outbox row. A repeated resultId does not create a second ERP posting.
Flow 40 sends the pending outbox back to Odoo and marks the row as delivered only after a successful ERP response.
Early confirmation in Odoo is hidden until MES returns a result. After receipt, the operator gets the final Produce All action. Odoo remains the owner of ERP posting, but it can no longer close the order before the line has completed.
WH/MO/00032 is in progress: product PKG-A, target quantity 10.00 and MES release queued.
Odoo receives good quantity 10.00 and consumption for MAT-BASE-A, MAT-LABEL-A and MAT-PACK-A.
After the MES result, WH/MO/00032 is closed in Odoo. MES release is confirmed in ERP and the execution ID is retained on the order.
What the case shows:

OpenPLC, Ignition Perspective and SQLite: order in events, KPIs and downtime causes.

OPC UA, SQLite, and Ignition: from live pump state to persisted history and a verified operating scenario.

OpenPLC, Modbus TCP, and Ignition: from ladder logic to a verifiable operator scenario.