# 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. ```python 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](device/test_helper.md). ## `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. ```python 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`](device/test_helper.md#9-client_field_test--the-gates-over-the-wire) 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. ```python 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](device/traffic_manager.md) and [Base device](device/base_device.md). ## Related Pages 1. [Test helpers](device/test_helper.md) — the pipelines that consume these 2. [Base device](device/base_device.md) — `BaseAptDevice` and its `transport=` argument 3. [Traffic manager](device/traffic_manager.md) — what `AptMotorSimulator` stands in for