Connect USB equipment
This guide gives a device resource its real hardware. The machine
the equipment plugs into publishes the USB device, a DeviceClass
selects it, and the device’s spec.claim claims it. During a
reservation, the device’s pod runs on that machine and its INDI
driver opens the device.
Two warnings come first.
- No drill has run this path on real equipment yet. The operator’s
tests and drills use the INDI simulators. The claim reaches the pod
through the same Kubernetes machinery that other
likenoperators use for their hardware, but whether each INDI driver can open its device as the pod’s user has not been checked. - Most dedicated astronomy cameras cannot reach a pod today. The next section explains which equipment works.
Equipment on the network, such as a mount with a Wi-Fi adapter or a weather station that serves its data over HTTP, needs no claim. Give the driver its address in KStars, or in the driver’s own properties.
What can reach a pod
liken publishes a USB device when a kernel driver controls it, or
when no driver binds any part of it, because a program drives it
through libusb. That decides what works:
| Equipment | How it connects | Reaches a pod |
|---|---|---|
| Most mounts: EQMOD cables, Sky-Watcher and Celestron USB ports, LX200 serial | a USB serial chip: FTDI, Prolific PL2303, WCH CH340, or USB CDC-ACM | yes, as a tty |
| Most focusers and power boxes: MoonLite, Pegasus, and the like | a USB serial chip | yes, as a tty |
| ZWO EFW filter wheels, ZWO EAF focusers | USB HID | yes, with its USB node |
| ZWO, QHY, Player One, SVBony, ToupTek, and the other vendor-SDK cameras | the vendor’s library over libusb, with no kernel driver | yes, as a whole device with its USB node |
| DSLRs and mirrorless cameras through gphoto2 | libusb, with no kernel driver | yes, as a whole device with its USB node |
A device with no kernel driver publishes whole, named by its USB port,
such as usb-1-2, and a claim on it delivers its USB node and nothing
else. The liken
device reference
gives the rule. QHY cameras also load their firmware through udev
rules on the host, and those rules do not run on a liken machine, so
a QHY camera that needs its firmware loaded does not work yet.
1. Load the kernel driver
A liken machine loads only the drivers for its disks and its network
ports. Every other device needs its driver named once in the
machine’s spec.modules. Plug the equipment in, then read what the
machine found and cannot drive:
kubectl get machine <node> -o jsonpath='{.status.hardware.unclaimed}' | jq
Each entry names the device and the modules that can drive it. The
USB serial chips use ftdi_sio, pl2303, ch341, or cdc_acm, and
HID devices use usbhid. The liken
hardware modules guide
gives the steps to declare them. A camera that a vendor library or
gphoto2 drives has no kernel module to declare, so go on to step 2.
2. Find the device
When a driver controls the device, or when the device has no kernel
driver at all, it appears in the node’s ResourceSlice:
kubectl get resourceslice <node>-liken.sh -o yaml
Look for the device by its name, vendor, and product
attributes. A USB serial adapter has subsystem: tty. Note the
serial attribute when it has one: an EQMOD cable and a focuser can
both use FTDI chips with the same vendor and product IDs, and the
serial number is what tells them apart. The liken
device reference
lists
every attribute.
3. Write a DeviceClass
liken ships no DeviceClass, because only you know what each piece
of equipment is. Write one for each device, and select it as narrowly
as you need. This class selects one FTDI cable by its serial number:
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
name: east-mount-cable
spec:
selectors:
- cel:
expression: |
device.driver == "liken.sh" &&
device.attributes["liken.sh"].vendor == "0403" &&
device.attributes["liken.sh"].product == "6001" &&
has(device.attributes["liken.sh"].serial) &&
device.attributes["liken.sh"].serial == "A10KXYZ1"
Guard an attribute that a device may lack with has(). A read of a
missing attribute is an evaluation error, and an evaluation error
stops the whole allocation.
4. Claim the device
A device’s spec.claim is a ResourceClaimSpec. The operator creates
a ResourceClaim from it when the reservation starts the device’s
pod, and deletes the claim when the pod stops:
apiVersion: observatory.liken.sh/v1alpha1
kind: Mount
metadata:
name: east
spec:
telescope: east
driver:
name: indi_eqmod_telescope
claim:
devices:
requests:
- name: mount
exactly:
deviceClassName: east-mount-cable
The operator creates no claim for a device on the shelf, or for a device whose telescope has no active reservation. So equipment that you describe stays free for other uses until you reserve it.
5. Reserve the telescope
During a reservation’s StartDevices step, each device with a claim
waits until the scheduler allocates its hardware and its pod runs. The
pod runs on the machine that holds the device, and the driver reaches
the INDI server over the cluster network, so the devices of one
telescope can be on different machines. The guide camera is the
exception that the scheduler does not decide: without a claim, it runs
on the node of the telescope’s INDI server, and with a claim, it runs
where its device is.
kubectl get rsv -n observatory -w
kubectl get resourceclaims -n observatory
A pod that stays Pending has a claim that no device satisfies. The
step’s summary names the device it waits for, and
kubectl describe pod gives the scheduler’s reason.
6. Check the port
The pod receives the device node at the same path that it has on the
machine, and no other tty. FTDI, PL2303, and CH340 adapters are
/dev/ttyUSB<n>, and CDC-ACM adapters are /dev/ttyACM<n>, numbered
in the order the kernel found them. Many INDI serial drivers open
their default port, usually /dev/ttyUSB0, and search the other
serial ports when that open fails. A driver with no search, or one
whose default port is a different name, does not find its device.
The operator connects each device during the Connect step. A device
that cannot open its port answers the connect with an error, and the
step fails with that device’s name. The operator has no field for a
driver’s port, and a driver in a pod does not keep its saved
configuration from one reservation to the next. Today, set the
driver’s DEVICE_PORT property from KStars, and then run the failed
step again as Troubleshoot
describes.