Skip to main content

lochinvar-modbus

Read Lochinvar boilers and water heaters fitted with the MODB-I-O Modbus communication board, as typed Python objects, on top of modbus-connection.

Supported devices

The models the board's manual (MODB-I-O Rev N) lists: Knight 81-286, Knight XL 400-801, Armor 151-801, Outdoor Knight / Knight XL / Armor, AQUAS 400-801, FTXL 400-850, Wall Mount 51-211, Wall Hung 55-399, Wall Mount Armor 125-200 and Shield 125-500. It has been run against one Knight Wall Hung (WHB399N) behind a Modbus TCP gateway. The board speaks Modbus RTU at 9600 or 19200 baud (DIP switch 9), no or even parity (DIP switch 10), address set by DIP switches 1-8.

Temperature units: read this

The manual documents every temperature in Celsius: measured values in tenths of a degree, setpoints in half degrees. A boiler whose display is set to Fahrenheit sends Fahrenheit instead: measured values in tenths of a degree and setpoints in whole degrees. Nothing on the bus says which, so you pass it:

from lochinvar_modbus import LochinvarBoiler, TemperatureUnit

boiler = LochinvarBoiler(unit, TemperatureUnit.FAHRENHEIT)

How this was established on a live Fahrenheit boiler: a disconnected sensor reads 9321 (the control's 500 °C open-circuit value, sent as 932.1 °F); its outdoor sensor read 629 on a 63 °F afternoon; and over 60 days its hot-water calls started at about 119 °F and stopped at 125-127 °F against a tank setpoint register of 124, which fits 124 °F, not the 62 °C the manual's scale would give.

What it covers

Component Table Registers What
status input 30001-30016 Discrete inputs (packed), system and outlet setpoints, outlet/inlet/flue temperatures, firing rate, pump speeds, cascade power, status/blocking/lockout codes
bms holding 40001-40008 BMS configuration and command words, rate command, tank setpoint, tank/outdoor/system-supply/DHW-recirculation temperatures

Both tables are read in one block each, two requests per update. The board rejects any read that touches an address it doesn't map, which is why the discrete inputs are read from their packed copies in 30001-30003 rather than the gappy 1xxxx table.

Decoding conventions:

  • A disconnected sensor (the 500 °C open-circuit value) reads None.
  • A setpoint of 0 °C / 32 °F means "no active setpoint" and reads None.
  • Status, blocking and lockout codes decode to StatusCode, BlockingCode and LockoutCode; a code the manual doesn't list stays a plain int, and 32767 ("code not present") reads None.
  • status.lockout only reports a reason while the status code is 40 (lockout); the manual warns the lockout register changes constantly otherwise.

Read-only

The library doesn't write. The BMS registers only take effect once BMS control is made active in the boiler's installer menu, and the boiler then expects the BMS to refresh them every few minutes or it falls back to its own controls. That's a deliberate decision for whoever wires it up, not a default.

Usage

import asyncio

from modbus_connection import ModbusTcpParams
from modbus_connection.tmodbus import ModbusConnection
from lochinvar_modbus import LochinvarBoiler, TemperatureUnit


async def main() -> None:
    connection = ModbusConnection(ModbusTcpParams(host="192.168.1.50", port=502))
    try:
        boiler = LochinvarBoiler(connection.for_unit(1), TemperatureUnit.FAHRENHEIT)
        await boiler.async_update()
        print(boiler.status.status, boiler.status.outlet_temperature)
        print("Tank:", boiler.bms.tank_temperature, "/", boiler.bms.tank_setpoint)
    finally:
        await connection.close()


asyncio.run(main())

Development

uv sync
uv run pytest
uv run ruff check . && uv run ruff format --check . && uv run mypy

The tests run against modbus-connection's in-memory mock backend, seeded with registers captured from a live boiler. No hardware is needed.

License

Unlicense: public domain.

Metadata

Release files for lochinvar-modbus 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lochinvar-modbus 0.1.0
File Size Uploaded Provenance Actions
lochinvar_modbus-0.1.0.tar.gz 13.6 kB With provenance Details for lochinvar_modbus-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for lochinvar-modbus 0.1.0
File Interpreter ABI Platform Actions
lochinvar_modbus-0.1.0-py3-none-any.whl Python 3 none any Details for lochinvar_modbus-0.1.0-py3-none-any.whl

Total release size: 25.0 kB

Release files / lochinvar_modbus-0.1.0.tar.gz

Download URL lochinvar_modbus-0.1.0.tar.gz
Size 13.6 kB
Tags Source
SHA-256 checksum
How to use checksums
7d8fe4df386ff2fd4e943934c7458538f2120604a675b406b41c151b829a8c90
BLAKE2b-256 checksum
How to use checksums
d466b24b4dd3673e6fe2da11f27868d99446c6a7a8ff4024eed63824fee8e825
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / lochinvar_modbus-0.1.0-py3-none-any.whl

Download URL lochinvar_modbus-0.1.0-py3-none-any.whl
Size 11.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ba1b584b0f2c3af7c4315433166e8550707bea7de7699d8285ac1e8b8f39ea66
BLAKE2b-256 checksum
How to use checksums
601d0cf0670dce505206ea6281d12cb1bd1127591b5fff714d068e5bb2f305e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Security for lochinvar-modbus 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for lochinvar_modbus-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page