🚧 Change module numbering

This commit is contained in:
Jonas Bengtsson
2026-10-04 13:05:47 +02:00
parent 7948b794f5
commit e5df0b04ed
17 changed files with 644 additions and 138 deletions
+67
View File
@@ -0,0 +1,67 @@
"""Example plant/PLC model plugin for the pump-station FAT scenario.
In a real FAT bench the PLC under test drives the outputs. For a
headless demo (or pre-FAT scenario smoke tests) this plugin emulates
the expected PLC behavior so the scenario can PASS end-to-end.
Register it in a scenario via:
plugins: [plugins.pump_plant.pump_plant]
The engine calls it once per tick.
"""
from __future__ import annotations
# latch state per engine instance (module-level dict keyed by id)
_LATCH = {}
def pump_plant(engine, value) -> None:
"""Emulated PLC with classic start/stop latch circuit:
- rising edge on start_button latches the pump ON
- e-stop OFF breaks the latch (and the safe state follows)
- valve follows the pump; speed setpoint follows level above 4000
"""
key = id(engine)
start = bool(engine.alias_value("start_button"))
em_stop = bool(engine.alias_value("em_stop_ok"))
level = float(engine.alias_value("level_sensor"))
# rising edge of the start button sets the latch; e-stop clears it
if engine.consume_rising_edge("start_button"):
_LATCH[key] = True
if not em_stop:
_LATCH[key] = False
pump_on = _LATCH.get(key, False) and em_stop
speed = int(max(0.0, (level - 4000.0) * 10.0)) if pump_on else 0
_set_do(engine, "pump_relay", pump_on)
_set_do(engine, "valve_open", pump_on)
_set_ao(engine, "speed_setpoint", speed)
def _set_do(engine, alias_name: str, value: bool) -> None:
"""Emulate a Modbus master writing the output coil.
Uses the engine's global alias location: ``loc.bit`` is the 0-based
global digital channel index == the Modbus bit address (Table 122).
"""
loc = engine.alias_location(alias_name)
result = engine.datastore.write_bits(loc.bit, [bool(value)])
assert not isinstance(result, Exception), result
def _set_ao(engine, alias_name: str, value: int) -> None:
"""Emulate a Modbus master writing the output register.
``loc.word`` is the global analog output word index == the Modbus
word address in output area 1 (0x0000-0x00FF).
"""
alias = engine._aliases[alias_name]
loc = engine.alias_location(alias_name)
raw = int(value * alias.scale + alias.offset) & 0xFFFF
result = engine.datastore.write_words(loc.word, [raw])
assert not isinstance(result, Exception), result