lager drivers install. Then every user
can drive its nets with the standard CLI. The driver code is stored on the box
only.
Bundle layout
pyserial, pyusb and hidapi) and the lager package. For other
packages, see Python packages.
The manifest
The manifest gives the driver’s type, its net settings and its actions. The CLI builds thelager <type> command from it, and the box checks every call against
it.
Each param and arg has a
type: str, int, float, bool or choice. A param
can also be net, which names another saved net of the given role; the driver
then uses that net to reach the hardware. Fields can also have required,
default, min and max (numbers only), choices (for choice) and help.
Action, param and arg names are 1 to 32 lower case letters, digits and _, starting with
a letter. No - is allowed; the CLI shows hold_time as --hold-time. These arg names
are reserved, because the CLI uses them already: box, json, as_json, help,
netname, action, role, quiet, http_timeout, ctx, box_addr, params.
The driver
- Only methods marked with
@actioncan be called, and each must be named in the manifest. The method gets the action’s args as keyword arguments, with the types the manifest gives. setup()runs before the action andteardown()runs after it, also when the action raises an exception.- Return a dict, a value or
None. A dict’smessageis printed by the CLI; the other keys are shown below it, and--jsonprints the whole result. - An exception becomes an error for the user, with its type and message.
print()output andself.loggo to the box log, not to the user.
Python packages
A driver can use packages that are not on the box. List them in a requirements file and name it in the manifest:lager drivers install, so a call never
waits for them. They are stored with the driver in /etc/lager/drivers/, so they
stay installed after lager update. If a package cannot be installed, the driver
is not installed, and the version that was installed before keeps working.
The file must pin every package to one version with a hash, including the
packages that your packages need. pip-compile writes such a file:
- Exact versions with hashes only. Each line is
name==versionwith at least one--hash. Options such as-r,-eand--index-urlare not allowed. - Wheels only. The box does not build packages from source. A package must
have a wheel for the box’s Python (3.12) and CPU. Boxes can be
x86_64oraarch64(ARM), so pick packages that have wheels for both, or pure-Python wheels.pip-compile --generate-hasheslists the hashes for every platform. - The box’s own packages come first. A driver cannot replace a package that the box already has. If you pin a package the box has, the version must be the same as the box’s, or the install is refused. Leave such packages out.
- Each driver has its own packages. Two drivers can use different versions of the same package.
- Limits. The box gives the install 5 minutes, and the installed packages can use at most 200 MB.
A box without internet
Put the wheel files in awheels/ folder in the bundle. The box uses them before
it looks on the internet. They count toward the 5 MB bundle limit. To download
them for the box’s CPU:
manylinux_2_36_x86_64 for an x86_64 box. Running uname -m on the box
shows which one it is. Pure-Python wheels work on both.
After an update
If alager update changes the box’s Python version, lager drivers list shows the
driver as error and its Deps as stale. Install the packages again with:
How a call runs
Each call runs the driver in a new process on the box. A driver that crashes or hangs cannot stop the box. The box loads Lager before the call, so the process starts quickly. It loadsdriver.py again for each call, so an
installed update takes effect on the next call. Two calls on the same net run one after the other. If a
lager uart session holds the UART net that the driver uses, the call is refused
until that session closes.
Using a driver from a script
Alager python script can use a custom net directly:
open_driver() loads the driver in the script’s own process. It runs setup() on entry and
teardown() on exit. It raises ManifestError when the net is not a custom net. It also
raises it when a net param names a missing net or a net of the wrong role. It raises
DriverFailed when the driver does not import or has no such action. lager.drivers also
exports DriverBusy, DriverTimeout and DriverUnavailable. The box’s HTTP API uses them
for a busy net, a timeout and a driver that is not installed.
Install and use it
lager python script. It is
kept out of the public Lager code, but a person who can connect to the box can
read it.
