Skip to content

v0.31.10: battery model catalog + Logitech webcam expansion#118

Merged
cmfisher606 merged 5 commits into
mainfrom
cf/webcams_and_battery
Jul 14, 2026
Merged

v0.31.10: battery model catalog + Logitech webcam expansion#118
cmfisher606 merged 5 commits into
mainfrom
cf/webcams_and_battery

Conversation

@cmfisher606

Copy link
Copy Markdown
Collaborator

What

v0.31.10: adds a read-only battery model catalog (lager battery models) for the Keithley 2281S, expands webcam support with 8 more Logitech models via catalog-driven detection, and fixes three battery bugs uncovered while hardware-verifying the catalog — model readback using the wrong SCPI query, built-in models being unloadable over SCPI, and driver errors being masked as "Resource busy".

Why

Battery-simulator users can load a model by slot (lager battery model 5) but had no way to discover which slots actually hold a model — they had to guess or walk to the instrument's front panel. Building the discovery feature against real hardware then exposed that the "current model" display had never been truthful (it always showed "DISCHARGE") and that recalling firmware built-in models had never worked at all. On the webcam side, a client needs the Logi 4K Pro; the old detection hard-coded three models and mapped /dev/video nodes with an index heuristic that breaks when cameras expose different node counts.

Changes

Battery — model catalog (new)

  • KeithleyBattery.model_catalog(): read-only catalog assembled from query-only :BATT:MOD<n>:VOC:STEPs? slot probes plus the 5 firmware built-ins. The 2281S has no :BATT:MODel:CATalog? (verified against reference manual 077114601 — the word "catalog" appears nowhere in it).
  • Dispatcher action list_models returns {"models": [...]} to /battery/command callers (same pattern as state); shared table formatter keeps CLI/TUI/HTTP output identical.
  • CLI lager battery <NET> models, battery TUI models command, HTTP + WebSocket endpoint actions.

Battery — bugs found during hardware verification

  • Model readback (model, state, TUI header) used :BATT:STAT?, which reports charge/discharge status — not the model — so it always showed "DISCHARGE", and set_model's verification raised a false "slot is empty" after every successful load. Now reads :BATT:MOD:RCL? (current_model()), which also catches the 2281S's silent empty-slot recall failures (no error is queued; readback is the only detection).
  • Built-in models were never loadable: the manual prints LI-ION4_2/LEAD-ACID12, but hyphens are SCPI syntax errors (-102). The catalog now uses the underscore spellings the firmware accepts; set_model takes either form.
  • The box endpoint returned driver-raised errors as 5xx, which made the CLI fall through to its legacy direct-USB path and bury the real message under [Errno 16] Resource busy. Driver errors now return as success: false with the driver's own message (HTTP and WebSocket).

Webcam

  • Catalog-driven camera detection: any SUPPORTED_USB entry with a webcam net_type is detected — adding a model is a table entry in usb_scanner.py + query_instruments.py (+ the role map in nets.py), no code changes.
  • /dev/videoN mapping now walks /sys/class/video4linux/videoN/device to the owning USB device, replacing the idx*4 heuristic that broke on mixed setups (C920 exposes 2 nodes, BRIO 4).
  • 8 new models: Logi 4K Pro, BRIO 4K Stream, C925e, C922 Pro, C920, C615, C270, StreamCam.

Docs/release: CHANGELOG, release notes, CLI battery reference, supported-instruments; version bump to 0.31.10.

Testing

  • 30 new unit tests: 23 battery (mocked SCPI transport — catalog parsing, empty slots, unsupported firmware, readback rendering, set_model verification incl. hyphen→underscore normalization) and 7 webcam (fake sysfs — node mapping, catalog sync between the two copies).
  • Hardware-verified on a 2281S (STG-1): catalog listing, built-in load with name-echo verification, truthful readback, empty-slot guidance error, slot restore.
  • Hardware-verified on JUL-24: Logi 4K Pro detected at its correct capture node (/dev/video4, metadata nodes and the host's non-catalog integrated webcam correctly skipped) and addable as a webcam net.
  • test/unit/box and test/unit/cli suites pass apart from 3 pre-existing failures that reproduce identically on main.

Notes

  • The 2281S SCPI ground truth (no catalog query; RCL? echoes slot number or built-in name; empty-slot recalls fail silently; hyphens unparseable) was established by probing real hardware and is documented in the driver docstrings.
  • Built-in model names shown to users changed from the manual's hyphenated spellings to the SCPI-true underscore forms (LI_ION4_2) so catalog output, readback, and model inputs are consistent; hyphenated input is still accepted.
  • Release process: this PR carries the v0.31.10 version commit at the branch tip — after rebase-merge, confirm it's at the tip of main before tagging, then publish to PyPI.
  • Follow-up (separate branch): the CLI still falls back to the doomed direct-USB path when a box HTTP command genuinely exceeds its 10s timeout; fallback should be reserved for boxes without the endpoint.

@cmfisher606 cmfisher606 merged commit d5eb318 into main Jul 14, 2026
2 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for 8 additional Logitech webcams using a new sysfs-based detection mechanism to correctly map video nodes, and introduces a new lager battery models command to list saved and built-in battery models on the instrument. It also addresses several bugs, including battery model readback, SCPI loading of built-in models, and error masking. Feedback on the changes points out a bug in _scpi_error_code where VISA transport-level errors (such as timeouts) are returned as integers outside the SCPI range, causing the model catalog probe to continue trying remaining slots and wasting time instead of aborting immediately.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +374 to +375
if args and isinstance(args[0], int):
return args[0]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If a transport-level or VISA communication error occurs (such as a timeout), exc.args[0] will contain a VISA status code (e.g., -1073807339). Since this is an integer, _scpi_error_code currently returns it directly. In model_catalog(), this code is not in the range [-199, -100], and it is not None, so the exception is caught and silently ignored via continue. This causes the catalog probe to continue trying the remaining slots, resulting in multiple consecutive timeouts and wasting significant time.

To fix this, we should ensure that _scpi_error_code only returns valid SCPI error codes (typically within the range [-32768, 32767]), so that VISA/transport errors return None and correctly trigger an immediate abort in model_catalog().

Suggested change
if args and isinstance(args[0], int):
return args[0]
if args and isinstance(args[0], int):
if -32768 <= args[0] <= 32767:
return args[0]

@cmfisher606 cmfisher606 deleted the cf/webcams_and_battery branch July 14, 2026 01:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant