Page 1 of 1

Python Plugin: Growatt Solar Inverter via USB RS232 or RS485 Modbus

Posted: Sunday 18 June 2017 20:31
by jeroenst
This is the first code for the Growatt plugin.

I don't have a Growatt inverter at this moment, can someone test it?

It uses the modbus port of the Growatt converter, get a modbus interface from ebay ( http://www.ebay.com/sch/i.html?_odkw=us ... 5&_sacat=0 ) or somewhere else...

It runs on Ubuntu 17.04 after I did include the right paths with sys.path.append

Known bugs:
1. When adding the hardware device there are 2 Serial Port fields. This is possible a bug in Domoticz because in the plugin only 1 field is defined
2. The icons of power and frequency don't match electric power, there is no Watt and Frequency available in TypeName of Domoticz

Code: Select all

# Growatt Python Plugin for Domoticz
#
# Author: jst
#
# Install modbus library: https://pypi.python.org/pypi/MinimalModbus
#
"""
<plugin key="Growatt" name="Growatt Solar Inverter via RS485" author="jst" version="1.0.0">
    <params>
        <param field="SerialPort" label="Serial Port" width="150px" required="true"/>
        <param field="Mode6" label="Debug" width="75px">
            <options>
                <option label="True" value="Debug"/>
                <option label="False" value="Normal" default="true"/>
            </options>
        </param>
    </params>
</plugin>
"""

import sys
sys.path.append('/usr/local/lib/python3.5/dist-packages/')
sys.path.append('/usr/local/lib/python3.5/dist-packages/pyserial-3.3-py3.5.egg')

import minimalmodbus
try:
    import Domoticz
except ImportError:
    import fakeDomoticz as Domoticz


class BasePlugin:
    enabled = False
    def __init__(self):
        return

    def onStart(self):
       Domoticz.Log("onStart called")
       if (len(Devices) == 0):
         Domoticz.Device("pv watt", 1, "Custom", Options = { "Custom" : "1;W"}).Create()
         Domoticz.Device("pv voltage", 2, "Voltage").Create()
         Domoticz.Device("pv current", 3, "Current (Single)").Create()
         Domoticz.Device("grid watt", 4, "Custom", Options = { "Custom" : "1;W"}).Create()
         Domoticz.Device("grid voltage", 5, "Voltage").Create()
         Domoticz.Device("grid current", 6, "Current (Single)").Create()
         Domoticz.Device("grid frequency", 7, "Custom", Options = { "Custom" : "1;Hz"}).Create()
         Domoticz.Device("kwh today", 8, "Custom", Options = { "Custom" : "1;kWh"}).Create()
         Domoticz.Device("kwh total", 9, "Custom", Options = { "Custom" : "1;kWh"}).Create()
       DumpConfigToLog()
       Domoticz.Log("Plugin is started.")
       Domoticz.Heartbeat(20)

    def onStop(self):
        Domoticz.Log("onStop called")

    def onConnect(self, Connection, Status, Description):
        Domoticz.Log("onConnect called")

    def onMessage(self, Connection, Data, Status, Extra):
        Domoticz.Log("onMessage called")

    def onCommand(self, Unit, Command, Level, Hue):
        Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level))

    def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile):
        Domoticz.Log("Notification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile)

    def onDisconnect(self, Connection):
        Domoticz.Log("onDisconnect called")

    def onHeartbeat(self):
        #Domoticz.Log("onHeartbeat called")
        ## Read Growatt Inverter ##
        try:
          instrument = minimalmodbus.Instrument(Parameters["SerialPort"], 1) # port name, slave address (in decimal)
        except:
          Domoticz.Log("Error openining USB Modbus connection to growatt inverter on "+Parameters["SerialPort"])
        else:
          try:
            instrument.serial.baudrate = 9600
            growatt_pv_watt = ((instrument.read_register(1) << 16) + instrument.read_register(2))/10
            growatt_pv_volt = instrument.read_register(int(3))/10
            growatt_pv_amp = instrument.read_register(4)/10
            growatt_grid_watt = ((instrument.read_register(11) << 16) + instrument.read_register(12))/10
            growatt_grid_freq = instrument.read_register(13)/100
            growatt_grid_volt = instrument.read_register(14)/10
            growatt_grid_amp = instrument.read_register(15)/10
            growatt_kwh_today = ((instrument.read_register(26) << 16) + instrument.read_register(27))/10
            growatt_kwh_total = ((instrument.read_register(28) << 16) + instrument.read_register(29))/10

            Devices[1].Update(growatt_pv_watt, growatt_pv_watt.replace('.',''))
            Devices[2].Update(growatt_pv_volt, growatt_pv_volt.replace('.',''))
            Devices[3].Update(growatt_pv_amp, growatt_pv_amp.replace('.',''))
            Devices[4].Update(growatt_grid_watt, growatt_grid_watt.replace('.',''))
            Devices[5].Update(growatt_grid_volt, growatt_grid_volt.replace('.',''))
            Devices[6].Update(growatt_grid_amp, growatt_grid_amp.replace('.',''))
            Devices[7].Update(growatt_grid_freq, growatt_grid_freq.replace('.',''))
            Devices[8].Update(growatt_kwh_today, growatt_kwh_today.replace('.',''))
            Devices[9].Update(growatt_kwh_total, growatt_kwh_total.replace('.',''))
            instrument.close()
          except:
            Domoticz.Log("Error reading growatt inverter on "+Parameters["SerialPort"])

global _plugin
_plugin = BasePlugin()

def onStart():
    global _plugin
    _plugin.onStart()

def onStop():
    global _plugin
    _plugin.onStop()

def onConnect(Connection, Status, Description):
    global _plugin
    _plugin.onConnect(Connection, Status, Description)

def onMessage(Connection, Data, Status, Extra):
    global _plugin
    _plugin.onMessage(Connection, Data, Status, Extra)

def onCommand(Unit, Command, Level, Hue):
    global _plugin
    _plugin.onCommand(Unit, Command, Level, Hue)

def onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile):
    global _plugin
    _plugin.onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile)

