Skip to main content

growatt-protocol

The protocol a Growatt datalogger speaks to its server over TCP 5279, as a standalone Python library. Framing, obfuscation, checksums, record decoding, register semantics, and the commands for reading and writing inverter registers.

No dependencies. Standard library only, no compiled extension, so it installs anywhere Python runs. A test walks the source and fails on any import outside the standard library, so that stays true.

pip install growatt-protocol

Records are self-describing

The useful thing about this protocol, and the reason this library is small: a telemetry record states the Modbus register ranges it carries.

datalogger serial | inverter serial | timestamp | group count | group…
group := start register (2B) | end register (2B) | one 16-bit word per register

So decoding reads register numbers off the wire rather than indexing a per-model table of byte offsets. That is what lets a handful of register profiles replace the dozens of model-specific layout files other implementations need, and it means a malformed record fails loudly instead of decoding into plausible-looking nonsense.

Decoding a record

from growatt_protocol import Frame, Framer, parse_register_record
from growatt_protocol.registers import decode_registers, resolve_profile

framer = Framer()  # TCP splits and coalesces; reassembly is required
for raw in framer.feed(chunk):
    payload = parse_register_record(Frame(raw))
    match = resolve_profile([(g.start, g.end) for g in payload.groups])
    decoded = decode_registers(match.profile, payload.registers)

    print(payload.inverter_serial, decoded.values["output_power"], "W")

Register meaning varies by inverter family — register 13 is PV3 power under one protocol, grid frequency under another, battery charge power on an off-grid unit — but the group range identifies the block, so resolve_profile picks the right one from the record itself. The exception is the off-grid SPF series, whose 0-based block is indistinguishable from Protocol II; that one has to be passed as an override.

Running a server

import asyncio
from growatt_protocol import GrowattServer, ServerConfig


def on_record(record):
    print(record.payload.inverter_serial, record.payload.registers)


async def main():
    server = GrowattServer(ServerConfig(port=5279), on_record=on_record)
    await server.start()
    await asyncio.Event().wait()


asyncio.run(main())

The server answers what a datalogger expects: acknowledgements before decoding, ping echoes, and — importantly — a clock update after the device announces itself. Without that last one a datalogger announces, waits, gives up and reconnects forever, never sending a single telemetry record.

Testing without hardware

from growatt_protocol.testing import FakeDatalogger

device = FakeDatalogger(chunk_size=1)  # one byte per write, to prove reassembly
await device.connect("127.0.0.1", server.port)
await device.send_data()

FakeUpstream stands in for the Growatt cloud, and can be killed mid-session to exercise relay fallback.

License

MIT, except the register definitions under registers/, which are Apache-2.0 and derived from Homeassistant-Growatt-Local-Modbus. See NOTICE. This project is not derived from johanmeijer/grott, which carries no license; full provenance is recorded in the repository.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

growatt_protocol-0.4.0.tar.gz (60.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

growatt_protocol-0.4.0-py3-none-any.whl (57.6 kB view details)

Uploaded Python 3

File details

Details for the file growatt_protocol-0.4.0.tar.gz.

File metadata

  • Download URL: growatt_protocol-0.4.0.tar.gz
  • Upload date:
  • Size: 60.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for growatt_protocol-0.4.0.tar.gz
Algorithm Hash digest
SHA256 199ed3004bc1c9f502c8a7f9ae635e21b7eaa8107fcc35dbccc41e5aa9340239
MD5 f43368e97e85578b3a3958bb13bd1d28
BLAKE2b-256 a714ff31e7008b08cb3a26cd1b3b9b42dc685a3d43babe15d5ae430e063eba96

See more details on using hashes here.

Provenance

The following attestation bundles were made for growatt_protocol-0.4.0.tar.gz:

Publisher: publish.yml on FezVrasta/growatt-datalogger

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file growatt_protocol-0.4.0-py3-none-any.whl.

File metadata

File hashes

Hashes for growatt_protocol-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 355eb3ed88fabd25c447cdad7e300fa5e3deee9fd03df95a3f3b9a22dab79bb1
MD5 5050a1eac37126d14e580bae75667a3d
BLAKE2b-256 796869f8c66310500618aec7708e8a08d406257212af1ffc05196789cbfd4418

See more details on using hashes here.

Provenance

The following attestation bundles were made for growatt_protocol-0.4.0-py3-none-any.whl:

Publisher: publish.yml on FezVrasta/growatt-datalogger

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

This release

0.4.0 This release

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 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