Skip to content

test/hardware validation suite#4

Merged
bonev-st merged 3 commits into
mainfrom
test/hardware-validation-suite
May 22, 2026
Merged

test/hardware validation suite#4
bonev-st merged 3 commits into
mainfrom
test/hardware-validation-suite

Conversation

@bonev-st
Copy link
Copy Markdown
Contributor

  • Add CLAUDE.md, requirements files, and How-to-use quickstart
  • Fix every Modbus transaction failing on pymodbus 3.13
  • Add live-hardware validation test suite (opt-in)

Stanimir Bonev and others added 3 commits May 22, 2026 11:07
CLAUDE.md captures the five-layer architecture, the model ↔ branch ↔
PRODUCT_CODE invariant, and the per-model register quirks so future
sessions don't have to re-derive them from the source.

requirements.txt / requirements-dev.txt mirror the runtime and [dev]
extras in pyproject.toml for bare environments that don't install the
package itself; pyproject.toml remains the source of truth.

README gains a top-level "How to use" quickstart that links into the
existing Library usage / CLI / Auto-detection sections instead of
duplicating them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pymodbus 3.13 added `exception_code` as a default attribute on every
response object — initialised to 0 on the success path. The transport
guard checked `getattr(response, "exception_code", None) is not None`,
which now matches a successful response, falls through every code
branch in `_raise_exception_response`, and raises a generic
`ModbusCommError("Modbus exception response 0x00")`.

The fix is to check truthiness: valid Modbus exception codes are
0x01..0x04, so any zero value means "no exception".

Confirmed live: before the fix, `smartpower-cli read INPUT_REG_IN_V`
against a real SmartPowerSolo failed with the 0x00 error even though
pymodbus had decoded a healthy response. After the fix the same read
returns the register value cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A new tests/hardware/ tree exercises the Modbus client end-to-end
against a real SmartPower module over RS-485. Default `pytest -q`
skips the whole suite — the gate is a marker (`hardware`,
`hardware_write`, `hardware_fault`) plus a matching CLI opt-in
(`--hardware`, `--allow-writes`, `--allow-fault-injection`) declared
in tests/conftest.py.

Coverage:
- test_smoke.py: port open, FC 0x2B identify, product-code ↔ model
  agreement, probe_model candidates, baseline read, HEAT safety bit.
- test_register_sweep.py: full dump() of the resolved model, type +
  signed/unsigned range sanity per register, repeat-sweep determinism,
  temperature plausibility (logged, non-fatal).
- test_writes.py: round-trip writes on an allowlist of non-actuating
  registers (HS_RATIO, REQ_PROFILE, TIMER_SP) and the capacitance
  pair. Every test reads + prints the original, target, readback, and
  restored value, and a try/finally guarantees restoration.
- test_fault_recovery.py: illegal-address via 0x3FFF, illegal-function
  via FC 0x2B read_code=0x04 (firmware ships with MEI_DEV_ONE_OBJ_ENA
  disabled), sub-ms timeout injection, retry-exhaustion check,
  interleaved-fault recovery sweep.

PLAN.md and README.md in tests/hardware/ document the design (gating,
safety rules, allowlists) and the operator workflow.

Markers are registered in pyproject.toml so pytest does not warn
about unknowns.

Verified against a real SmartPowerSolo (FW 2.54, /dev/ttyUSB0,
slave 1): 17 passed + 2 xfailed (1 ms timeout against a slave fast
enough to beat the deadline — the documented escape hatch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bonev-st bonev-st merged commit bb2469e into main May 22, 2026
5 checks passed
@bonev-st bonev-st deleted the test/hardware-validation-suite branch May 22, 2026 08:54
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3791c36eff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/conftest.py
Comment on lines +116 to +118
if not hardware:
item.add_marker(skip_no_hardware)
continue
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor implied hardware flags before global hardware skip

pytest_addoption advertises --allow-writes and --allow-fault-injection as implying --hardware, but pytest_collection_modifyitems checks if not hardware first and skips all marked tests before those flags are considered. In practice, running pytest --allow-writes --port=... tests/hardware/test_writes.py silently skips the write suite, which can give false confidence in automation because the command exits without exercising hardware tests.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant