Growatt solar panels support

Can support for Growatt solar panels be added to Home assistant?

There is already an API on github available: https://github.com/Sjord/growatt_api_client

Did not test this of course ;-).

Thank you for pointing out the API on Github, I was trying to create a web scraper sensor for some time.
If you have appdaemon installed, I have an app to collect the Current Power Output and Todays Total Power Out put in to sensors as below

"""Create sensors for Current Power Output and Daily Power Generation from Growatt Invertor
  Using api client from https://github.com/Sjord/growatt_api_client
  
    Features:
       - Updates the sensors every 5 minutes 
       - Do not fetch the data from Growatt at night

    Arguments:
        username: Username to login to server.growatt.com
        password: Password for server.growatt.com

    Example configuration
    In apps.yaml:
    Growatt:
      class: GrowattSensor
      module: growattsensor
      username: 'user'
      password: 'pwd'

    """

from enum import IntEnum
import datetime
import hashlib
import json
import requests
import appdaemon.plugins.hass.hassapi as hass

def hash_password(password):
    """
    Normal MD5, except add c if a byte of the digest is less than 10.
    """
    password_md5 = hashlib.md5(password.encode('utf-8')).hexdigest()
    for i in range(0, len(password_md5), 2):
        if password_md5[i] == '0':
            password_md5 = password_md5[0:i] + 'c' + password_md5[i + 1:]
    return password_md5


class Timespan(IntEnum):
    day = 1
    month = 2


class GrowattApi:
    server_url = 'http://server.growatt.com/'

    def __init__(self):
        self.session = requests.Session()

    def get_url(self, page):
        return self.server_url + page

    def login(self, username, password):
        password_md5 = hash_password(password)
        response = self.session.post(self.get_url('LoginAPI.do'), data={
            'userName': username,
            'password': password_md5
        })
        data = json.loads(response.content.decode('utf-8'))
        return data['back']

    def plant_list(self, user_id):
        response = self.session.get(self.get_url('PlantListAPI.do'),
                                    params={'userId': user_id},
                                    allow_redirects=False)
        if response.status_code != 200:
            raise RuntimeError("Request failed: %s", response)
        data = json.loads(response.content.decode('utf-8'))
        return data['back']

    def plant_detail(self, plant_id, timespan, date):
        assert timespan in Timespan
        if timespan == Timespan.day:
            date_str = date.strftime('%Y-%m-%d')
        elif timespan == Timespan.month:
            date_str = date.strftime('%Y-%m')

        response = self.session.get(self.get_url('PlantDetailAPI.do'), params={
            'plantId': plant_id,
            'type': timespan.value,
            'date': date_str
        })
        data = json.loads(response.content.decode('utf-8'))
        return data['back']


