Usage & Examples
This guide walks through common workflows using spx_python.client.SpxClient and the utilities in spx_python.helpers. The examples mirror the scenarios exercised in tests/test_basic_spx_python.py, tests/test_helpers.py, and the system-level tests inside spx-examples.
Navigating the system tree
SpxClient behaves like a nested mapping. Indexing descends into sub-components, while attributes inside the attr section appear as properties.
client = spx_python.init(address=BASE_URL, product_key=PRODUCT_KEY)
# Access the models container
models = client["models"] # returns another SpxClient
# Descend to an instance and grab the temperature attribute wrapper
sensor = client["instances"]["sensor"]
temperature_attr = sensor["attributes"]["temperature"]
current = temperature_attr.internal_value # READ
temperature_attr.internal_value = current + 2.5 # WRITE
# Methods exposed by a component become callables
sensor.reset()
sensor.start()Using get, keys, items
get, keys, itemsclient.get()fetches the full JSON payload at the current path.client.get("child", default)behaves likedict.get, catchingSpxApiError.for name in client["instances"]:iterates over child component names.
Setting attributes via put_attr
put_attrput_attr(relative_path, value) addresses attributes using slash-separated paths. The last segment is the attribute, the preceding segments form the parent path.
put_item performs a raw PUT with an arbitrary payload when you need to update multiple fields at once.
Transparent mode for dry runs
Transparent mode turns the client into a no-op stub that records nothing and simply returns empty structures. Enabling it is useful when unit-testing higher-level logic without a live SPX server.
Inside transparent mode:
Indexing returns new transparent clients without performing HTTP.
Attribute reads return the sentinel (which is falsy).
Writes and method calls are ignored but return
{"result": True}to keep call chains intact.
See tests/test_client_unit.py::TestTransparentSentinel for the complete behaviour matrix.
Managing models and instances
The helpers in spx_python.helpers wrap the repetitive steps used across the spx-examples integration tests.
create_instance automatically derives an instance key from the model name (sensor_sim → sensor_sim, sensor_sim_2, …). These helpers power tests such as tests/test_helpers.py::TestHelperIntegration.
Waiting for state changes
Polling utilities make assertions in integration tests reliable:
wait_for_instance(client, "foo_inst", timeout=5)— poll until the instance is visible.wait_for_state(instance, {"RUNNING", "running"})— poll the.stateproperty.wait_for_attribute_value(instance, "attributes/output", 1.0)— poll until a value matches.wait_seconds(duration)— sleep with short intervals to keep loops responsive.
These helpers are used heavily in the spx-examples device tests (for example the BLE vital signs monitor and Modbus SUTs) to confirm that scenarios and attribute overrides propagate as expected.
Bootstrapping whole systems
bootstrap_model_instance bundles the recurring flow present in end-to-end tests:
The helper returns the SpxClient, the instance wrapper, and a flag indicating whether the model changed (allowing you to reset or recreate dependent instances automatically). This mirrors the setup code in tests like spx-examples/tests/test_ble_vital_signs_monitor_sut.py.
Calling component methods
When a component exposes methods such as start, stop, or custom endpoints defined in your YAML, the client surfaces them as callables that perform POST /method/<name>.
If the call returns JSON, SpxClient hands it back directly. Non-JSON responses result in None. The unit tests cover both cases (tests/test_client_unit.py::test_call_method_value_error_returns_none).
Putting it together
The combination of dictionary traversal, transparent mode, and helper routines lets you write expressive test code:
Everything shown here is battle-tested through spx-python’s own test suite and the sample systems shipped with spx-examples.
Last updated

