Skip to content

Second-capacitor + write_capacitance + review-notes polish#3

Merged
bonev-st merged 1 commit into
mainfrom
feat/write-capacitance
May 19, 2026
Merged

Second-capacitor + write_capacitance + review-notes polish#3
bonev-st merged 1 commit into
mainfrom
feat/write-capacitance

Conversation

@bonev-st
Copy link
Copy Markdown
Contributor

Summary

  • Adds the read_second_capacitance / write_capacitance / write_second_capacitance API for the second HOLD_REG_SECOND_CAP_* pair, with atomic 2-register read/write and uint16-precision-maximising exponent picker.
  • Addresses the May-2026 review notes (P0-P3 in the priority list): fixes the --sp-p semantic mismatch in example.py, rejects ambiguous suffix lookups in Register.from_name(), batches read_many() into contiguous-range reads, and cleans up test layout (shared fakes moved to tests/conftest.py, test_transport.py split into 4 focused modules).
  • CI hardening: least-privilege permissions, PR-only concurrency cancel, workflow_dispatch, Python 3.13 added to the matrix, new build job runs python -m build and twine check --strict.

Test plan

  • python -m pytest -q --cov=smartpower_modbus — 222 tests pass, coverage 89%.
  • python -m ruff check . — clean.
  • python -m mypy smartpower_modbus — clean.
  • python -m py_compile example.py — clean.
  • python -m build + python -m twine check --strict dist/* — both pass.
  • Smoke against real hardware: python example.py --port COMx --slave 1 --model SmartPowerGen_2.0 --sp-p 50 should now write 50% (not 0.50%).
  • smartpower-cli ... write SP_P 50 should now fail with an ambiguity error pointing at INPUT_REG_SP_P vs HOLD_REG_SP_P instead of ReadOnlyRegisterError.

🤖 Generated with Claude Code

- P0: example.py --sp-p now float + write_value(); '50' means 50%, not raw 50 (0.50%).
- P1: Register.from_name() rejects ambiguous suffixes (SP_P, ERROR, CONFIG, ...) with a
  helpful candidate list instead of silently picking the input-reg variant.
- P1: Extracted FakeSerialClient + fixtures from tests/test_transport.py to
  tests/conftest.py; test_capacitance.py and test_units.py no longer cross-import.
- P2: CI hardening — least-privilege permissions, PR-only concurrency cancel,
  workflow_dispatch, Python 3.13 in matrix, new build job runs `python -m build`
  and `twine check --strict`.
- P2: README clarifies retry_writes default + adds Developer checks section
  mirroring CI; doc/SDR-... path references replaced with 'Spec rev A7'.
- P3: Documented low-level write_coil/write_coils caller-responsibility coercion.
- P3: read_many() batches contiguous-address runs by kind into single FC01/02/03/04
  reads (capped at 2000 bits / 125 words), dedupes, validates model up front.
- P3: Split test_transport.py into test_transport_errors.py, test_device_info.py,
  test_client_lifecycle.py — happy-path + batching stays in test_transport.py.

All CI gates pass locally (ruff, mypy, pytest --cov, py_compile, build, twine).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bonev-st bonev-st merged commit db88e68 into main May 19, 2026
5 checks passed
@bonev-st bonev-st deleted the feat/write-capacitance branch May 19, 2026 12:22
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

val, exp = _encode_capacitance(float(value))

P2 Badge Preserve capacitance type validation

When a caller passes True/False (or a numeric string) to write_capacitance()/write_second_capacitance(), this float(value) coercion runs before _encode_capacitance() and bypasses the encoder's explicit non-real/bool rejection, so write_capacitance(True) silently writes a 1.0 F setting instead of raising InvalidValueError and leaving the bus untouched. Pass the original value into _encode_capacitance() (or validate before coercion) so the public write helpers enforce the same checks that the encoder tests document.

ℹ️ 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".

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