Simulation

plesty.lib.sim provides stand-ins for hardware, so a contract can be proven without an instrument on the bench. Three of them, at three different depths.

Class

Stands in for

Depth

DataGenerator

the values an instrument would return

a schema

DemoDevice

a whole device module

a device class

AptMotorSimulator

a Thorlabs APT controller

a serial port

None of these belong in a hub module’s shipped code — they are what its tests and the contract pipelines build on.

DataGenerator — Values From a Schema

DataGenerator(seed=None) reads a parameter’s own metadata — dtype, range, options, shape, headers — and produces a representative random value that satisfies it. This is what lets the mock gates exercise every registered key and operation without knowing anything about the device.

from plesty.lib.sim.data_generator import DataGenerator

gen = DataGenerator(seed=42)
value = gen.rand_default(param)        # respects dtype, range and options

Beyond rand_default it offers rand_int, rand_float, rand_bool, rand_str, rand_list, rand_tuple, rand_dict, rand_plesty_array and rand_plesty_table2d. Pass seed to make a failing run reproducible — the test helpers thread their own seed argument down to it for exactly that reason.

Used by device_param_system, device_func_system, DevicePipeline and FieldTestPipeline. See Test helpers.

DemoDevice — One of Everything

DemoDevice is a complete device that needs no instrument. It answers from an in-memory store, and its schema is deliberately one of everything the parameter system has to handle: a plain float and int, a str with options, a bool, a read-only key, a write-only key, and a grouped key (MOTOR.position) to exercise full-key resolution. Two operations, measure_power and reset, cover the acquire and lifecycle sides of the function system.

from plesty.lib.sim.demo_device import DemoDevice, MOCK_ADDRESS

device = DemoDevice(MOCK_ADDRESS)      # "mock" — the in-memory store

It exists so tests stop hand-writing their own. Before it, plesty-lib’s tests had a _MockDevice and plesty-sdk’s scaffold tests had a _DocDevice, each slightly different and each drifting from the standard separately. DocDevice remains as an alias of DemoDevice for that older name.

Any address other than "mock" is taken to be a real instrument and refuses to connect — which is what a module does when the hardware is not there, and makes the failure path testable too. device_id is generated when omitted, so constructing the device repeatedly (as the gates do) does not collide on the resource registry.

DemoDevice is what the spawned mode of client_field_test serves, which is how that tier runs in CI at all.

AptMotorSimulator — A Fake Serial Port

AptMotorSimulator is not a device; it is a transport. It presents the serial-port surface AptTrafficManager expects — write, read, in_waiting, reset_input_buffer, flush, close — and answers real APT protocol frames, tracking position, homed and channel as a controller would.

from plesty.lib.sim.apt import AptMotorSimulator
from my_stage import MyRotationStage

stage = MyRotationStage(port="sim", transport=AptMotorSimulator())
stage.connect()
stage.home()

Because it substitutes at the port, everything above it is the real code path: the framing, the traffic manager, BaseAptDevice, the parameter system. Only the motor is missing. See Traffic manager and Base device.