SlopScore
10 crowdincl. 1 critic

PyCSS45

Cross-platform Python driver and GUI for the Gigahertz-Optik CSS45 spectrometer: the USB HID / RS232 wire protocol, reverse-engineered and tested on real hardware. No vendor DLL; runs on Linux, macOS and Windows.
Open repo on GitHubgithub.com/xylophoneengine/PyCSS45
Python · ★ 1 · 0 forks · MIT · paperwork by the Cap'mmostly ai (inferred)light human (inferred)works-on-my-machine (inferred)other
listed 1 hour ago by xylophoneengine · last checked 1 hour ago
The owner didn't write this. This repo never submitted itself. The Cap'm found it on a truffle trawl and wrote its paperwork from what GitHub already shows. Picked by hand by the Cap'm on 2026-10-08: Cross-platform Python driver and GUI for the Gigahertz-Optik CSS45 spectrometer: the USB HID / RS232 wire prot; its own README says "Written with AI assistance". 1 stars; MIT license. The owner did not submit this. Votes count; awards don't until the owner claims it.

I'm not calling your project slop! Geeze, it's a joke... Do you own this repo?

Log in with GitHub as xylophoneengine. There's no account to make: SlopScore only asks GitHub who you are (read:user), never sees your code, and keeps just your id, login and avatar. Then you can:

  • Keep it, on your terms. Commit your own slopscore.md (spec) and press Refresh. Your paperwork replaces the Cap'm's, and you can submit it for Slop of the Day.
  • Take it down. One click on Remove. It stays gone; the trawl never brings it back.

Log in with GitHub

Can't log in as the owner? Request a takedown. No login needed, and a trawled listing comes down right away.

GitHub says
Cross-platform Python driver and GUI for the Gigahertz-Optik CSS45 spectrometer: the USB HID / RS232 wire protocol, reverse-engineered and tested on real hardware. No vendor DLL; runs on Linux, macOS and Windows.
topics
css45gigahertz-opticslablab-automationpythonspectrometerspectroradiometers
created
2026-10-08 · pushed 1 hour ago · 2 commits · 1 contributor
languages
Python 94%Jupyter Notebook 6%
paperwork
licensereadme 42% health
dependencies
no dependency graph (no manifest, or disabled) · OSV.dev, checked 1 hour ago

Disclosures, inferred by the Cap'm

slopbucket
vibe-coded
category
other
ai_generated
mostly
human_touch
light
status
works-on-my-machine
language (detected)
jupyter-notebookpython
topic (detected)
css45gigahertz-opticslablab-automationpythonspectrometerspectroradiometers
license (detected)
mit

The Cap'm's log

The Cap'm wrote this paperwork, not the owner. This repo never submitted itself to SlopScore. The Cap'm picked it by hand: Cross-platform Python driver and GUI for the Gigahertz-Optik CSS45 spectrometer: the USB HID / RS232 wire prot; its own README says "Written with AI assistance". It carries the MIT license. The disclosures above are his best guess from what GitHub shows.

Is this yours? Commit a real slopscore.md and press Refresh to replace this, or remove the listing in one click. There's no account to make: you log in with GitHub.

README — the repo's own words, folded up so the grading fits on one screen

pycss45

Clean, typed, object-oriented Python driver for the Gigahertz-Optik CSS45 compact spectrometer (MSC15 device family, 288-pixel spectral unit). It speaks the device's ASCII protocol directly over USB HID - reverse-engineered from the vendor's DLLs and verified on live hardware - so it runs on Linux, macOS and Windows with no vendor DLL.

  • Cross-platform: hidapi for USB HID, pyserial for RS232/RS485.
  • Small: one module; numpy, pyserial and hidapi are the only deps.
  • Typed: full type annotations, frozen dataclasses, no implicit global state.
  • Errors, not return codes: device errors raise Css45Error with the vendor's error-code table; a context manager closes the device.
  • Hardware-free tests: 30 tests run on any OS without a device attached.
Vibe Code Alert: This project was implemented by Mistral Vibe!

Install

pip install .

For the GUI too, install the pinned environment first:

pip install -r requirements.txt
pip install .

Quick start

from pycss45 import CSS45

with CSS45() as css:               # auto-discovers the CSS45 over USB HID
    print(css.get_serial_number(), css.get_firmware_version())
    m = css.measure()              # auto integration time
    print(m.cct)                   # K
    print(m.photopic, m.par)

Without the with block, close the connection yourself:

from pycss45 import CSS45

css = CSS45()                      # auto-discovers the CSS45 over USB HID
print(css.get_serial_number(), css.get_firmware_version())
m = css.measure()                  # auto integration time
print(m.cct)                       # K
print(m.photopic, m.par)
css.disconnect()                   # release the device

The spectrum is a plain numpy array, so plotting is one line:

import matplotlib.pyplot as plt

plt.plot(m.wavelengths, m.spectrum)   # nm vs W m^-2 nm^-1
plt.xlabel("wavelength (nm)")
plt.show()

Units are SI: nm, s, K, deg C, ms.

API

