Help Required Uploading Growatt Inverter To PVOutput


Sure! I am logging packets sent starting tomorrow. This may giver us some clue.

Regarding errors from weather service, I too had a lot of issues, most of than are “API call timeouted” but I do have couple of “HTTP 500” errors (server side error). At least one fail each day but sometime three or four errors. I strongly believe this is internet issues somewhere between my RPi and OWM server or even OWM server busy and not responding in time. “API call timeout” are clear a server responding in no time while HTTP was connected, hence, server side issue or connection issue somewhere in the Internet. HTTP 500 generally means server too busy to answer HTTP request or some internal issue preventing it from providing response (like a background service not responding - a database, a worker process, whatever); again, server side issue for sure. The error you got (“NewConnectionError” or “Temporary failure in name resolution”) is an issue with connection and/or DNS servers, I did experience this once in the past but it is not common on my logs. Something is preventing HTTP connection to the server, in this specific case, the DNS server did not answer well… We don´t know the DNS error, urllib3 did not provide enough logs to clarify it; it could be our internet provider DNS failing to answer (I don´t use internet provider DNS server, I use Google/OpenDNS as my primary and secondary DNS service - they could fail too but less likely as my small provider´s server). It also could be the OWM DNS provider failing (I did not check who is resolving for them) but I guess they might have DNS hosted by a major provider. Anyway, this is more or less out of our control (besides change our DNS servers there is not much we can do).



I think the most likely reason for my DNS errors are that my Pi is right on the edge of my wi-fi network. I thought that the signal was strong enough but now I think that my connection may occasionally fail. This would explain my DNS errors with both PVOutput and OWM. Your retry loop has solved the former and to be honest I’m not too bothered about the weather data - I have no temperature values missing anyway.



Best to check / log the data sent, particularly the value of the time (t) parameter. The 12:08 logged may have been 12:07:20 and rounded down to 12:05 instead of up to 12:10.


Hi @jrbenito
Short story: Connection done, tests not done

Long story: Could not make it onsite so a friend (electrician) went there and connected a ch340 usb to RS485 converter to espressobin. He checked Data+ & Data- and he is certain that the connection is correct. The converter is recognised by the kernel. Here is the dmesg & lsusb output:

