2026-06-06 12:18:10 -04:00

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):

  1. /release-notes in Claude Code → review/approve the draft → it writes CHANGELOG.md.
  2. python scripts\bump.py → updates pyproject.toml.
  3. git commit -am "chore: release X.Y.Z" (the release commit itself doesn't bump).
  4. git tag vX.Y.Z
  5. git 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 ~...\r dialect 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). See docs/SUITE-ARCHITECTURE.md and CLAUDE.md for 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.

Description
A unified, modern architecture rebuild of the DA-12 and DA-07 service tool and IOModbus apps (with the ability to add further modules as needed).
Readme 12 MiB
Languages
Python 57.9%
Visual Basic 6.0 41.8%
PowerShell 0.2%
Inno Setup 0.1%