We recently had a Growatt MIN 11400TL-XH-US inverter and associated battery system installed as part of our solar power system. It all seems quite reasonable, except that its IoT presence is aggressively tied to the cloud. I’d like it not to be. There’s https://github.com/johanmeijer/grott, for an off-the-shelf approach to this problem, but I was not sufficiently enamored of its implementation to want to run it myself. Nevertheless, it has been a useful resource for cross-checking my understanding of Growatt’s protocols.

Please understand that there may be mistakes in the following and it is still mostly the result of educated guesses from packet dumps. There are no warranties associated with this text, not even implied ones.

Connectivity

The inverter’s datalogger – apparently fully integrated, in the case of MIN devices – can be programmed to connect to one of four endpoints, by DNS:

  1. server.growatt.com

  2. server-us.growatt.com

  3. server-cn.growatt.com

  4. server.smten.com

It does so on ports 5279 and 5280. I do not know what transpires on port 5280.

Modified Modbus Header

The TCP stream established to port 5279 is reminiscent of “Modbus over TCP/IP”. Every message, in each direction, begins with an 8-byte header and ends with a 2-byte checksum. Multi-byte fields in the header are MSB-first (that is, network-endian).

The checksum is performed with the standard Modbus CRC-16 polynomial, but is, unlike in Modbus RTU serial streams, here transmitted MSB-first.

Protocols

Growatt uses protocol identifiers 6 (and 5, apparently?) to indicate a… let’s say lightly obfuscated payload. Specifically, all post-header non-checksum bytes are xor’d with the mask “Growatt” (in ASCII). The checksum is computed using the obfuscated contents, not their “plaintext”.

Function Codes

0x03 and 0x04: Register Dumps

The datalogger periodically generates, without in-band stimulus, function code 0x03 and 0x04 messages. The payload of these messages appear to consist of a 67-byte header followed by an array of register report structures. The initial header contains…

  • A 30-byte, NUL-terminated, right NUL-padded ASCII string of the datalogger’s serial number.

  • A 30-byte, NUL-terminated, right NUL-padded ASCII string of the inverter’s serial number.

  • A 6-byte date and timestamp. The format for this is Y M D H M S with most fields being straightforward. Y takes the year 2000 as its zero value. M encodes January as 1 and counts from there; D also counts from 1.

  • A 1-byte count of subsequent register report structures.

A register report structure consists of a 4-byte fixed header followed by an array of 2-byte, MSB-first register values. The header contains two 2-byte, MSB-first fields, the minimum (inclusive) and then maximum (inclusive) register indices to follow. See the document “Growatt PV Inverter Modbus RS485 RTU Protocol v120” for the defined list of registers.

Function code 0x03 gives registers in the “holding register” namespace, while 0x04 gives registers in the “input register” namespace.

The server replies with its own corresponding 0x03 or 0x04 message, with the same transaction identifier, containing a single byte payload of 0x00 (but obfuscated, of course, as 0x47 or G).

0x16: Ping

Ping messages will be echoed exactly by the server, including an unchanged transaction identifier.

In practice, it looks like the datalogger sends identical payloads for each ping: the same 30-byte string encoding of its serial number as above followed by two zero bytes.

0x18: Server-Initiated Command

Function code 0x18 is observed coming from the server.

0x19: Datalogger Identification

These short messages consist of the same 30-byte string encoding of the datalogger’s serial number followed by a 4-byte header and a variable length payload. The header is two 2-byte MSB-first fields: a key and the length of the payload string. The known keys are as follows:

Key

Payload

4

Update interval in minutes, as decimal value (e.g., “5.0”)

8

Datalogger alias (defaults to serial number)

14

Datalogger IP address (dotted quad format)

16

Datalogger MAC address

18

Server TCP port

19

Server DNS name

21

Firmware version string

The server occasionally replies with its own 0x19 message.