LoRaWAN Node for Growatt Photovoltaic Inverter Modbus Data Interface
Use this project to monitor your PV Inverter in case it is out of reach of your WiFi access point (and a WiFi repeater would not help/is not wanted) and you are not able to cover the distance with an RS485 cable. Otherwise, the original Growatt ShineWiFi-S (serial) / ShineWiFi-X (USB), the customized otti/Growatt_ShineWiFi-S or nygma2004/growatt2mqtt can be used.
This is a reimplementation of growatt2lorawan using RadioLib.
- Scheduled uplink (2 message types)
- Network time sync
- Downlink decoding
- Commanded uplink (configuration)
- Battery voltage reading
- Hardware Requirements
- Inverter Modbus Interface Options
- Power Supply
- Pinning Configuration
- LoRaWAN Network Service Configuration
- Library Dependencies
- Software Build Configuration
- LoRaWAN Payload Formatters
- MQTT Integration and IoT MQTT Panel Example
- Remote Configuration Commands / Status Requests via LoRaWAN
- Loading LoRaWAN Network Service Credentials from File
- Datacake Integration
- ESP32 (optionally with LiPo battery charger and battery)
- SX1276 or SX1262 (or compatible) LoRaWAN Radio Transceiver
- LoRaWAN Antenna
- optional: RS485 Transceiver - 3.3V compatible, half-duplex capable (e.g Waveshare 4777 module)
- optional: USB-to-TTL converter for Debugging (e.g. AZ Delivery HW-598)
-
USB Interface
The inverter's USB port operates like a USB serial port (UART) interface at 115200 bits/s. If the length of a standard USB cable is sufficient to connect the ESP32 to the inverter (and there are no compatibility issues with the ESP32 board's USB serial interface), this is the easiest variant, because no extra hardware is needed.
As pointed out in otti/Growatt_ShineWiFi-S, only CH340-based USB-Serial converters are compatible - converters with CP21XX and FTDI chips do not work!
-
COM Interface
The inverter's COM port provides an RS485 interface at 9600 bits/s. An RS485 tranceiver is required to connect it to the ESP32.
The desired interface is selected by pulling the GPIO pin INTERFACE_SEL
(defined in settings.h
) to 3.3V or GND, respectively:
Level | Modbus Interface Selection |
---|---|
low (GND) | USB Interface |
high (3.3V/open) | RS485 Interface |
The ESP32 development board can be powered from the inverter's USB port which only provides power if the inverter is active.
No sun - no power - no transmission! 😎
But: Some ESP32 boards have an integrated LiPo battery charger. You could power the board from a battery while there is no PV power (at least for a few hours).
GPIO define | Description |
---|---|
INTERFACE_SEL | Modbus Interface Selection (USB/RS485) |
GPIO define | Waveshare 4777 pin |
---|---|
MAX485_DE | RSE |
MAX485_RE_NEG | n.c. |
MAX485_RX | RO |
MAX485_TX | DI |
USB-to-TTL converter, e.g. AZ Delivery HW-598
GPIO define | USB to TTL Converter |
---|---|
DEBUG_TX | RXD |
DEBUG_RX | TXD / n.c. |
Create an account and set up a device configuration in your LoRaWAN network provider's web console, e.g. The Things Network.
- LoRaWAN v1.1
- Regional Parameters 1.1 Revision A
- Device class A
- Over the air activation (OTAA)
Important
Check the maximum permitted payload size and uplink/downlink rate according to your regional parameters and change the configuration if required! See Airtime calculator for LoRaWAN.
- RadioLib by Jan Gromeš
- Lora-Serialization by Joscha Feth
- ESP32Time by Felix Biego
- ModbusMaster by Doc Walker
- Install the Arduino ESP32 board package in the Arduino IDE
- Select your ESP32 board
- Install all libraries as listed in package.json — section 'dependencies' — via the Arduino IDE Library Manager
- Clone (or download and unpack) the latest (growatt2lorawan-v2 release)
- Set your LoRaWAN Network Service credentials —
RADIOLIB_LORAWAN_DEV_EUI
,RADIOLIB_LORAWAN_NWK_KEY
andRADIOLIB_LORAWAN_APP_KEY
— in secrets.h:
// The Device EUI & two keys can be generated on the TTN console
// Replace with your Device EUI
#define RADIOLIB_LORAWAN_DEV_EUI 0x---------------
// Replace with your App Key
#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
// Put your Nwk Key here
#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
- Load the sketch growatt2lorawan-v2.ino
- Compile and Upload
Upload Uplink Formatter and Downlink Formatter scripts in your LoRaWAN network service provider's web console to allow decoding / encoding of raw data to / from JSON format.
See The Things Network MQTT Integration and Payload Formatters and TS013-1.0.0 Payload Codec API for more details.
Decode uplink payload (a sequence of bytes) into JSON format, i.e. data structures which are readable/suitable for further processing.
In The Things Network Console:
- Go to "Payload formatters" -> "Uplink"
- Select "Formatter type": "Custom Javascript formatter"
- "Formatter code": Paste scripts/uplink_formatter.js
- Apply "Save changes"
Encode downlink payload from JSON to a sequence of bytes.
In The Things Network Console:
- Go to "Payload formatters" -> "Downlink"
- Select "Formatter type": "Custom Javascript formatter"
- "Formatter code": Paste scripts/downlink_formatter.js
- Apply "Save changes"
Arduino App: IoT MQTT Panel
You can either edit the provided JSON configuration file before importing it or import it as-is and make the required changes in IoT MQTT Panel. Don't forget to add the broker's certificate if using Secure MQTT! (in the App: Connections -> Edit Connections: Certificate path.)
Editing IoT_MQTT_Panel_Growatt2LoRaWAN.json
Change USERNAME and PASSWORD as needed:
[...]
"username":"USERNAME","password":"PASSWORD"
[...]
Many software parameters can be defined at compile time, i.e. in BresserWeatherSensorLWCfg.h. A few parameters can also be changed and queried at run time via LoRaWAN, either using raw data or using Javascript Uplink/Downlink Formatters.
Parameter | Description |
---|---|
<sleep_interval> | Sleep interval (regular) in seconds; 0...65535 |
<sleep_interval_long> | Sleep interval (energy saving mode) in seconds; 0...65535 |
<lw_status_interval> | LoRaWAN node status message uplink interval in no. of uplink frames; 0...255; 0: disabled |
<ubatt_mv> | Battery voltage in mV |
<long_sleep> | 0: regular sleep interval / 1: long sleep interval (depending on U_batt) |
<epoch> | Unix epoch time, see https://www.epochconverter.com/ ( <integer> / "0x....") |
Warning
Confirmed downlinks should not be used! (see here for an explanation.)
- Sleep interval (long):
SLEEP_INTERVAL
,SLEEP_INTERVAL_LONG
; see growatt2lorawan_cfg.h LW_STATUS_INTERVAL
: see growatt2lorawan_cfg.h
Command | Port | Downlink | Uplink |
---|---|---|---|
CMD_GET_DATETIME | 0x20 (32) | 0x00 | epoch[31:24] epoch[23:16] epoch[15:8] epoch[7:0] rtc_source[7:0] |
CMD_SET_DATETIME | 0x21 (33) | epoch[31:24] epoch[23:16] epoch[15:8] epoch[7:0] |
n.a. |
CMD_SET_SLEEP_INTERVAL | 0x31 (49) | sleep_interval[15:8] sleep_interval[7:0] |
n.a. |
CMD_SET_SLEEP_INTERVAL_LONG | 0x33 (51) | sleep_interval_long[15:8] sleep_interval_long[7:0] |
n.a. |
CMD_SET_LW_STATUS_INTERVAL | 0x35 (53) | lw_status_interval[7:0] | n.a. |
CMD_GET_LW_CONFIG | 0x36 (54) | 0x00 | sleep_interval[15:8] sleep_interval[7:0] sleep_interval_long[15:8] sleep_interval_long[7:0] lw_status_interval[7:0] |
CMD_GET_LW_STATUS | 0x38 (56) | 0x00 | ubatt_mv[15:8] ubatt_mv[7:0] long_sleep[7:0] |
Note
The command ("cmd": ...
) may be omitted if it can be derived from the given parameters.
Command | Downlink | Uplink |
---|---|---|
CMD_GET_DATETIME | {"cmd": "CMD_GET_DATETIME"} | {"epoch": <epoch>} |
CMD_SET_DATETIME | {"epoch": <epoch>} | n.a. |
CMD_SET_SLEEP_INTERVAL | {"sleep_interval": <sleep_interval>} | n.a. |
CMD_SET_SLEEP_INTERVAL_LONG | {"sleep_interval_long": <sleep_interval_long>} | n.a. |
CMD_SET_LW_STATUS_INTERVAL | {"lw_status_interval": <lw_status_interval>} | n.a. |
CMD_GET_LW_CONFIG | {"cmd": "CMD_GET_LW_CONFIG"} | {"sleep_interval": <sleep_interval>, "sleep_interval_long": <sleep_interval_long>, "lw_status_interval": <lw_status_interval>} |
CMD_GET_LW_STATUS | {"cmd": "CMD_GET_LW_STATUS"} | {"ubatt_mv": <ubatt_mv>, "long_sleep": <long_sleep>} |
Note
To simplify deployment of a larger number of devices, LoRaWAN credentials can be read from a JSON file. This allows to use the same source code and binary file for a fleet of devices.
If a valid file secrets.json
exists on LittleFS, the settings defined at compile time (in secrets.h
) are overridden.
Modify the example data/secrets.json as required and install it to the board's Flash memory using earlephilhower/arduino-littlefs-upload.
Warning
Only very basic validation of the file secrets.json
is implemented — check the debug output.
For integration with Datacake, there is the script datacake_decoder.js. With Datacake, you can get data reports as CSV files at regular intervals. The Python script datacake_report_pv.py allows to concatenate, sort and filter those files and to create a report with data plots as PDF file (example).