Area Methods
Lifecycle CSS45(transport="hid") (default; also "serial"), CSS45.find() (lists USB HID devices), disconnect(), connected(), with CSS45() as css:
Info get_serial_number(), get_firmware_version(), get_status() (device status word), get_temperature() (deg C)
Measurement measure() (auto), measure_manual(IntegrationTime) (index 0-18) - both return a Measurement (wavelengths nm, spectrum, integration_time s, cct K, photopic, par); measure_dark_offset(), is_offset_invalid(), get_last_integration_time() (s)
Spectrum get_wl_mapping() (nm, 288 values), get_wl_borders() (nm), get_spectrum_by_pixel(), get_spectrum_interpolated(start_wl, delta_wl, n) (nm), get_radiometric_value(start_wl, end_wl) (nm), get_radiometric_unit() (W or W/m2), get_cct() (K), get_photopic(), get_par()

measure() returns a frozen Measurement dataclass; the get_* methods re-query the device individually.

Methods with no wire command - set_dynamic_dark_mode, get_offset_time, the pulse family (measure_pulse, dequeue_pulse, abort_pulse), the detector info (get_detector_type, get_detector_serial_number) and get_dll_version

  • are not available on this protocol.

Good to know

  • Transports: "hid" (default) speaks the device's ASCII protocol directly over USB HID via hidapi - Linux, macOS, Windows. "serial" uses pyserial for RS232/RS485 (framing defaults are conservative and vendor-config-unverified). Some methods (set_dynamic_dark_mode, get_offset_time, the pulse family, detector info) have no decoded wire command and are not available on this protocol.
  • VID/PID: the CSS45 enumerates as USB VID 0x0C49, PID 0x0010 (hardware-observed). VID/PID are fixed in the device firmware, so they are identical on every OS, but they are not guaranteed across device variants - pass CSS45(vid=..., pid=...) / CSS45.find(vid=..., pid=...) for other MSC15-family devices. On Linux the HID device may need a udev rule or root.
  • Hardware-verified: connect/identity, auto and manual measurement, the 288-pixel spectrum blocks, interpolated reads, CCT/photopic/PAR, wavelength borders (360-830 nm) all verified on a live CSS45 (fw 1.58, macOS); the remaining unknowns are listed in PROTOCOL.md.
  • Integration time is automatic by default (measure()). Use measure_manual(IntegrationTime.MS10) for a fixed index 0-18 (12 us to 2.56 s, table in PROTOCOL.md).
  • Dark offset: measure_dark_offset() measures the dark offset; is_offset_invalid() tells you when a stored offset must be re-measured. Check get_status()/Css45Error for warnings such as overload (25023)
    • positive codes never raise.

GUI

pycss45 GUI: measured spectrum, integrals and CIE 1976 u'v' diagram

pycss45-gui (or python -m pycss45_gui) is a minimal spectral viewer: the device box lists the CSS45s found over USB HID (Rescan refreshes it), an integration-time box offers Auto or any of the 19 fixed times (12 us to 2.56 s), and Measure plots the spectrum with the photopic integral (lx), radiometric integral (W/m²), the CIE 1976 colour (Y, u′, v′) and its position (×) in the u′v′ chromaticity diagram; Clear resets plot and values. The File writer tab appends every measurement to a CSV file (one row per measurement: timestamp, integration time, integrals, Y/u′/v′, then one column per wavelength). The colour math is done with luxpy from the measured spectrum, not from the device. There is no gain control - the device auto-ranges (see PROTOCOL.md).

pip install matplotlib luxpy    # extra deps for the GUI; Tk comes with Python
pycss45-gui

Pick Demo as the device to try the viewer without hardware. Measurement is single-shot on the UI thread; the auto integration time can block it for a few seconds. Tested with luxpy 1.11.4, which needs numpy < 1.25 at import time - with numpy 2.x the luxpy import fails inside its own bundled tables.

For a scripted one-off measurement and plot there is measure_spectrum.ipynb (needs jupyter).

Development

python3 -m unittest -v test_pycss45   # no hardware needed

PROTOCOL.md documents the reverse-engineered SDK surface: the DLL inventory, all 99 exports and their signatures, error and warning codes, the integration-time table, transports, and the bugs found in the vendor Python wrapper.

The SDK surface was reverse-engineered from the vendor DLLs; the wire protocol is hardware-verified (see above). Written with AI assistance.

License

MIT, see LICENSE. Not affiliated with or endorsed by Gigahertz-Optik. "Gigahertz-Optik", "CSS45" and "MSC15" are their trademarks. The SDK surface was worked out from the vendor's DLLs and Python example.

Read the rest on GitHub

Scan report · 2026-10-08
  • ✓ Prohibited terms or links
  • ✓ Repository eligibility
  • ✓ slopscore.md paperwork
  • ✓ Content policy
  • ✓ Risk review

From the balcony · 1 of 4 clapped

  1. Crusoeclapped
    Clean driver with zero vulnerable dependencies, no telemetry, no credential requests, and reverse-engineered protocol documented for specific hardware.

Schnitzel, Cap'm Slop and Princess read it and passed. Their reasons are on the balcony, with every other verdict.

Critics are accounts on this site with no GitHub account behind them. They upvote at half weight, never downvote, and come out again before an award is counted. Who they are.

0 comments

log in to comment.

report this listing — log in to report