You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add PowerStrip device family, PwrUSBDevice driver, and HIDPort transport
Problem: A PwrUSB / PowerUSB power bar (USB HID 04d8:003f, enumerates as
"Simple HID Device Demo") with three switchable outlets was attached, but
PyHardwareLibrary had no power-strip family or driver for it, and no way to
reach an HID device the OS claims (on macOS, IOHIDFamily owns the interface, so
neither SerialPort nor USBPort/libusb can open it).
Solution: Add hardwarelibrary/powerstrips/ following the interface-segregated
capability-mixin pattern of sources/ and daq/. PowerStripDevice is a thin marker
base over PhysicalDevice exposing capabilities()/hasCapability(); capabilities.py
defines OutletSwitchingControl, DefaultOutletControl, and CurrentMeteringControl,
each a public method over a do* hook. PwrUSBDevice implements all three, speaking
the device's single-byte HID report protocol through a HIDPort. Outlet state is
cached on write because live readback is unreliable on this firmware.
DebugPwrUSBPort decodes the real command bytes so DebugPwrUSBDevice exercises the
encoding end to end without hardware.
Add HIDPort, a CommunicationPort backed by hidapi (IOKit on macOS), alongside
SerialPort and USBPort. It is required because the OS claims the HID interface;
hidapi is optional, installed via the new pwrusb extra (pip install -e .[pwrusb]),
whose package is hidapi (cython-hidapi, imports as hid), not the different hid
package. HIDPort.flush drains with a strictly positive per-read timeout, since
hidapi blocks on timeout_ms=0.
The single-byte protocol was reverse-engineered publicly and cross-checked
against aarossig/pwrusbctl (Apache-2.0) and pwrusb.com; the implementation is our
own (attribution in the module docstring and CHANGELOG). Verified end to end on
the lab unit (a PowerUSB "Basic"): opens over HID and switches outlets 1/2/3 on
and off. Metering is only meaningful on a "Smart" unit. Documents the new family
in the pyhardwarelibrary skill.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .claude/skills/pyhardwarelibrary/SKILL.md
+44-1Lines changed: 44 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
---
2
2
name: pyhardwarelibrary
3
-
description: Control lab hardware with the PyHardwareLibrary Python package — motion stages, spectrometers, lasers, power meters, DAQs, and oscilloscopes. Use when a user wants to move a stage, acquire a spectrum, turn a laser on/off or set its power/wavelength, read a power meter, read/write DAQ voltages, discover connected devices, run code without hardware (debug devices), or build a headless/GUI controller around a device. Covers the device lifecycle, per-family public API, event notifications, and the DeviceController worker-thread wrapper.
3
+
description: Control lab hardware with the PyHardwareLibrary Python package — motion stages, spectrometers, lasers, power meters, DAQs, oscilloscopes, and USB power strips. Use when a user wants to move a stage, acquire a spectrum, turn a laser on/off or set its power/wavelength, read a power meter, read/write DAQ voltages, switch power-strip outlets on/off, discover connected devices, run code without hardware (debug devices), or build a headless/GUI controller around a device. Covers the device lifecycle, per-family public API, event notifications, and the DeviceController worker-thread wrapper.
4
4
---
5
5
6
6
# Using PyHardwareLibrary
@@ -10,6 +10,15 @@ subclass with a uniform lifecycle and a small, predictable public API per family
10
10
skill is for *using* devices to get work done (move, measure, set). To *write a new
11
11
driver*, read `CLAUDE.md` and `README-4-New-device-coding-example.md` instead.
12
12
13
+
**Use the primitives from `CommunicationPort` for all communications.** A driver's `do*`
14
+
methods talk to hardware only through `self.port` — `writeData` / `readData` (and the
15
+
`readString` / `writeString` / `writeStringReadMatch` helpers built on them). Do **not**
16
+
invent new send/receive helpers on the device (no `_sendCommandByte`, no `_query`); call
17
+
the port methods directly. To support a new transport (serial, USB, HID, TCP, ...),
18
+
subclass `CommunicationPort` and go through the expected mechanism of **overriding
19
+
`readData` and `writeData`** (plus `open` / `close` / `isOpen` / `flush`) — the string and
20
+
transaction helpers then compose on top for free. `HIDPort` is the reference example.
21
+
13
22
## The one rule: lifecycle
14
23
15
24
Every device follows the same pattern. Construct it, initialize it, use it, shut it down.
0 commit comments