A Python-based bridge to communicate with Growatt Inverters (specifically MOD TL3-XH) via Modbus RS485 and publish data to MQTT.
Unlike simple monitoring scripts, this project supports writing to holding registers, allowing you to control battery limits and AC charging via Home Assistant.
- 📡 Live Monitoring: Reads PV power, Grid voltage, Battery status (SOC, Power), and Load consumption.
- 🎛️ Control: Allows writing to registers to control Battery Charge/Discharge limits and AC Charging.
- 🪄 MQTT Auto-Discovery: Seamless Plug & Play integration with Home Assistant (no manual YAML configuration required!).
- 📦 Modern Packaging: Easy installation via
pip, systemd service, orDocker. - 🏠 Home Assistant Ready: Optimized for easy integration with HA automation and the HA Energy Dashboard.
- 🔧 MOD TL3-XH Optimized: Uses the correct register map (3000+ range) for newer firmware versions.
You can install the package directly from the source.
# 1. Clone repository
git clone [https://github.com/YOUR_USER_NAME/growatt2mqtt.git](https://github.com/YOUR_USER_NAME/growatt2mqtt.git)
cd growatt2mqtt
# Create a virtual environment named 'venv'
python3 -m venv venv
# Activate the environment
source venv/bin/activate
# 2. Install package
pip install .
# 3. Setup configuration
cp growatt2mqtt.cfg.example growatt.cfg
nano growatt.cfg # <-- Edit MQTT IP and Serial Port here
# 4. Run
growatt-run -c growatt.cfgA Dockerfile is included to run the bridge in an isolated environment.
# 1. Pull Image
docker pull ghcr.io/dein-user/growatt-2-mqtt:latest
# 2. Run Container
# Note: You must map the USB device and the config file!
docker run -d \
--name growatt \
--restart unless-stopped \
--device /dev/ttyUSB0:/dev/ttyUSB0 \
-v $(pwd)/growatt.cfg:/config/growatt.cfg \
growatt-2-mqtt:latestConfiguration is handled via the growatt2mqtt.cfg file.
[time]
# Data polling interval in seconds
interval = 10
# Time to sleep if inverter is offline (e.g., at night for PV-only systems)
offline_interval = 60
# Time to sleep after a communication error
error_interval = 60
[serial]
port = /dev/ttyUSB0
baudrate = 9600
[mqtt]
host = 192.168.1.10
port = 1883
topic = inverter/growatt
user = mqtt_user
password = mqtt_pass
# Enable Home Assistant MQTT Auto-Discovery (true/false)
discovery = true
[inverters.main]
unit = 1
# Important for MOD TL3-XH: Use the XH specific protocol
protocol_version = TL-XHBy default, the bridge uses Home Assistant's MQTT Auto-Discovery feature. Ensure discovery = true is set in your growatt.cfg.
Once the bridge connects to your MQTT broker and Home Assistant is online, your inverter will automatically appear as a new Device in Home Assistant under Settings -> Devices & Services -> MQTT.
All sensors are automatically created and grouped under the inverter device.
Device classes (Power, Energy, Voltage) and state classes are automatically assigned.
You can instantly add the energy sensors (like E_Today) to your Home Assistant Energy Dashboard.
Migrating from an older version? If you update to this version and already have manual YAML sensors configured, you will see duplicated sensors. To prevent this, either delete your old YAML sensors or disable auto-discovery by setting discovery = false in your config.
If you prefer to define your sensors manually or have auto-discovery disabled, you can add them to your Home Assistant configuration.yaml file manually:
mqtt:
number:
# Control Battery Discharge Limit (0-100%)
- name: "Growatt Discharge Limit"
unique_id: growatt_bat_discharge_limit
command_topic: "inverter/control/BatDischargePowerLimit"
state_topic: "inverter/growatt/solar/MOD5000TL3-XH"
value_template: "{{ value_json.fields.BatDischargePowerLimit }}"
min: 0
max: 100
mode: slider
unit_of_measurement: "%"
# Control Battery Charge Limit (0-100%)
- name: "Growatt Charge Limit"
unique_id: growatt_bat_charge_limit
command_topic: "inverter/control/BatChargePowerLimit"
state_topic: "inverter/growatt/solar/MOD5000TL3-XH"
value_template: "{{ value_json.fields.BatChargePowerLimit }}"
min: 0
max: 100
mode: slider
unit_of_measurement: "%"
switch:
# Enable/Disable AC Charging (Grid Charging)
- name: "Growatt AC Charge"
unique_id: growatt_ac_charge_enable
command_topic: "inverter/control/ACChargeEnable"
state_topic: "inverter/growatt/solar/MOD5000TL3-XH"
value_template: "{{ value_json.fields.ACChargeEnable }}"
payload_on: "1"
payload_off: "0"
state_on: 1
state_off: 0You can change the inverter's settings by publishing JSON messages to the /set topic. For example, to change the maximum grid feed-in power:
Topic: inverter/growatt/set
{
"command": "MaxPower",
"value": 5000
}Available commands depend on your register map (e.g., MaxPower, ChargePower, DischargePower).
If you want to develop, test, or build dashboards while the sun is down (and your real inverter is offline), you can use the built-in Modbus simulator. It creates a virtual serial tunnel and feeds realistic, fluctuating data to the bridge.
[ growatt2mqtt ] <---> (/dev/pts/1) [ socat tunnel ] (/dev/pts/2) <---> [ simulator.py ]
- Start the Virtual Tunnel
Run the included helper script to create a virtual serial connection. It will automatically check your OS and give you the correct paths.
python3 tools/start_socat.pyLeave this terminal open. It will output two ports (e.g., Port 1: /dev/pts/1 and Port 2: /dev/pts/2).
- Start the Simulator
Open a second terminal and start the simulator using Port 2. You can choose the inverter profile that matches your setup.
# For String Inverters (TL-X, MIC, MIN)
python3 tools/simulator.py /dev/pts/2 --profile mic600
# For Hybrid Inverters (MOD TL3-XH)
python3 tools/simulator.py /dev/pts/2 --profile tlxh
# Add --debug to see the raw Modbus hex traffic- Connect the Bridge
Open a third terminal. Edit your growatt.cfg and change the serial port to Port 1:
[serial]
port = /dev/pts/1
baudrate = 9600Then, start the bridge normally:
growatt-run -c growatt.cfgYou should now see simulated data (sine waves for power/voltage) arriving in your MQTT broker!
To run the script automatically at boot, install the systemd service.
Create the service file or use the template file (growatt2mqtt.service) in the repo:
sudo nano /etc/systemd/system/growatt2mqtt.servicePaste the following configuration:
[Unit]
Description=Growatt MQTT Bridge Service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/home/pi/growatt2mqtt
# Point to the executable INSIDE the virtual environment
ExecStart=/home/pi/growatt2mqtt/venv/bin/growatt-run -c growatt.cfg
Environment=PYTHONUNBUFFERED=1
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetEnable and Start:
sudo systemctl daemon-reload
sudo systemctl enable growatt.service
sudo systemctl start growatt.serviceCheck Status:
sudo systemctl status growatt.service
# View logs:
journalctl -u growatt.service -fUse one of the following shortcodes in your config file to load the correct register map:
| Shortcode | Description / Compatible Series | Covered Registers |
|---|---|---|
| TL3X | Standard PV Inverters (MIC, MIN, MAC, TL-X, TL3-X) | Basic Data (0-124), Strings/PID (125-249) |
| TL-XH | "Battery Ready" Hybrid Systems (High Voltage) | Inverter (3000-3124), Battery/BDC (3125-3249) |
| TL-XH-MIN | MIN TL-XH Series (US/Global Single Phase Hybrid) | Inverter (3000+), Battery 1 (3125+), Battery 2 (3250+) |
| SPH | SPH 3000-6000 Hybrid Inverters | Basic (0-124), Hybrid Data (1000-1124), Extended (1125+) |
| SPA | AC-Coupled Storage Retrofit (e.g., SPA 3000TL BL) | Hybrid (1000-1124), Extended (1125+), AC-Grid (2000+) |
| MIX | MIX / SPH Series (Alternative Layout) | Basic (0-124), Storage/Energy Flow (1000-1124) |
| MAX | Commercial Inverters (MAX 1500V / MAX-X LV) | Basic (0-124), Strings 1-16 (125-249), Strings 17-32 (875-999) |
| MOD-XH | MOD TL3-XH Series (3-Phase Battery Ready Hybrid) | Inverter (3000-3124), Battery/BDC (3125-3249) |
| EASTRON | Eastron SDM630 Smart Meter (Direct RS485 Connection) | Voltage/Amps (0-50), Power/Energy (52-80, 342) |
| CHINT | Chint DTSU666 Smart Meter (Direct RS485 Connection) | Voltage/Amps (8192+), Power/Energy (8212+, 16384+) |
Note: If you are unsure, start with TL3X for pure PV inverters or TL-XH for modern battery-ready systems.
If you receive no data or errors:
-
Check your wiring (A to A, B to B on RS485).
-
Verify the unit ID (default is often 1).
-
Set log_level = DEBUG in growatt2mqtt.cfg to see raw Modbus frames and parser outputs.
Currently the code is tested for the following models:
| Model | Compatibility | Covered Registers |
|---|---|---|
| Growatt MOD 5000TL3-XH | ☑ | Input Reg / Holding Reg |
| Growatt MIC 600TL-X | ☑ | Input Reg / part. Holding Reg |