class GrowattSensor(hass.Hass):
  ''' Class to create Growatt Sensors in HA'''
  def initialize(self):
    self.handle = None
    self.username = self.args["username"]
    self.password = self.args["password"]
    self.api = GrowattApi()
    self.currentPowerOutput = "0"
    self.totalPowerGenerated = "0"
    #update sensor in every 5 minutes
    self.run_every(self.updateSensor, self.datetime(), 5 * 60)
    #update daily power output at night
    #runtime = datetime.time(23, 0, 0)
    #self.run_daily(self.run_daily_c, runtime)

  def updateSensor(self, kwargs):
    '''Function to update sensors)'''
    if self.now_is_between("sunrise - 00:45:00", "sunset + 00:45:00"):
      self.log("Updating sensors")
      login_res = self.api.login(self.username, self.password)
      user_id = login_res['userId']
      plant_info = self.api.plant_list(user_id)
      data, kw = (plant_info['data'][0]['currentPower']).split( )
      self.currentPowerOutput = data
      self.log("Current power output is {} kW".format(data))
      self.set_state('sensor.currentsolarpower',state=data,attributes={"friendly_name":'Current Power Output', 'unit_of_measurement':'kW', 'icon':'mdi:solar-power'})
      data1, kwh = (plant_info['data'][0]['todayEnergy']).split( )
      self.totalPowerGenerated = data1
      self.log("Todays power production is {} kWh".format(data1))
      self.set_state('sensor.dailypoweroutput',state=data1,attributes={"friendly_name":'Todays Power Generation', 'unit_of_measurement':'kWh', 'icon':'mdi:solar-power'})
    else:
      self.log("Insering old data")
      self.set_state('sensor.currentsolarpower',state=self.currentPowerOutput,attributes={"friendly_name":'Current Power Output', 'unit_of_measurement':'kW', 'icon':'mdi:solar-power'})
      self.set_state('sensor.dailypoweroutput',state=self.totalPowerGenerated,attributes={"friendly_name":'Todays Power Generation', 'unit_of_measurement':'kWh', 'icon':'mdi:solar-power'})```

I managed to create a custom component for this

Please test if you can

Cool, will test this soon, after I figured out to make a dasboard with appdeamon!

I connected my Fronius via JSON, it was handy that the interface card already supported this, i believe you could use SNMP as well, i use SNMP to monitor my UPS and other networking gear, might be worth a look to see if you can get values that way.

Just a question from a noob, (first time I’ve done something like this). So… how does one go about outputting RS232 from the inverter so that it’s readable in HASSIO? I can get an RS232 > Ethernet cable, but surely parsing JSON data from the inverter to HASSIO is more complicated.

App did not initialize:
2019-02-03 17:24:15.994127 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/growattapi.py - ignoring
2019-02-03 17:24:15.995041 INFO AppDaemon: Initializing app Growatt using class GrowattSensor from module growattsensor
2019-02-03 17:24:15.996038 WARNING AppDaemon: Unable to find module module growattsensor - Growatt is not initialized

from enum import IntEnum
import datetime
import hashlib
import json
import requests
import appdaemon.plugins.hass.hassapi as hass

def hash_password(password):
    """
    Normal MD5, except add c if a byte of the digest is less than 10.
    """
    password_md5 = hashlib.md5(password.encode('utf-8')).hexdigest()
    for i in range(0, len(password_md5), 2):
        if password_md5[i] == '0':
            password_md5 = password_md5[0:i] + 'c' + password_md5[i + 1:]
    return password_md5


class Timespan(IntEnum):
    day = 1
    month = 2


class GrowattApi:
    server_url = 'http://server.growatt.com/'


    def __init__(self):
        self.session = requests.Session()

    def get_url(self, page):
        return self.server_url + page

    def login(self, username, password):
        password_md5 = hash_password(password)
        response = self.session.post(self.get_url('LoginAPI.do'), data={
            'userName': username,
            'password': password_md5
        })
        data = json.loads(response.content.decode('utf-8'))
        return data['back']

    def plant_list(self, user_id):
        response = self.session.get(self.get_url('PlantListAPI.do'),
                                    params={'userId': user_id},
                                    allow_redirects=False)
        if response.status_code != 200:
            raise RuntimeError("Request failed: %s", response)
        data = json.loads(response.content.decode('utf-8'))
        return data['back']

    def plant_detail(self, plant_id, timespan, date):
        assert timespan in Timespan
        if timespan == Timespan.day:
            date_str = date.strftime('%Y-%m-%d')
        elif timespan == Timespan.month:
            date_str = date.strftime('%Y-%m')

        response = self.session.get(self.get_url('PlantDetailAPI.do'), params={
            'plantId': plant_id,
            'type': timespan.value,
            'date': date_str
        })
        data = json.loads(response.content.decode('utf-8'))
        return data['back']


class GrowattSensor(hass.Hass):
  ''' Class to create Growatt Sensors in HA'''
  def initialize(self):
    self.handle = None
    self.username = self.args["username"]
    self.password = self.args["password"]
    self.api = GrowattApi()
    self.currentPowerOutput = "0"
    self.totalPowerGenerated = "0"
    #update sensor in every 5 minutes
    self.run_every(self.updateSensor, self.datetime(), 5 * 60)
    #update daily power output at night
    #runtime = datetime.time(23, 0, 0)
    #self.run_daily(self.run_daily_c, runtime)

  def updateSensor(self, kwargs):
    '''Function to update sensors)'''
    if self.now_is_between("sunrise - 00:45:00", "sunset + 00:45:00"):
      self.log("Updating sensors")
      login_res = self.api.login(self.username, self.password)
      user_id = login_res['userId']
      plant_info = self.api.plant_list(user_id)
      data, kw = (plant_info['data'][0]['currentPower']).split( )
      self.currentPowerOutput = data
      self.log("Current power output is {} kW".format(data))
      self.set_state('sensor.currentsolarpower',state=data,attributes={"friendly_name":'Current Power Output', 'unit_of_measurement':'kW', 'icon':'mdi:solar-power'})
      data1, kwh = (plant_info['data'][0]['todayEnergy']).split( )
      self.totalPowerGenerated = data1
      self.log("Todays power production is {} kWh".format(data1))
      self.set_state('sensor.dailypoweroutput',state=data1,attributes={"friendly_name":'Todays Power Generation', 'unit_of_measurement':'kWh', 'icon':'mdi:solar-power'})
    else:
      self.log("Insering old data")
      self.set_state('sensor.currentsolarpower',state=self.currentPowerOutput,attributes={"friendly_name":'Current Power Output', 'unit_of_measurement':'kW', 'icon':'mdi:solar-power'})
      self.set_state('sensor.dailypoweroutput',state=self.totalPowerGenerated,attributes={"friendly_name":'Todays Power Generation', 'unit_of_measurement':'kWh', 'icon':'mdi:solar-power'})

Problem was in the apps file.
Content changend to:

growattapi:
  class: growattsensor
  module: growattapi
  username: !secret username
  password: !secret password

Now I get readings from the server.
Next thing to find out is how to keep the readings alive after a reset of the system. Appdeamon sensor is pretty volatile.

Instead of appdaemon use the custom component from
https://community.home-assistant.io/t/anyone-experience-with-connecting-a-growatt-solar-inverter/60430/2

Didyou ever got this answered? Rs232 local reading without growatt cloud?

Is this all based on local reading or cloud?

This should be possible with https://pypi.org/project/growattRS232/
However there is no Home Assistant integration for it yet as far as i know and if will require an RS232 to USB adapter.

Any of the integrations for Growatt that need a username and password are likely cloud polling

How can i get the monthly results to see in HA. I see only a sensor created for Today and output power etc. ?? I am using the integration from HA.