harp-device
The transport-agnostic device layer for the Harp protocol: the core Harp registers and a Device base that handles framing, request/reply and register access. It depends only on harp-protocol, with no transport dependencies. Pair it with a transport such as harp-serial.
Read/write registers
A Device operates over a transport. read and write take a register class:
from harp.device import core
# `device` is a Device opened over some transport, see harp-serial
who = device.read(core.WhoAmI).payload # -> np.uint16
device.write(core.OperationControl, payload) # write a register
When a request fails
An error reply raises DeviceError, which keeps the reply as reply so the frame sent by the device stays available for inspection. Pass raise_on_error=False to the constructor to receive such a reply as an ordinary return value instead. A transport failure raises TransportError, and every later request reports the same failure rather than waiting for a reply that cannot arrive. A device that never answers raises TimeoutError after REPLY_TIMEOUT, which is also what happens when close is called during a request.
Extend for a specific device
A device is described by a module. Downstream, often generated, packages record the device identity as WHO_AM_I, declare the register classes at module level, and expand the core REGISTER_MAP beside them:
from harp.device.core import REGISTER_MAP as _CORE_REGISTER_MAP
WHO_AM_I: int = 1216
REGISTER_MAP = {**_CORE_REGISTER_MAP, 32: DigitalInputState, ...}
This is the same structure create_device_module builds from a schema, so a device reads the same way whether it was generated ahead of time or compiled at runtime. A WHO_AM_I of 0 marks an unregistered device, used while a device is in development or outside the official registry, and identity checks are skipped for it.
A device module names only what its schema declares, the registers beside the enums and payload classes built from them. The core registers and any core mask reused by the schema have a single definition, in harp.device.core, and are accessed from there rather than through the device module. The core register set is not a device, so it carries no WHO_AM_I. REGISTER_MAP covers the complete device address space, including both core and application registers.
Pass the module to Device, or to open_device, to validate identity on open:
from harp.device import behavior, client, core
with client.Device(transport, behavior) as device:
device.read(core.WhoAmI) # a core register
device.read(behavior.DigitalInputState) # declared by the schema
The WHO_AM_I in the module determines the check, and 0 skips it. Omitting the module skips validation. The module is not otherwise consulted: registers are passed to read, write and subscribe as arguments either way, and only a subscribed register is parsed on arrival. Core registers such as WhoAmI and OperationControl come from harp.device.core and are read the same way.
A new transport is just an object implementing the ITransport protocol, with open, write, read and close.
Generate registers from a device.yml
Without a pre-generated device package, create_device_module builds the same structure at runtime from Harp device.yml text. It emits register, enum, and payload classes at module level, a REGISTER_MAP beside them, and the identity declared by the schema as WHO_AM_I. Identifiers match a generated package name for name: register, enum, and payload class names come from the yml verbatim, payload fields are snake_case, and enum members are SCREAMING_SNAKE_CASE. A maskType the schema does not declare resolves against the core masks, and a register marked private is emitted with an underscore-prefixed name.
from pathlib import Path
from harp.device import schema
behavior = schema.create_device_module(Path("device.yml").read_bytes())
reg = behavior.AnalogData # by name
reg = behavior.REGISTER_MAP[44] # or by address
The module is not registered in sys.modules, so it has to be bound rather than imported. Names come from the schema at runtime, so they don't autocomplete and aren't statically checked. A generated package on disk gives both.
For a custom interfaceType, pass its converter via converters=, keyed by {InterfaceType}Converter or {MemberName}Converter. An unresolved custom type raises UnknownConverterError, or pass require_converters=False to decode it natively:
schema.create_device_module(yml_text, converters={"DataConverter": DataConverter()})
parse_device_schema(yml_text) is also public, returning the parsed schema model without a module: registers, masks, and optional device identity.
harp-device is released as open source under the MIT license. Bug reports and contributions are welcome at the GitHub repository.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file harp_device-0.5.0.tar.gz.
File metadata
- Download URL: harp_device-0.5.0.tar.gz
- Upload date:
- Size: 26.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbeed57addb265e6e040c37b2438c1b8e6e1b2b8524f168f87f8aca98ea42aec
|
|
| MD5 |
c19c5f74df042f5cdd36c067aa81469b
|
|
| BLAKE2b-256 |
8418f48f8b553b09ce119e5819b075f1bce538797e333154a20206c557484cdb
|
File details
Details for the file harp_device-0.5.0-py3-none-any.whl.
File metadata
- Download URL: harp_device-0.5.0-py3-none-any.whl
- Upload date:
- Size: 27.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acf178e38cb943a950914dc69323845c572fef32ce5cb82f6877135395a67bf1
|
|
| MD5 |
e8375aae89ead333b06aa995dd885656
|
|
| BLAKE2b-256 |
03cd2303fe6cd78a23fa274f6ffc1943099f450509a89dfd88e94afcbee4db83
|