[283872.866969] kmodloader: loading kernel modules from /etc/modules.d/*
[283872.894485] usbcore: registered new interface driver ch341
[283872.900372] usbserial: USB Serial support registered for ch341-uart
[283872.908179] kmodloader: done loading kernel modules from /etc/modules.d/*
[319464.695964] usb 1-1: new full-speed USB device number 2 using orion-ehci
[319464.904202] ch341 1-1:1.0: ch341-uart converter detected
[319464.915737] usb 1-1: ch341-uart converter now attached to ttyUSB0
root@OpenWrt:~# lsusb
Bus 003 Device 002: ID 152d:3562 JMicron Technology Corp. / JMicron USA Technology Corp. JMS567 SATA 6Gb/s bridge
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub

Unfortunately, modpoll works on 32bit systems so I could not use it on aarch64. I then tried modbus_cli but i get this error:

Traceback (most recent call last):
  File "/usr/bin/modbus", line 7, in <module>
    from itertools import chain, zip_longest, groupby
ImportError: cannot import name zip_longest

Then there is mbpoll but it needs cross compilation which I am not comfortable with.
I will try to test with your code for one inverter later today or tomorrow.


Hi @jrbenito

I successfully tested two inverters with your code so far by modifying the address like:
inv = Inverter(0x2, '/dev/ttyUSB0')
so the connection works.
One question; As I am not familiar with python, could you please let me know how can I export partial or full data read from the inverter (eg, serial no, inv.wh_total etc) to a file or to the console?
Thank you


Precisely! I saw that my report gaps are either round down or round up. The solution is correctly calculate how much seconds to sleep after sending packages (what could take some time). This would precisely run at clock five minutes and not each five minutes.



Glad your cabling is working, now we can try some code :wink:

I did not understand, do you want to dump things to console? Just use print xxx

I will have some code to test probably tomorrow, I let you know.



Could you try tag teste-0.6.12 and let me know? I will put it on trial too but with a bunch of other things hence I made this special test tag just for you.

Please feedback.



Thanks, running it now.



FYI, I just merged v0.7.0 with changes to pvoutput function (now a class) and also aggregating mods of teste-0.6.12. Up to this version there is no modification on user side, however, this is first step to accommodate multiple inverters/system (@lampra) that I will push to dev branch today. Those modification will need configuration file changes (and cleanup in fact).


Some feedback after 48 hours. All good so far :slight_smile: No missing values since I started running this version however I will continue to monitor over the next few days.



Great, looking forward to start testing.

Yes I want to dump things(serial no, firmware etc) to console. I tried to use print XXX both in the file or from interactive mode but did not manage to get data. Anyway, this is not that important.


Ah got it.

The bare minimum you need is more or less this:

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
inv = ModbusClient(method='rtu', port='/dev/ttyUSB0', baudrate=9600, stopbits=1,
                   parity='N', bytesize=8, timeout=1)

rr = inv.read_input_registers(0, 45, unit='0x1')
print rr

First you import the modbus library, define the modbus interface (inv) and do inv.connect(), this last command will open the serial port on Linux (/dev/ttyUSB0) in this example. If everything ok until here, you can issue any number of read_input_registers or read_holding_registers and print out whatever you want. In the example above, I am reading 45 registers starting from 0 (or register from 0 to 44). As per Growatt documentation, inverter can read at most 45 register in a single command, and also, it cannot return registers like from 10 to 54 because 10~44 are in on “45 registers page” and 45~54 are stored in another “45 registers page”. This is most likely due internal memory organization. Hence, you can read 0-44, 10-15, 40-44, 45-89 but you cannot read 40-60, 70-110, etc.

Also, notice that there are two classes of register a Growatt would know, the input registers are read using function read_input_registersand holding registers that are read with read_holding_registers. Simply put, a input register is a quantity that a device give you, a temperature sensor would have a input register that stores current temperature from the sensor. A holding register is more likely a configuration hence, a temperature device would have a holding register to configure readings as Celsius or Fahrenheit. Growatt has holding registers for every configuration like max voltage, timers, faults, etc. and reading registers for power, energy, vdc, vac, etc… Example: firmware version is a holding register while current out power is a reading register.

Hope this helps


Dear @lampra ,

A finished a draft of what should be the logic to use multi-inverter. Now I need you to try it and provide some feedback. I don´t expect it to work at first try since I could not try it myself (I am temporarily away from my VPN to test it) hence I need any error report so I can figure out what I did wrong.

Could you please try version at Multi-inv tree? It might work for single inverter as well to multi-inverter setup.


Thank you for your patience but I can’t seem to be able to make it work.

root@OpenWrt:~# python
    Python 2.7.15 (default, Aug 16 2018, 07:51:15) 
    [GCC 7.3.0] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from pymodbus.client.sync import ModbusSerialClient as ModbusClient
    >>> inv = ModbusClient(method='rtu', port='/dev/ttyUSB0', baudrate=9600, stopbits=1,
                       parity='N', bytesize=8, timeout=1)... 
    >>> inv.connect()
    >>> rr = inv.read_input_registers(0, 45, unit='0x1')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib/python2.7/site-packages/pymodbus/client/", line 125, in read_input_registers
        return self.execute(request)
      File "/usr/lib/python2.7/site-packages/pymodbus/client/", line 108, in execute
        return self.transaction.execute(request)
      File "/usr/lib/python2.7/site-packages/pymodbus/", line 141, in execute
      File "/usr/lib/python2.7/site-packages/pymodbus/", line 204, in _transact
        packet = self.client.framer.buildPacket(packet)
      File "/usr/lib/python2.7/site-packages/pymodbus/framer/", line 236, in buildPacket
        message.function_code) + data
    struct.error: cannot convert argument to integer
    >>> rr = inv.read_input_registers(0, 45, unit=0x1)  
    >>> print rr
    Modbus Error: [Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 2 bytes (0 received)
    >>> inv.close()
    >>> quit()


That’s great. I Installed and started testing.
First off, it seems that the single quotes needs to be removed from the pvoutput.cfg file to make it work. In the same file, for the latitude & longitude the float(min=-180, max=180, default=0.0) also need to be removed and substituted by the coordinates. The code then starts running but I get the following error both if I provide the address of one or two inverters.

root@OpenWrt:~/canadianSolar-pvoutput-multi-inv# pip install -r requirements.txt
Requirement already satisfied: configobj==5.0.6 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 3))
Collecting pymodbus==2.0.1 (from -c requirements/constraints.txt (line 12))
  Downloading (125kB)
    100% |████████████████████████████████| 133kB 695kB/s 
Requirement already satisfied: pyowm==2.9.0 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 13))
Requirement already satisfied: pyserial==3.4 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 14))
Requirement already satisfied: requests==2.19.1 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 15))
Requirement already satisfied: six==1.11.0 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 16))
Requirement already satisfied: urllib3==1.23 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 17))
Requirement already satisfied: pytz in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 18))
Requirement already satisfied: geojson==2.3.0 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 7))
Requirement already satisfied: idna==2.7 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 8))
Requirement already satisfied: certifi==2018.8.24 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 1))
Requirement already satisfied: chardet==3.0.4 in /usr/lib/python2.7/site-packages (from -c requirements/constraints.txt (line 2))
Installing collected packages: pymodbus
  Found existing installation: pymodbus 1.5.2
    Uninstalling pymodbus-1.5.2:
      Successfully uninstalled pymodbus-1.5.2
Successfully installed pymodbus-2.0.1
root@OpenWrt:~/canadianSolar-pvoutput-multi-inv# sh
Traceback (most recent call last):
  File "./", line 397, in <module>
  File "./", line 299, in main_loop
  File "./", line 101, in version
    for address, regs in self.units:
ValueError: too many values to unpack
python script erro, sleeping few seconds and call it again

Edit : let me know if you prefer reporting tests here or in an issue at github



Sorry, “unit” in the read_input_registers should be a number, not a string.

Later 3 lines from your interactive try show another type of error, probably inverter was off or communication not ok.


Ok ok, code without testing is terrible.

First, sorry my mistake, inverter address shall not have single quote because they need to be numbers, will modify configurations examples. For latitude and longitude of OWM module I did copy and paste from spec to the config example and forgot to change, the correct values are decimals representing your location (lat: -22.33 lon: 49.74 for instance) but they are optional, if not using OWM they do not need be un-commented.

Now for the code issues:

I forgot to add “.items()” to lines 59 and 102 like I did for line 321 (lines referenced in new code). Since I did not test with proper modbus, I never got these errors. This code is needing some sort of unit testing to be proper tested without real hardware :smiley:

Regarding reports, you can do it the way you like, here or at issues in github.

Please, try new version at multi-inv branch.



No need to be sorry. Thank you for your time and for the great code.
I downloaded and tested the new version. It seems that the single quotes from the system id also need to be removed.
We will need to wait until sunrise :smiley: tomorrow morning for further info!!

root@OpenWrt:~/canadianSolar-pvoutput-multi-inv# sh
Could not initialize inverter object: Error: need same number of inverters and system_ids
python script erro, sleeping few seconds and call it again
root@OpenWrt:~/canadianSolar-pvoutput-multi-inv# vi pvoutput.conf
root@OpenWrt:~/canadianSolar-pvoutput-multi-inv# sh
2018-10-03 21:53 - Next shift starts in 427 minutes
Exiting by user request.


To solve this you need to have additional systems registered in the pvoutput (one for each inverter), for instance:

inverter 0x1 - pvoutput system id 35678
inverter 0x2 - pvoutput system id 35679
and so on

Hence, inverter address 0x1 will report to sytem id 35678. Did you do it?

You can aggregate measurments later by the pvoutput interface.