Verified against the repo's first real DA-07 capture (157 frames, saved as tests/da07/fixtures/capture-2026-06-12-refresh.txt): the ~E payload ends at the alarm byte, followed only by an optional 8-byte CT sensor serial - there is no disp field and no name field on the wire. The phantom disp read (inherited from the VB6, which had the same bug feeding its hidden Disp column) ate the serial's first byte, producing the reported "Tag column cuts off the first characters" symptom. Removed disp everywhere: decoder E branch, ChannelRecord, the Channels-tab Disp column (later columns shift left one), controller.set_channel_disp, encoder CH_DISP (ICD §11 has no ~D field 9), the simulator's disp byte, repo snapshot, and help text. The simulator now emits the wire-faithful E layout (serial-only tail). The Tag column shows name -> serial -> catalog default, matching legacy precedence; a written name lives only in the local model until ~P (the presumed custom-name frame, absent from this capture) is decoded - BL-E5 part 2 stays open, needs-capture. The capture also re-confirmed no ~H arrives during a refresh (it streams periodically afterwards), which is what made the stale-model revert fire every second once live. Docs updated: BL-E5 part 1 done, HW-VERIFICATION item 8 resolved, field-notes entry added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CIMTechniques Service Suite
A modern Python 3 + PySide6 rebuild of CIMTechniques' legacy VB6 instrument tools — a unified, signed, single-install application for configuring and monitoring CIMTechniques sensor stations over serial / RS-232 during production and in the field.
The suite is a monorepo: a shared core package, a shell launcher, and one module
per instrument family. You install, sign, and update one app.
| Module | Instrument | Status |
|---|---|---|
| DA-12 | DA-12 Monitoring Station | Functionally complete against simulator; hardware verification pending |
| DA-07 ("eLink") | DA-07 station (Station → Devices → Channels) | Functionally complete against simulator; hardware verification pending |
| IOModbus | Config-driven Modbus RTU master (bundled device catalog) | Functionally complete against simulator; hardware verification pending |
All three modules are rebuilt from their original VB6 baselines (preserved read-only
under cim_suite/modules/<id>/legacy/). The outstanding milestone is verification
against real DA-12, DA-07, and Modbus hardware.
Quick start
Requires Windows and Python 3.11+.
# Setup
py -m venv .venv
.venv\Scripts\python -m pip install -e ".[dev]"
# Run against the in-memory simulator (no hardware needed — the normal dev path)
.venv\Scripts\python -m cim_suite.shell.app --module da12 --simulate
.venv\Scripts\python -m cim_suite.shell.app --module da07 --simulate
.venv\Scripts\python -m cim_suite.shell.app --module iomodbus --simulate
# Run against real hardware on a serial port
.venv\Scripts\python -m cim_suite.shell.app --module da12 --port COM3
# Open the suite launcher (module card grid)
.venv\Scripts\python -m cim_suite.shell.app
The simulator (SimulatedStation) speaks the real wire protocol, so the whole app —
and the full test suite — runs headless with no instrument attached.
Development
# Tests (headless; UI tests run offscreen via pytest-qt)
.venv\Scripts\python -m pytest -q
# Lint
.venv\Scripts\python -m ruff check cim_suite tests
A green pytest and a clean ruff are both part of "done" here.
Building a standalone app
# One-folder executable (PyInstaller)
.venv\Scripts\pyinstaller --noconfirm --distpath packaging\dist --workpath packaging\build packaging\suite.spec
# Windows installer (requires Inno Setup 6). Pass the version so the installer and
# Add/Remove Programs match the app — it's single-sourced from pyproject.toml:
$v = .venv\Scripts\python -c "import cim_suite; print(cim_suite.__version__)"
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" /DAppVersion=$v packaging\installer.iss
Versioning & releases
The suite uses Semantic Versioning (MAJOR.MINOR.PATCH). There
are two records of change, with different audiences:
- Git history — the technical record. Every commit uses the
Conventional Commit format
<type>: <description>. CHANGELOG.md— the human-facing record: plain-language release notes for the (non-technical) people who use the app. It's also shown in-app via the What's new button on the start page.
| Commit type | Meaning | Version bump | In changelog? |
|---|---|---|---|
feat |
A new user-facing capability | minor | Yes (Added / Changed) |
fix |
A bug fix | patch | Yes (Fixed) |
feat! / BREAKING CHANGE: in body |
Removes or breaks existing behavior | major | Yes (Changed / Removed) |
docs, style, refactor, perf, test, build, ci, chore, revert |
Internal work | none | Collapsed to one "maintenance" line, or dropped |
# One-time on a fresh clone: install the commit-message validation hook
.venv\Scripts\python scripts\setup_hooks.py
# Bump the version (deterministic; edits pyproject.toml only). --dry-run to preview.
.venv\Scripts\python scripts\bump.py --dry-run
.venv\Scripts\python scripts\bump.py # auto-detect from commits
.venv\Scripts\python scripts\bump.py --minor # or force a bump level
# Draft release notes: in Claude Code run /release-notes (collects commits, drafts
# plain-language entries for your review, and only writes CHANGELOG.md once approved).
# Under the hood it calls:
.venv\Scripts\python scripts\release_notes.py --json
The version string lives in one place — [project] version in pyproject.toml;
cim_suite.__version__ reads from it, and the installer takes it via /DAppVersion.
The bump level is computed from commit prefixes, never by an LLM. The changelog prose
is the only LLM-assisted step and is never committed without review. Releases start from
the last vX.Y.Z git tag (or a --baseline <rev> you pass when there's no tag yet).
Cutting a release (order matters — draft notes before bumping, so the suggested version is correct):
/release-notesin Claude Code → review/approve the draft → it writesCHANGELOG.md.python scripts\bump.py→ updatespyproject.toml.git commit -am "chore: release X.Y.Z"(the release commit itself doesn't bump).git tag vX.Y.Zgit push --follow-tags(pushes the commit and the new tag together).
Architecture
Five strictly-ordered layers. The protocol core is pure (no I/O, no Qt) and the device is swappable — this is the central discipline, not an accident.
| Layer | Package | Role |
|---|---|---|
| Shared core | cim_suite/core |
Protocol primitives, transport interface + pyserial reader, theme/design system, config, export engine |
| Protocol (pure) | cim_suite/modules/<id>/protocol |
Framing, decode (frame → dataclass), encode (command → wire string). No I/O; fully unit-tested |
| Transport | cim_suite/modules/<id>/transport |
SimulatedStation in-memory fake; real serial transport lives in core |
| Domain | cim_suite/modules/<id>/domain |
In-memory models, calibration, logging, and the StationController hub |
| UI | cim_suite/modules/<id>/ui |
MainWindow + tabbed thin views that render models and call controller methods |
| Shell | cim_suite/shell |
Entry point, module registry, launcher landing page, suite window |
Data flows one way in, one way out, through the StationController:
transport (reader thread) → controller → framer → decode → models → *Changed signals → UI
UI edit → controller.set_* → encode → transport.write
Note: the modules deliberately do not share a protocol. DA-12 streams big-endian fixed-point
{...}frames unsolicited; DA-07 uses a little-endian, IEEE-754-float, checksummed~...\rdialect over a polled ACK handshake; IOModbus is a standard half-duplex Modbus RTU master driven by a bundled register-map catalog (no proprietary protocol of its own). Seedocs/SUITE-ARCHITECTURE.mdandCLAUDE.mdfor the full rationale.
Documentation
| Doc | What it covers |
|---|---|
CLAUDE.md |
Orientation + working conventions (the best starting point) |
docs/SUITE-ARCHITECTURE.md |
Monorepo / multi-module design |
docs/RUNNING.md |
Running the app |
docs/REBUILD-STATUS.md |
Point-in-time rebuild status |
docs/BACKLOG.md |
Live to-do list |
docs/HARDWARE-VERIFICATION.md |
Protocol details to confirm against real hardware |
docs/DESIGN-SYSTEM.md |
Suite-wide visual standard |
docs/EXPORT.md |
.xlsx export engine + adoption checklist |
docs/VB6-MIGRATION-PLAYBOOK.md |
Reverse-engineering traps from the VB6 port |
CHANGELOG.md |
Human-facing release notes (see Versioning & releases above) |
License
Proprietary — © CIMTechniques. All rights reserved.