# CIMTechniques Service Suite A modern Python 3 + [PySide6](https://doc.qt.io/qtforpython/) 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//legacy/`). The outstanding milestone is verification against real DA-12, DA-07, and Modbus hardware. ## Quick start Requires **Windows** and **Python 3.11+**. ```powershell # 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 ```powershell # 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 ```powershell # 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](https://semver.org/) (`MAJOR.MINOR.PATCH`). There are **two records of change, with different audiences**: - **Git history** — the technical record. Every commit uses the [Conventional Commit](https://www.conventionalcommits.org/) format `: `. - **[`CHANGELOG.md`](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 | ```powershell # 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 ` 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//protocol` | Framing, decode (frame → dataclass), encode (command → wire string). No I/O; fully unit-tested | | Transport | `cim_suite/modules//transport` | `SimulatedStation` in-memory fake; real serial transport lives in `core` | | Domain | `cim_suite/modules//domain` | In-memory models, calibration, logging, and the `StationController` hub | | UI | `cim_suite/modules//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`](CLAUDE.md) | Orientation + working conventions (the best starting point) | | [`docs/SUITE-ARCHITECTURE.md`](docs/SUITE-ARCHITECTURE.md) | Monorepo / multi-module design | | [`docs/RUNNING.md`](docs/RUNNING.md) | Running the app | | [`docs/REBUILD-STATUS.md`](docs/REBUILD-STATUS.md) | Point-in-time rebuild status | | [`docs/BACKLOG.md`](docs/BACKLOG.md) | Live to-do list | | [`docs/HARDWARE-VERIFICATION.md`](docs/HARDWARE-VERIFICATION.md) | Protocol details to confirm against real hardware | | [`docs/DESIGN-SYSTEM.md`](docs/DESIGN-SYSTEM.md) | Suite-wide visual standard | | [`docs/EXPORT.md`](docs/EXPORT.md) | `.xlsx` export engine + adoption checklist | | [`docs/VB6-MIGRATION-PLAYBOOK.md`](docs/VB6-MIGRATION-PLAYBOOK.md) | Reverse-engineering traps from the VB6 port | | [`CHANGELOG.md`](CHANGELOG.md) | Human-facing release notes (see _Versioning & releases_ above) | ## License Proprietary — © CIMTechniques. All rights reserved.