Modbus register maps you can validate.
Vendor documentation for Modbus devices arrives as PDFs, spreadsheets and the occasional scanned image. It is inconsistent, frequently wrong, and almost never states the things a client actually needs — the address convention, the byte order, whether a value was measured or merely transcribed. ModbusHub turns that material into structured data that can be diffed, validated in CI, and consumed by tools.
Status: draft. The v0.4 schema is still moving and no catalog release has been cut. Pin a commit if you build against it.
The gap between the second and third numbers is the honest summary of this project's state: almost everything here is transcription, not measurement. Every row says which it is.
The two numbers
Modbus's oldest trap is that the number printed in a vendor PDF is often not the number that goes on the wire. This catalog does not guess. It defines two columns, and the relation between them is fixed by definition:
Register = Address + 1 Address the value placed in the Modbus PDU starts at 0 Register the published ordinal starts at 1
What varies between documents is only which column the vendor printed. That is declared once per source file, with an anchor a reviewer can check against the PDF:
source:
addressing:
documented_as: "register"
evidence: "hardware_verified"
anchor:
documented: 3019
expect_label: "Power Meter Manufacture Date/Time"
Source files store the number exactly as printed, under the vendor's own column name. The import scripts perform no arithmetic — the other column is derived at build time. Review stays mechanical: open the PDF, compare, the numbers match.
Evidence, not assertion
Every claim carries its provenance, and the level is recorded per register, not per file. A map may mix levels; a reader must always be able to tell which rows were measured and which were only read off a page.
- printed
- the document says so explicitly
- frame_example
- the document shows a wire-level frame
- structural
- it follows necessarily from the data
- inferred
- only third-party implementations agree
- hardware_verified
- it was measured on a real device
- unverified
- unknown
A map whose addressing evidence is unverified cannot be promoted to
verification.status: tested. The validator enforces it.
Contradictions are declared
Vendor documents contradict themselves. When they do, the contradiction is written down rather than quietly corrected — the validator refuses an address overlap that has not been declared.
A real one, from an ENTES MPR register table: the Format column says
uint64 while Word Counts says 2. Address spacing settles it, and
an older edition of the same table independently confirms the resolution.
document_errors: - id: type-98 registers: [98] kind: type_conflict documented: "Format = uint64, Word Counts = 2" resolution: use_documented
The same mechanism records when two firmware editions of one table assign different meanings to the same address — a failure that returns a plausible wrong number rather than an error.
Checks travel with the data
A register map tells you where a value lives. It does not tell you whether the installation is sane. Commissioning check lists reference measurements, never addresses, so one list runs against a Schneider meter, an ENTES analyzer or a KAEL controller unchanged:
- id: WIR1 severity: error reads: [active_power.phase.*] rule: "all_same_sign(active_power.L1, active_power.L2, active_power.L3)" on_fail: "One phase draws power in the opposite direction — reversed CT or wrong voltage reference."
Checks carry provenance too. evidence: means the check was run on real hardware
and this was the result; basis: means a vendor document supports it but nothing
has been measured. A check claiming both is rejected.
What is in the catalog today
Nine devices across three manufacturers. This table is generated from the catalog itself, so it cannot drift from what is actually in the repository.
| Manufacturer | Device | Category | Registers | Verification |
|---|---|---|---|---|
| Schneider Electric | PM810 | Power meter | 1,056 | 14 measured |
| ENTES | MPR 3X-4X | Power analyzer | 1,921 | document only |
| KAEL | MULTISER-01-PC-TFT | Power analyzer | 2,426 | document only |
| KAEL | MULTISER-02-PC-TFT | Power analyzer | 2,472 | document only |
| KAEL | MULTISER-03-PC-TFT | Power analyzer | 2,630 | document only |
| KAEL | MULTISER-04-PC-TFT | Power analyzer | 3,011 | document only |
| KAEL | MULTISER-05-PC-TFT | Power analyzer | 3,014 | document only |
| KAEL | VARkombi-18-PC-TFT | PF controller | 1,385 | document only |
| KAEL | VARkombi-12-PC | PF controller | 185 | document only |
The full list, with per-map evidence breakdowns and every declared contradiction, is in
devices.md.
What is not done yet — starting with a live capture tool that makes promotion from
printed to hardware_verified mechanical — is in
ROADMAP.md.
Get started
git clone https://github.com/ModbusHub/registry.git cd registry python3 -m pip install -r tools/requirements.txt python3 tools/validate.py # schema + cross-file rules python3 tests/run.py # valid fixtures pass, invalid ones must fail python3 tools/export.py # build dist/catalog.json
Adding a device? Start with the
device authoring guide
(Türkçe) —
a step-by-step walk from a vendor PDF to a validated entry, using the hardware-verified
PM810 as the worked example. The short version: transcribe the vendor's numbers verbatim,
declare documented_as, provide an anchor, and never silently shift an address.