diff --git a/doc/hoymiles-format-description.txt b/doc/hoymiles-format-description.txt index 2559e698..7ed155d0 100644 --- a/doc/hoymiles-format-description.txt +++ b/doc/hoymiles-format-description.txt @@ -1,11 +1,11 @@ -Goal of this Document -===================== +About this Document +=================== This description aims to document the data format that Hoymiles micro inverters use to communicate their current operating state. The original Hoymiles setup requires connectivity to "the cloud", -see [this chapter](#system-description). +see [this section below](#system-description). With the information documented here, it is possible to interact with a set of Hoymiles micro inverters in a purely "offline" way, i.e. @@ -13,11 +13,11 @@ without requiring internet access or any connectivity to a "cloud". The only required hardware is a Nordic "NRF24L01+" wireless module. -The `ahoy` project at [ahoy] collects software for various platforms, +The `ahoy` project at [5] collects software for various platforms, including Aduino and RaspberryPi. -> Note: Some of the sections in this document are (still) in German. Translation -> will be provided if and when necessary. +> Note: Some of the sections in this document are (still) in German. Translations +> may be provided if and when necessary. Origin, Contributors @@ -44,7 +44,7 @@ Here's a list of some of the early contributors: - Thomas B. (tbnobody): protocol analysis, logging - Arnaldo G. (arnaldo_g): data capturing - Oliver F (of22): protocol analysis, logging -- Martin G. (petersilie): protocol analysis, logging +- Martin G. (petersilie): protocol analysis, logging, RaspberryPi @@ -56,7 +56,8 @@ Ein Setup wie von Hoymiles vorgesehen, sieht wie folgt aus: - Eine "DTU" kommuniziert mit vielen Wechselrichtern. - Die Kommunikation geht immer von der DTU aus: DTU stellt Anfrage und erwartet eine Antwort vom WR. -- Dafür muss die DTU die Adressen aller WR kennen. +- Dafür muss die DTU die Adressen (=Seriennummern) aller WR kennen. +- Diese werden der DTU im Rahmen eines Einrichtungsprozesses beigebracht. ``` Nordic @@ -67,20 +68,20 @@ Ein Setup wie von Hoymiles vorgesehen, sieht wie folgt aus: +-------+ +-----------+ | DTU | | MI-600 | +-------+ +-----------+-+ - | MI-600 | + | MI-1500 | +-----------+-+ - | MI-1500 | + | MI-... | +-----------+ - : - : + : + : ABBILDUNG 1: Systemübersicht ``` ``` - Nordic - WLAN "Enh. Shockburst" - 2.4 GHz + Nordic + WLAN "Enh. Shockburst" + 2.4 GHz \|/ \|/ | | +---------+ +-----------+ @@ -97,9 +98,9 @@ Ein Setup wie von Hoymiles vorgesehen, sieht wie folgt aus: ``` - Nordic - "Enh. Shockburst" - NRF24LE1E 2.4 GHz + Nordic + "Enh. Shockburst" + NRF24LE1E 2.4 GHz +------------------+ \|/ +----------+ | | | | | GD32F303 | <----->| µC | NRF24L01+ |-------+ @@ -114,7 +115,7 @@ Ein Setup wie von Hoymiles vorgesehen, sieht wie folgt aus: Adressierung ============ -Die Seriennummern der DTU und der WR werden wie folgt in Adressen für die +Die Seriennummern der DTU und der WR werden wie folgt als Adressen für die Kommunikation verwendet: **Interne Kommunikation**: Die meisten Datenpakete enthalten Quell- und @@ -129,7 +130,7 @@ Innerhalb der Pakete auf (C) wird daraus die 4-Byte-Adresse der letzen 8 Dezimalziffern. **NRF24 addressing scheme**: Over the air, the inverters communicate using -the Nordic "Enhanced Shockburst" [3] Protocol configured for +the [Nordic "Enhanced Shockburst" Protocol][3] configured for 5-byte addresses. The inverter serial number is converted into a "Shockburst" address @@ -147,9 +148,10 @@ In this example, the resulting "Shockburst" address is: 0x3288817201. **Additional example**, this time for inverter with serial number 99973104619: The datasheet specifies the over-the-air packet format: "Most Significant Byte -(MSB) to the left" (cf figure 11) +(MSB) to the left" (cf [datasheet figure 11][3]) - Address := Byte_4, Byte_3, Byte_2, Byte_1, Byte_0 ("LSByte must be unique") + Address := Byte_4, Byte_3, Byte_2, Byte_1, Byte_0 + ("LSByte must be unique") so 0x1946107301 results in @@ -201,12 +203,12 @@ and some translation/mangling/processing happens inside the NRF24LE1E, in partic - recalculation of CRCs These packets (which are all framed in 0x7e...0x7f bytes) are described in section -"encapsulated packets" below. +[Encapsulated Packets](#encapsulated-packets) below. More recent efforts focus mainly on the actual "Enhanced Shockburst" packets that are transmitted over the air. These packets are described in section -"Enhanced Shockburst Payloads", and the information contained in this section is -more up to date. +[Enhanced Shockburst Payloads](#Enhanced-Shockburst-Payloads), and the +information contained in this section is more up to date. @@ -217,17 +219,19 @@ Encapsulated Packets These are packets as observed on Link (C) in figure (3). - Nachricht: DTU an WR: "Init" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- 7E 07 00 00 00 00 00 00 00 00 00 07 7F ^^ ^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ Bedeutung SOF MID WR ser# WR ser# ? CRC8 EOF +``` ? Nachricht: DTU an WR: "Init 2" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- 7E 07 72 81 88 32 72 81 88 32 00 07 7F @@ -235,10 +239,12 @@ Nachricht: DTU an WR: "Init 2" (?) Bedeutung SOF MID DTU ser# DTU ser# ? CRC8 EOF Einheit BCD (letzte 8) BCD (letzte 8) ? ? Beispiel 72818832 72818832 ? +``` Nachricht 0x80: DTU an WR: "Zeit setzen" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- |<-------------CRC16 'modbus' für CRC_M----------------->| 7E 15 72 22 02 00 72 22 02 00 80 0B 00 62 09 04 9b 00 00 00 00 00 00 00 00 F2 68 F0 7F @@ -246,10 +252,12 @@ Nachricht 0x80: DTU an WR: "Zeit setzen" (?) Bedeutung SOF MID WR ser# WR ser# CMD ? TIME (UTC) CRC_M CRC8 EOF Einheit BCD (letzte 8) BCD (letzte 8) ? [s] HI LO Beispiel 72220200 72220200 ? 2022-02-13 +``` 13:16:11 Nachricht 0x81: DTU an WR: "Anfrage DC-Daten" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- GD->NRF 7E 15 70 51 43 68 70 51 43 68 81 xx 7F ...... (NOCH NICHT VERIFIZIERT / GESEHEN) @@ -261,9 +269,11 @@ GD->NRF 7E 15 70 51 43 68 70 51 43 68 81 xx 7F .. on-air 15 70 51 43 68 70 53 54 53 81 BA (payload) ^^^^^^^^^^^ ^^^^^^^^^^^ WR ser # DTU ser # +``` Nachricht 0x82: DTU an WR: "Anfrage AC-Daten" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- GD->NRF 7E 15 70 51 43 68 70 51 43 68 82 xx 7F ...... (NOCH NICHT VERIFIZIERT / GESEHEN) @@ -275,9 +285,11 @@ GD->NRF 7E 15 70 51 43 68 70 51 43 68 82 xx 7F .. on-air 15 70 51 43 68 70 53 54 53 82 B9 (payload) ^^^^^^^^^^^ ^^^^^^^^^^^ WR ser # DTU ser # +``` Nachricht 0x83: DTU an WR: "Anfrage DC-Daten" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- GD->NRF 7E 15 70 51 43 68 70 51 43 68 83 xx 7F ...... (NOCH NICHT VERIFIZIERT / GESEHEN) @@ -289,9 +301,11 @@ GD->NRF 7E 15 70 51 43 68 70 51 43 68 83 xx 7F .. on-air 15 70 51 43 68 70 53 54 53 83 B8 (payload) ^^^^^^^^^^^ ^^^^^^^^^^^ WR ser # DTU ser # +``` Nachricht 0x85: DTU an WR: "???" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- GD->NRF 7E 15 70 51 43 68 70 51 43 68 85 xx 7F ...... (NOCH NICHT VERIFIZIERT / GESEHEN) @@ -303,9 +317,11 @@ GD->NRF 7E 15 70 51 43 68 70 51 43 68 85 xx 7F .. on-air 15 70 51 43 68 70 53 54 53 85 BE (payload) ^^^^^^^^^^^ ^^^^^^^^^^^ WR ser # DTU ser # +``` Nachricht 0xFF: DTU an WR: "???" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- GD->NRF 7E 15 70 51 43 68 70 51 43 68 FF xx 7F ...... (NOCH NICHT VERIFIZIERT / GESEHEN) @@ -317,9 +333,11 @@ GD->NRF 7E 15 70 51 43 68 70 51 43 68 FF xx 7F .. on-air 15 70 51 43 68 70 53 54 53 FF C4 (payload) ^^^^^^^^^^^ ^^^^^^^^^^^ WR ser # DTU ser # +``` Nachricht 0x01: WR an DTU: "Aktuelle DC Daten" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- 7E 95 72 22 02 00 72 22 02 00 01 00 01 01 4c 03 bd 0c 46 00 b5 00 03 00 05 00 00 BD 7F @@ -327,9 +345,11 @@ Nachricht 0x01: WR an DTU: "Aktuelle DC Daten" (?) Bedeutung SOF MID WR ser# WR ser# CMD ? PV1.u PV1.i PV1.p PV2.u PV2.i PV2.p ? CRC8 EOF Einheit BCD (letzte 8) BCD (letzte 8) ? [0.1V] [0.01A] [.1W] [0.1V] [0.01A] [.1W] ? Beispiel 72220200 72220200 ? 33.2V 9.57A 317.2W 18.1V 0.03A 0.5W ? +``` Nachricht 0x02: WR an DTU: "Aktuelle AC Daten" (?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- 7E 95 72 22 02 00 72 22 02 00 02 28 23 00 00 24 44 00 3C 00 00 09 0F 13 88 0B D5 83 7F @@ -337,9 +357,11 @@ Nachricht 0x02: WR an DTU: "Aktuelle AC Daten" (?) Bedeutung SOF MID WR ser# WR ser# CMD ? ? ? AC.u AC.f AC.p CRC8 EOF Einheit BCD (letzte 8) BCD (letzte 8) ? [0.1V] [0.01Hz] [0.1W] Beispiel 72220200 72220200 ? 9284 60 231.9V 50.00Hz 302.9W +``` Nachricht 0x83: WR an DTU (?): "???" (nach CMD wäre das eher auch eine Antwort vom WR?) +``` ---------------------------------------------------------------------------------------------------------------------------------------------- 7E 95 72 22 02 00 72 22 02 00 83 00 03 00 83 03 E8 00 B2 00 0A FD 26 1E 7F @@ -347,6 +369,7 @@ Nachricht 0x83: WR an DTU (?): "???" (nach CMD wäre das eher auch eine Antwort Bedeutung SOF MID WR ser# WR ser# CMD ? ? ? ? ? ? CRC8 EOF Einheit BCD (letzte 8) BCD (letzte 8) ? Beispiel 72220200 72220200 ? 131 1000 178 10 +``` @@ -368,7 +391,7 @@ Enhanced Shockburst Payloads - These are the packets that are exchanged between inverters and DTU via the Nordic "Enhanced Shockburst" protocol. - Each payload is preceded by a preamble, and terminated by a 16-bit CRC, as described - in the corresponding Nordic datasheet. See also figure 4 above. + in the [Nordic datasheet][3]. See also figure 4 above. @@ -378,17 +401,20 @@ CMD 0x80: DTU --> WR: "Set time/date" (?) |<-------------CRC16 'modbus' für CRC_M----------------->| 15 72220200 72220200 80 0B 00 62 09 04 9b 00 00 00 00 00 00 00 00 F2 68 F0 ^^ ^^^^^^^^ ^^^^^^^^ ^^ ^^^^^ ^^^^^^^^^^^ ^^^^^ ^^^^^ ^^ -Name MID DST_SER# SRC_SER# CMD uk1 TIME (local) SEQ? CRC_M CRC8 +Name MID DTU_SER# DTU_SER# CMD uk1 TIME (local) SEQ? CRC_M CRC8 Units see "addressing" ? [s-since-epoch] HI LO Example 72220200 72220200 ? 2022-02-13 13:16:11 ``` - This message will cause the inverter to transmit a CMD=0x01, CMD=0x02, and, occasionally, also a CMD=0x83 message - to the DTU with serial number DST_SER#. + to the DTU with serial number DTU_SER#. - Values of "0xb0, 0x00" and "0x11, 0x00" have been observed for "UK1". Their meaning is unknown. - "SEQ" was observed to contain increasing numbers when sent by a Hoymiles DTU. In particular, each issued "command" (e.g. "switch inverter on", "switch inverter off") appears to increase this value. A constant value of 0x0000 or 0x0005 appears to work just fine. +- Repeatedly sending the same TIME information (instead of correctly increasing time) + [has been shown](https://www.mikrocontroller.net/topic/525778?page=2#7021386) to result + in identical behaviour, the inverter still replies as described above. ``` @@ -404,7 +430,9 @@ Example 72220200 72220200 ? 33.2V 9.57A - The exact meaning of the contents of this message varies depending on inverter type. So far, the following variants have been observed: - HM-400 (single channel): - HM-700 (2-channel): - - HM-1500 (4-channel): + - HM-1500 (4-channel): +``` +TODO TODO TODO 73109025 73109025 01 00 01 014F 0003 000B 0000 40AE 03AC 08E6 7C ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ 335 3 11 940 2278 @@ -414,14 +442,16 @@ Example 72220200 72220200 ? 33.2V 9.57A ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ 349 77 179 1 13337 34.9V 0.77A 1.79W 1 133.37kW +``` + ``` Nachricht 0x02: WR an DTU: "Aktuelle AC Daten" (?) ---------------------------------------------------------------------------------------------------------------------------------------------- - 7E 95 72 22 02 00 72 22 02 00 02 28 23 00 00 24 44 00 3C 00 00 09 0F 13 88 0B D5 83 7F - ^^ ^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^ ^^^^^ ^^^^^ ^^ ^^ -Bedeutung SOF MID WR ser# WR ser# CMD ? ? ? AC.u AC.f AC.p CRC8 EOF + 7E 95 72 22 02 00 72 22 02 00 02 28 23 00 00 24 44 00 3C 00 00 09 0F 13 88 0B D5 83 + ^^ ^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^ ^^^^^ ^^^^^ ^^ +Bedeutung SOF MID WR ser# WR ser# CMD ? ? ? AC.u AC.f AC.p CRC8 Einheit BCD (letzte 8) BCD (letzte 8) ? [0.1V] [0.01Hz] [0.1W] Beispiel 72220200 72220200 ? 9284 60 231.9V 50.00Hz 302.9W ``` @@ -432,23 +462,25 @@ Beispiel 72220200 72220200 ? 9 Nachricht 0x83: WR an DTU (?): "???" (nach CMD wäre das eher auch eine Antwort vom WR?) ---------------------------------------------------------------------------------------------------------------------------------------------- - 7E 95 72 22 02 00 72 22 02 00 83 00 03 00 83 03 E8 00 B2 00 0A FD 26 1E 7F - ^^ ^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ ^^ -Bedeutung SOF MID WR ser# WR ser# CMD ? ? ? ? ? ? CRC8 EOF -Einheit BCD (letzte 8) BCD (letzte 8) ? -Beispiel 72220200 72220200 ? 131 1000 178 10 + 95 72 22 02 00 72 22 02 00 83 00 03 00 83 03 E8 00 B2 00 0A FD 26 1E + ^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ +Bedeutung MID WR ser# WR ser# CMD ? ? ? ? ? ? CRC8 +Einheit BCD (letzte 8) BCD (letzte 8) ? +Beispiel 72220200 72220200 ? 131 1000 178 10 ``` Legend ====== -MID: Message-ID. Antworten haben Bit 7 gesetzt, - z.B. Frage 0x15 --> Antwort 0x95. - z.B. Frage 0x07 --> Antwort 0x87. - Für Kommunikation GD <--> NRF - -CMD: +**MID**: Message-ID. Antworten haben Bit 7 gesetzt, +``` + z.B. Frage 0x15 --> Antwort 0x95. + z.B. Frage 0x07 --> Antwort 0x87. + Für Kommunikation GD <--> NRF +``` + +**CMD**: Befehl an den WR hat Bit 7 gesetzt 0x80 "Zeit setzen" 0x81 "Anfrage DC-Daten", erwartete Antwort: 0x01 @@ -460,33 +492,41 @@ CMD: 0x01 "Aktuelle DC-Daten" 0x02 "Aktuelle AC-Daten" -SOF: Start-of-Frame 0x7e -EOF: End-of-Frame 0x7f -CRC8: CRC8 mit poly=1 init=0 xor=0, für alle Bytes zwischen SOF und CRC8. +**SOF**: Start-of-Frame 0x7e + +**EOF**: End-of-Frame 0x7f + +**CRC8**: CRC8 mit poly=1 init=0 xor=0, für alle Bytes zwischen SOF und CRC8. Beispiel in Python: +``` >>> import crcmod >>> f = crcmod.mkCrcFun(0x101, initCrc=0, xorOut=0) >>> payload = bytes((0x95,0x72,0x22,0x02,0x00,0x72,0x22,0x02,0x00,0x83,0x00,0x03,0x00,0x83,0x03,0xE8,0x00,0xB2,0x00,0x0A,0xFD,0x26)) >>> hex(f(payload)) '0x1e' +``` -CRC_M: CRC16 wie für "Modbus"-Protokoll, High-Byte gefolgt von Low-Byte +**CRC_M**: CRC16 wie für "Modbus"-Protokoll, High-Byte gefolgt von Low-Byte Beispiel in Python: +``` >>> import crcmod >>> f = crcmod.predefined.mkPredefinedCrcFun('modbus') >>> payload = bytes((0x0B,0x00,0x62,0x2F,0x45,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00)) >>> hex(f(payload)) '0x3bd6' +``` -TIME: Aktuelle (DTU-)Zeit als Unix "time_t" (Sekunden seit 1970-01-01) +**TIME**: Aktuelle (DTU-)Zeit als Unix "time_t" (Sekunden seit 1970-01-01) -Glossar -======= +Glossary +======== + +**WR**: Wechselrichter (inverter) + +**DTU**: Data Terminal Unit (?). Die Hoymiles-Bezeichnung für den Kommunikations-Master. -WR: Wechselrichter (inverter) -DTU: Data Terminal Unit (?). Die Hoymiles-Bezeichnung für den Kommunikations-Master. -BCD: Binary Coded Decimal +**BCD**: Binary Coded Decimal Notizen @@ -504,8 +544,9 @@ References - [1]: https://www.mikrocontroller.net/topic/525778 "The post that started the community effort" - [2]: https://www.mikrocontroller.net "mikrocontroller.net" -- [3]: "Nordic NRF24LE01+ datasheet" +- [3]: https://infocenter.nordicsemi.com/pdf/nRF24LE1_PS_v1.6.pdf "Nordic NRF24LE01+ datasheet" - [4]: https://nrf24.github.io/RF24 "Optimized high speed nRF24L01+ driver documentation" +- [5]: https://github.com/grindylow/ahoy "AHOY Communications Project" Revision History