def onDisconnect(Connection):
    global _plugin
    _plugin.onDisconnect(Connection)

def onHeartbeat():
    global _plugin
    _plugin.onHeartbeat()

    # Generic helper functions
def DumpConfigToLog():
    for x in Parameters:
        if Parameters[x] != "":
            Domoticz.Debug( "'" + x + "':'" + str(Parameters[x]) + "'")
    Domoticz.Debug("Device count: " + str(len(Devices)))
    for x in Devices:
        Domoticz.Debug("Device:           " + str(x) + " - " + str(Devices[x]))
        Domoticz.Debug("Device ID:       '" + str(Devices[x].ID) + "'")
        Domoticz.Debug("Device Name:     '" + Devices[x].Name + "'")
        Domoticz.Debug("Device nValue:    " + str(Devices[x].nValue))
        Domoticz.Debug("Device sValue:   '" + Devices[x].sValue + "'")
        Domoticz.Debug("Device LastLevel: " + str(Devices[x].LastLevel))
    return

Re: Python Plugin: Growatt Solar Inverter via USB Modbus

Posted: Monday 19 June 2017 13:47
by devros
hello, i have something similar
solar inverter (http://www.ebay.com/itm/2000W-Solar-on- ... F5Ow8R3kEw) with wifi-plug-usb (conected to this portal http://www.shinemonitor.com/main.html) figured out that wifi plug is conected to this page using modbus protocol.
In Wifi plug admin page i can specify own server with port.
Any idea how to modify this script to support TCP/modbus comunication ?

Re: Python Plugin: Growatt Solar Inverter via USB Modbus

Posted: Monday 19 June 2017 23:42
by Dnpwwo
@jeroenst,

The double serial port field is probably caused by a 'feature' of the Domoticz hardware page.

Prior to the Python plugin framework all hardware support was effectively hardcoded from a parameter point of view, this was heavily influenced by the name of the hardware. I suspect that by having the word "USB" in the name the Hardware page has assumed you want it to show the Serial Port field.

Try renaming it to see if the extra field goes away.

Re: Python Plugin: Growatt Solar Inverter via USB Modbus

Posted: Tuesday 20 June 2017 7:41
by jeroenst
Dnpwwo wrote:@jeroenst,
Try renaming it to see if the extra field goes away.
You're right, I renamed it and the extra field is gone. Shouldn't this be changed in Domoticz?

Re: Python Plugin: Growatt Solar Inverter via USB Modbus

Posted: Tuesday 20 June 2017 7:45
by jeroenst
devros wrote:hello, i have something similar
solar inverter (http://www.ebay.com/itm/2000W-Solar-on- ... F5Ow8R3kEw) with wifi-plug-usb (conected to this portal http://www.shinemonitor.com/main.html) figured out that wifi plug is conected to this page using modbus protocol.
In Wifi plug admin page i can specify own server with port.
Any idea how to modify this script to support TCP/modbus comunication ?
I think you have to create a whole new module for this with a TCP server socket and a piece of code that decodes the parameters received.

If you can receive the data using netcat and specify the values received I'm willing to write a module for you.

Re: Python Plugin: Growatt Solar Inverter via USB Modbus

Posted: Tuesday 20 June 2017 11:09
by devros
jeroenst wrote:
devros wrote:hello, i have something similar
solar inverter (http://www.ebay.com/itm/2000W-Solar-on- ... F5Ow8R3kEw) with wifi-plug-usb (conected to this portal http://www.shinemonitor.com/main.html) figured out that wifi plug is conected to this page using modbus protocol.
In Wifi plug admin page i can specify own server with port.
Any idea how to modify this script to support TCP/modbus comunication ?
I think you have to create a whole new module for this with a TCP server socket and a piece of code that decodes the parameters received.

If you can receive the data using netcat and specify the values received I'm willing to write a module for you.
Great i will try to grab data, so far i was able to extract JSON file from shinemonitor. Any link with tutorial how to do this ?

Re: Python Plugin: Growatt Solar Inverter via USB RS485 Modbus

Posted: Tuesday 20 June 2017 11:39
by jeroenst
@devros

ncat -e /bin/cat -k -t -l <portnumber>

Re: Python Plugin: Growatt Solar Inverter via USB RS485 Modbus

Posted: Tuesday 20 June 2017 11:55
by devros
jeroenst wrote:@devros

ncat -e /bin/cat -k -t -l <portnumber>
thanks, but how to specify WIFI-PLUG IP adress (im scaning from another computer)?, also im not sure about used port on that machine (tried nmap but only 80 is open (http)). Log on webpage shinemonitor.com is log updated every 5 minutes so maybe is port opened only at sending time.

Re: Python Plugin: Growatt Solar Inverter via USB RS485 Modbus

Posted: Tuesday 20 June 2017 12:05
by jeroenst
Specify the adres and port ncat is listening on in de admin webpage of the wifiplug but if if you want to continue use of shinemonitor grabbing the json file is a better idea.

Re: Python Plugin: Growatt Solar Inverter via USB RS485 Modbus

Posted: Tuesday 20 June 2017 12:30
by devros
jeroenst wrote:Specify the adres and port ncat is listening on in de admin webpage of the wifiplug but if if you want to continue use of shinemonitor grabbing the json file is a better idea.
Finally I understand (ncat open specific port and save log) :), I'll try it when I'm home and post results later
in admin webpage i can specify 3 IP addresses with ports, so it should work fine together :)
it looks like wifiplug is sending
today energy(kWh)
total energy(kWh)
grid voltage AB(V)
actual output power(W)
DC voltage 1(V)

Re: Python Plugin: Growatt Solar Inverter via USB RS485 Modbus

Posted: Tuesday 20 June 2017 12:43
by jeroenst