Skip to main content

Release Stargazers codecov

Contributors Forks Issues

MIT License


luxmodbus

Framing, register map, and discovery for the LuxPower inverter Modbus protocol.


Report Bug · Request Feature
Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. The Frame
  5. Provenance
  6. Contributing
  7. License

About The Project

luxmodbus is a small, dependency-free Python library for the LuxPower inverter Modbus protocol — packet framing, the declarative register map, and register discovery. It has no Home Assistant dependency and is the protocol core consumed by the Lumen Home Assistant integration. Because it imports nothing from Home Assistant, it can be tested entirely offline against captured packet bytes.

Status

Early. Implemented so far:

  • protocol.py — frame encode/decode (LuxPower TCP envelope + inner Modbus RTU data frame), read/write request builders, and read-response unpacking. No I/O, no register-meaning knowledge.
  • registers.py — declarative address → meaning map (the single source of truth) with a decode engine and a bounds-checked encode_value for writes.
  • discovery.py — passive diff-and-log engine: compares observed registers against the known map and records the unknown with a rolling value history.

(back to top)

Getting Started

This project uses uv.

git clone https://github.com/totaldebug/luxmodbus.git
cd luxmodbus
uv sync
uv run nox -s tests

(back to top)

Usage

from luxmodbus import Frame, decode_inputs

frame = Frame.decode(raw_bytes)          # validates prefix + CRC
data = frame.data_frame()                # inner Modbus frame
# raw register values -> {key: scaled value}
values = decode_inputs({1: 2503, 4: 530, 5: (90 << 8) | 88})
# {"pv1_voltage": 250.3, "battery_voltage": 53.0, "soc": 88, "soh": 90}

(back to top)

The Frame

LuxPower wraps a modified Modbus RTU "data frame" inside a TCP envelope:

prefix(2)=A1 1A | protocol(u16 LE) | frame_length(u16 LE) | reserved(1)=01 |
tcp_function(1) | dongle_serial(10) | data_length(u16 LE) | data_frame(N) | crc16(u16 LE)
  • frame_length = total_len - 6
  • data_length = len(data_frame) + 2 (the trailing CRC)
  • crc16 is the standard Modbus CRC (poly 0xA001, init 0xFFFF) over the data frame, appended little-endian.

The inner data frame:

action(1) | device_function(1) | inverter_serial(10) | register(u16 LE) | value

See docs/capturing-packets.md for how to capture real packets and turn them into test fixtures.

(back to top)

Provenance

Clean-room: the protocol facts (field layout, CRC algorithm, function codes, register meanings) are taken from the official Lux Power Modbus RTU specification and validated against real packet bytes. No code is copied from other implementations.

(back to top)

Contributing

Contributions are welcome. Please open an issue first to discuss changes, then ensure uv run nox -s tests passes (style, types, docstring coverage, and the test suite) before opening a PR.

(back to top)

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

Metadata

Release files for luxmodbus 0.3.1

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

Source distribution (sdist)

Source distribution for luxmodbus 0.3.1
File Size Uploaded
luxmodbus-0.3.1.tar.gz 25.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for luxmodbus 0.3.1
File Interpreter ABI Platform
luxmodbus-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 53.6 kB

Release files / luxmodbus-0.3.1.tar.gz

Download URL luxmodbus-0.3.1.tar.gz
Size 25.8 kB
Tags Source
SHA-256 checksum
How to use checksums
0442bdab1029e922705b8d6701ab96f7ba6c97b47e23ae21b517ca81d7b07fce
BLAKE2b-256 checksum
How to use checksums
d71cc1d6a5cc9505cb84f6262b228268500873b5e3ded0785f00cd4162e6c221
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / luxmodbus-0.3.1-py3-none-any.whl

Download URL luxmodbus-0.3.1-py3-none-any.whl
Size 27.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fd861574f76cf608220cce8a89ef8135de78fa2aaaf45f0d8ecd65b643b289ad
BLAKE2b-256 checksum
How to use checksums
07c28508d48281890b5caaa58a1b5e7b6cdd27d254784a39ace0a959e2d5f606
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

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