Files
opcda-diagnozer/CHANGELOG.md
T
2026-10-08 06:30:54 +02:00

5.0 KiB
Raw Blame History

Changelog

All notable changes to the OPC DA Diagnozer are documented here. The format follows Keep a Changelog; versions bump per SemVer. Dates are YYYY-MM-DD.

[Unreleased]

Added — server discovery & browsing

  • list-servers verb: enumerates OPC DA servers locally or on a DCOM host via the Automation Wrapper (GetOPCServers), with a no-COM registry-scan fallback (--source registry|automation|auto), JSON output, and DA-version metadata.
  • Browsing of the connected server's address space, unified in the list-items [all|branches|tags] verb: all prints the full structure tree (branches with /, tags with [ItemID: ...]), branches the structure-only flat list, tags the flat ItemID list for config tags:. --branch (dotted path or repeated segments), --depth N (1 default, 0 = whole subtree), --json. Replaces the earlier split list-devices/list-tags.
  • browse.max_depth config key (default 32) as the address-space walk guard, validated by check-config; cycle-safe tree walk in opc/browse.py.
  • SpaceNode tree data model (branch/leaf) replacing the earlier device-centric DeviceInfo.

Added — reading & CLI

  • read verb: one-shot read of explicit tags (or the config's tags) with a table or --json, --source device|cache, and a non-zero exit when any tag doesn't read GOOD — scriptable as a health check.
  • probe verb: connect once and read every configured tag once.
  • --server / --host overrides on every connecting verb; with --server no config file is needed at all.
  • Frozen-exe default config path: config.yaml next to the exe (a Windows service starts with CWD = System32), not the working directory.

Added — monitoring design (D16) & config

  • devices: config section with DeviceEntry(name, tag, ok_values): D16 device-link indicators. The normal (connected) reading is configurable per indicator (ok_values, default [true]) — inverted fault flags [false, 0] and string states ["RUN"] are first-class. Strict validation: duplicate indicators and indicator/tag-list overlap are rejected; check-config prints the indicators.
  • Detection rules D16 (DEVICE_LINK_DOWN/DEVICE_LINK_UP) and the plain-text anomaly log reporter (report/textlog.py task) specified in the docs (SPECIFICATION §6.1, §9.1; IMPLEMENTATION_PLAN Phases 1–2) — implementation pending, see TODO.md.
  • Clear-text status rule (spec §7): every reporter writes NAME (0xNN) — e.g. BAD / communication failure (0x18).

Added — packaging

  • scripts/build_exe.ps1: PyInstaller build of the 32-bit console exe with hidden imports for the deferred COM modules (incl. win32timezone — see Fixed), embedded version metadata, a PE-bitness check, and smoke tests including a frozen-read canary against a live server.
  • --version and this CHANGELOG.md / TODO.md.

Fixed

  • COM lifecycle: all COM references (browsers, groups, items) are released inside the apartment before CoUninitialize; retained exception tracebacks are cleared in as_com_error — both caused "Win32 exception occurred releasing IUnknown" noise and hard crashes at exit.
  • Frozen exe: every tag read failed with SystemError: ... InvokeTypes ... exception set because pywin32 lazily imports win32timezone during VARIANT-DATE conversion and PyInstaller never bundles it — now a hidden import, with the build canary guarding it.
  • Reads: per-tag failures now carry the underlying exception's own type and text (_per_tag_error) instead of a bare "failed"; a degenerate device timestamp (never-updated alias, DST math) can no longer fail a read — the timestamp is metadata and is dropped to None.
  • Matrikon browse quirk: servers may return an empty ItemID for special leaves (alias roots); the adapter falls back to the bare browse name.
  • HRESULT labels: OPC_E_UNKNOWNITEMID (0xC0040007) and OPC_E_INVALIDITEMID (0xC0040008) were swapped; now corrected everywhere.

Verified

  • All CLI verbs live-tested against Matrikon OPC Simulation Server (Matrikon.OPC.Simulation.1): discovery, browse (all kinds/depths), reads (incl. alias tags after server-side alias repair), config-driven max_depth, and the frozen exe (onedir + onefile) including the read canary.
  • Test suite: 108 tests, all passing (pure logic + fake-client driven, runs on any OS; COM paths are live-smoke-tested on dev boxes only).

[0.1.0] - 2026-10-07

Added

  • Initial project skeleton: typed YAML config with strict actionable validation (check-config), OPC DA quality decode tables (spec §7), event model skeletons (DiagEvent, D1–D15 EventKinds), client/protocol abstractions, and the fake in-process client powering cross-OS tests.
  • Phase 0 decisions recorded: 32-bit interpreter mandatory (Automation Wrapper is a 32-bit in-proc DLL), ruamel.yaml over PyYAML (no 32-bit cp314 wheels), COM imports import-guarded for cross-OS test runs.