Extend with a Custom Component
SPX lets you add custom components so you can model behaviors that go beyond the built‑ins. In this guide we’ll create a tiny extension that simulates contact faults on a PT100 sensor (random spikes or drop‑to‑zero events), load it into a running SPX Server, and use it in a model.
This article is part of Getting Started. It focuses on a minimal, code‑defined workflow.
What you’ll build
A YAML model that references a new action called
contact_faultA Python implementation of that action (a custom extension)
A short script that:
connects to the SPX Server via
spx_pythonreloads extensions from the configured directories (e.g.
./extensions)runs a deterministic time simulation (you control the clock)
1) Define the model in YAML
We’ll model a PT100‑like sensor and apply a few actions: a saw, a ramp with overshoot, proportional noise, and our new contact_fault action that injects spikes/drops.
models:
pt100_sensor:
attributes:
temperature: 0.0
actions:
- { saw: $attr(temperature), stop_value: 14, period: 5 }
- { ramp: $attr(temperature), stop_value: 150, duration: 5, type: overshoot, overshoot: 5 }
- { noise: $ext(temperature), std: 0.01, mode: proportional }
- { contact_fault: $ext(temperature), spike_value: 500.0 } # custom extension
{
"models": {
"pt100_sensor": {
"attributes": {
"temperature": 0.0
},
"actions": [
{ "saw": "$attr(temperature)", "stop_value": 14, "period": 5 },
{ "ramp": "$attr(temperature)", "stop_value": 150, "duration": 5, "type": "overshoot", "overshoot": 5 },
{ "noise": "$ext(temperature)", "std": 0.01, "mode": "proportional" },
{ "contact_fault": "$ext(temperature)", "spike_value": 500.0 }
]
}
}
}
Why $ext(...)? We typically map fault injections to the external view of an attribute so core logic remains stable while the presented value exhibits faults.
2) Implement the custom action (contact_fault.py)
contact_fault.py)Create ./extensions/contact_fault.py:
You can organize extensions as single files or full folders/repositories. If an extension folder contains a
requirements.txt, SPX will attempt to install those dependencies (subject to your server configuration/permissions).
3) Load the extension in a running SPX Server
Use spx_python to connect and then reload modules. By default the server scans the configured extensions directories (e.g., ./extensions in the working directory). Ensure your contact_fault.py lives in one of those directories.
Note If your extension lives elsewhere, add that directory to the server’s extension search paths (per your deployment settings) before calling
reload_modules().
4) Create a model and run a deterministic time simulation
Deterministic means you control the clock — the simulation advances when you set timer.time and call run().
(Optional) Plot with Plotly:
Troubleshooting
“Module not found / class not registered” Ensure your file is inside a configured extensions directory and that you called
wrapper.reload_modules()after adding it. Check server logs for import errors.Dependencies missing If your extension needs packages, provide a
requirements.txtin the extension folder. Whether installs are allowed depends on your server configuration.No spikes visible Increase
probabilityor set a lowerdrop_ratioto bias spikes. You can also setseedfor reproducible runs.Real‑time vs deterministic time This example uses deterministic control (
timer.time+run()). For real‑time/polling modes, you would enable polling and usestart()/stop()instead.
Next steps
Package your extension as a reusable repo and point the server to it
Add unit tests for your custom component
Use labels/notes in snapshots to track experiments and reload setups quickly
Happy extending! 🎛️
Last updated

