Python Plugin: Growatt Solar Inverter via USB RS232 or RS485 Modbus
Posted: Sunday 18 June 2017 20:31
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
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