Skip to main content

mygrid-modbus

A standalone async Python device library for MyGrid ModuleTwo batteries, implementing manufacturer register map version 2. Requires Python 3.12+.

The library uses modbus-connection component models. Applications supply a ModbusUnit, choose the transport backend, and own the connection lifetime. No application framework is required. Install it from PyPI; the source is on GitHub.

Installation

python -m pip install 'mygrid-modbus[tmodbus]'

From a checkout of this repository: python -m pip install '.[tmodbus]'.

Install the base package without extras when the consuming application supplies its own unit. The optional [pymodbus] extra selects the other supported backend.

Query a battery

The helper is read-only; it never sends power or restart commands:

uv sync --frozen
uv run script/query.py 192.168.1.20 --port 502
uv run script/query.py 192.168.1.20 --port 502 --raw
# The installed distribution also provides mygrid-query.

--raw includes an address-keyed register dump, suitable for replay in tests with mock_modbus_unit.load_raw(payload['registers']). The helper uses modbus_connection.cli_helper for connection arguments and backend selection. Only the documented TCP socket transport is offered. Unit ID is fixed to 1.

Device API

import asyncio

from modbus_connection import ModbusTcpParams
from modbus_connection.tmodbus import ModbusConnection
from mygrid_modbus import MyGridDevice


async def main() -> None:
    connection = ModbusConnection(ModbusTcpParams(host="192.168.1.20", port=502))
    try:
        device = MyGridDevice(connection.for_unit(1))
        report = await device.async_update()
        if "battery" in report.updated:
            print(device.battery.stored_energy)  # typed component attribute
            print(device.snapshot)  # immutable, validated readings
        if report.failed:
            print(report.failed)
        # Explicit commands only, if this application is the power controller:
        # accepted = await device.async_set_power(100)
        # await device.async_set_power(0)
        # await device.async_restart()
        raw = await device.async_read_raw()
        print(raw)
    finally:
        await connection.close()


asyncio.run(main())
API Contract
MyGridDevice(unit) Device composed of a typed Battery component
async_update() Returns UpdateReport; one pooled read of holding registers 0–17
battery Component with declarative signed/scaled/low-word-first fields
snapshot Last fully validated BatteryData; raises before the first good read
async_read() Convenience validated snapshot read; raises on failure
async_set_power(watts) Fresh limits, one validated write, confirmed readback
async_restart() One function-06 write of value 1 to register 9
async_read_raw() Fresh raw words grouped by Modbus space, replayable by the mock

Power is in W, energy in Wh. Positive power charges; negative power discharges. A setpoint is a signed I16 value in 100 W increments and must fall within fresh device limits. A readback confirms acceptance, not actual power delivery.

Status 0 means normal, 1 fault and 2 telemetry stale. The immutable snapshot suppresses SOC, measured power and faults when status is 2; other valid fields remain available. Raw dumps preserve exactly what the device returned. When a poll fails, inspect its report before treating cached component values or the last snapshot as current. An unsupported map or invalid SOC/status fails the component instead of publishing corrupt measurements.

MyGridError, UnsupportedMapError and InvalidSetpointError extend the neutral ModbusError hierarchy. Transport connection/timeouts retain their typed backend-neutral exceptions. Raw diagnostics raise the same errors. Operations have a 12-second budget after this device's lock is acquired; the device requests a minimum 3-second request timeout through its unit. The owner resolves timing requirements across consumers.

The library never closes or disconnects the supplied unit, even on a failed command or cancellation. Both supported backends disable write retransmission. The device retains no desired setpoint and never replays commands. A failed confirmation can mean the write was applied; read the battery before manually deciding to issue another command.

Use async_set_power() for live-limit validation. Component field metadata describes writable fields and static validators, while the device method handles fresh limits and readback. All other registers are read-only except restart. The component constrains reads to the documented range and uses low-word-first U32 fields, including high fault bits.

Device prerequisites

Enable external control in the manufacturer's app before connecting; otherwise the TCP port is closed. Use the same LAN and the Auto leader for a cluster. The battery accepts one TCP client at a time, so share a connection between local consumers. Choose one writer: sharing the socket does not arbitrate competing power strategies.

There is no TLS/authentication, serial transport, firmware-update API, hardware identity, follower enumeration or documented disconnection watchdog in this map. Keep port 502 on the trusted LAN. Closing the connection does not request idle. Cluster SOC, limits and setpoints have documented aggregate meanings; energy aggregation is not established by the manual. See protocol details.

Development and release

uv sync --frozen
uv run ruff check .
uv run ruff format --check .
uv run ty check .
uv run pytest --cov=mygrid_modbus
uv build
uv run twine check dist/*
uv run python scripts/check_artifacts.py

Tests use the supplied mock_modbus_unit/mock_modbus_connection pytest fixtures for models, failures and replayed dumps. Independent raw-frame TCP tests exercise both real backends, clamping, lost acknowledgments and connection sharing. CI covers Python 3.12–3.14 and built-wheel installation, including base imports without backend extras.

Live smoke tests

With a ModuleTwo that has Modbus TCP enabled, check that it still speaks register map 2:

MYGRID_HOST=192.168.0.15 uv run pytest -m live

They are read-only (no setpoint or restart is ever sent), skipped without MYGRID_HOST, and excluded from ordinary runs. A failure is classified as DEVICE UNAVAILABLE (cannot connect or no answer), DEVICE INCOMPATIBLE (unusable data) or DEVICE USES AN UNSUPPORTED REGISTER MAP. These tests have never passed yet: the ModuleTwo used for development refuses connections on port 502.

Release instructions describe tag-based versions, trusted publishing and the required pypi environment. Publishing is not performed by local validation. The Apache-2.0 license covers original code; the manufacturer manual is included unmodified as docs/mygrid-modbus-tcp-manual-en.md and remains MyGrid's. Physical hardware validation remains pending.

Metadata

Release files for mygrid-modbus 0.1.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 mygrid-modbus 0.1.1
File Size Uploaded Provenance
mygrid_modbus-0.1.1.tar.gz 72.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for mygrid-modbus 0.1.1
File Interpreter ABI Platform
mygrid_modbus-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 87.5 kB

Release files / mygrid_modbus-0.1.1.tar.gz

Download URL mygrid_modbus-0.1.1.tar.gz
Size 72.7 kB
Tags Source
SHA-256 checksum
How to use checksums
6d712fa0bee4b584bc39498c7e701b03ae44b96f67fd3a1adf7760a16453087a
BLAKE2b-256 checksum
How to use checksums
3ea86325add53aa0a91a2e61a4ae144b45060c1ac8d210286e66c358694eef13
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 24, 2026.

Transparency log

Release files / mygrid_modbus-0.1.1-py3-none-any.whl

Download URL mygrid_modbus-0.1.1-py3-none-any.whl
Size 14.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
373816357077c363b40cc21bd0e55d724ca54d566cd6cef40ad022c2d41f1e0e
BLAKE2b-256 checksum
How to use checksums
9694cb99652870ea3249327e15e647f1974f0966b1f8f1ee6580b5ea3bc583fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 24, 2026.

Transparency log

Security for mygrid-modbus 0.1.1

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

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for mygrid_modbus-0.1.1.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 24, 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.1 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