File: mix_example.py

package info (click to toggle)
growattserver 1.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 296 kB
  • sloc: python: 1,344; makefile: 2
file content (208 lines) | stat: -rwxr-xr-x 10,855 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import growattServer
import datetime
import getpass
import pprint

"""
This is a very trivial script that logs into a user's account and prints out useful data for a "Mix" system (Hybrid).
The first half of the logic is applicable to all types of system. There is a clear point (marked in the script) where we specifically
make calls to the "mix" WebAPI calls, at this point other types of systems will no longer work.
This has been tested against my personal system (muppet3000) which is a hybrid inverter system.

Throughout the script there are points where 'pp.pprint' has been commented out. If you wish to see all the data that is returned from those
specific library calls, just uncomment them and they will appear as part of the output.

NOTE - For some reason (not sure if this is just specific to my system or not) the "export to grid" daily total and overall total values don't seem to be populating. As such they are untested.
This has been causing problems on my WebUI and mobile app too, it is not a bug in this library, the output from this script has been updated to reflect it's inaccuracy.
"""

pp = pprint.PrettyPrinter(indent=4)

"""
A really hacky function to allow me to print out things with an indent in-front
"""
def indent_print(to_output, indent):
  indent_string = ""
  for x in range(indent):
    indent_string += " "
  print(indent_string + to_output)

#Prompt user for username
username=input("Enter username:")

#Prompt user to input password
user_pass=getpass.getpass("Enter password:")

api = growattServer.GrowattApi()
login_response = api.login(username, user_pass)

plant_list = api.plant_list(login_response['user']['id'])
#pp.pprint(plant_list)

print("***Totals for all plants***")
pp.pprint(plant_list['totalData'])
print("")

print("***List of plants***")
for plant in plant_list['data']:
  indent_print("ID: %s, Name: %s"%(plant['plantId'], plant['plantName']), 2)
print("")

for plant in plant_list['data']:
  plant_id = plant['plantId']
  plant_name = plant['plantName']
  plant_info=api.plant_info(plant_id)
  #pp.pprint(plant_info)
  print("***Info for Plant %s - %s***"%(plant_id, plant_name))
  #There are more values in plant_info, but these are some of the useful/interesting ones
  indent_print("CO2 Reducion: %s"%(plant_info['Co2Reduction']),2)
  indent_print("Nominal Power (w): %s"%(plant_info['nominal_Power']),2)
  indent_print("Solar Energy Today (kw): %s"%(plant_info['todayEnergy']),2)
  indent_print("Solar Energy Total (kw): %s"%(plant_info['totalEnergy']),2)
  print("")
  indent_print("Devices in plant:",2)
  for device in plant_info['deviceList']:
    device_sn = device['deviceSn']
    device_type = device['deviceType']
    indent_print("- Device - SN: %s, Type: %s"%(device_sn, device_type),4)

  print("")
  for device in plant_info['deviceList']:
    device_sn = device['deviceSn']
    device_type = device['deviceType']
    indent_print("**Device - SN: %s, Type: %s**"%(device_sn, device_type),2)
    #NOTE - This is the bit where we specifically only handle information on Mix devices - this won't work for non-mix devices

    #These two API calls return lots of duplicated information, but each also holds unique information as well
    mix_info = api.mix_info(device_sn, plant_id)
    pp.pprint(mix_info)
    mix_totals = api.mix_totals(device_sn, plant_id)
    #pp.pprint(mix_totals)
    indent_print("*TOTAL VALUES*", 4)
    indent_print("==Today Totals==", 4)
    indent_print("Battery Charge (kwh): %s"%(mix_info['eBatChargeToday']),6)
    indent_print("Battery Discharge (kwh): %s"%(mix_info['eBatDisChargeToday']),6)
    indent_print("Solar Generation (kwh): %s"%(mix_info['epvToday']),6)
    indent_print("Local Load (kwh): %s"%(mix_totals['elocalLoadToday']),6)
    indent_print("Export to Grid (kwh): %s"%(mix_totals['etoGridToday']),6)
    indent_print("==Overall Totals==",4)
    indent_print("Battery Charge: %s"%(mix_info['eBatChargeTotal']),6)
    indent_print("Battery Discharge (kwh): %s"%(mix_info['eBatDisChargeTotal']),6)
    indent_print("Solar Generation (kwh): %s"%(mix_info['epvTotal']),6)
    indent_print("Local Load (kwh): %s"%(mix_totals['elocalLoadTotal']),6)
    indent_print("Export to Grid (kwh): %s"%(mix_totals['etogridTotal']),6)
    print("")

    mix_detail = api.mix_detail(device_sn, plant_id)
    #pp.pprint(mix_detail)

    #Some of the 'totals' values that are returned by this function do not align to what we would expect, however the graph data always seems to be accurate.
    #Therefore, here we take a moment to calculate the same values provided elsewhere but based on the graph data instead
    #The particular stats that we question are 'load consumption' (elocalLoad)  and 'import from grid' (etouser) which seem to be calculated from one-another
    #It would appear that 'etouser' is calculated on the backend incorrectly for systems that use AC battery charged (e.g. during cheap nighttime rates)
    pacToGridToday = 0.0
    pacToUserToday = 0.0
    pdischargeToday = 0.0
    ppvToday = 0.0
    sysOutToday = 0.0

    chartData = mix_detail['chartData']
    for time_entry, data_points in chartData.items():
      #For each time entry convert it's wattage into kWh, this assumes that the wattage value is
      #the same for the whole 5 minute window (it's the only assumption we can make)
      #We Multiply the wattage by 5/60 (the number of minutes of the time window divided by the number of minutes in an hour)
      #to give us the equivalent kWh reading for that 5 minute window
      pacToGridToday += float(data_points['pacToGrid']) * (5/60)
      pacToUserToday += float(data_points['pacToUser']) * (5/60)
      pdischargeToday += float(data_points['pdischarge']) * (5/60)
      ppvToday += float(data_points['ppv']) * (5/60)
      sysOutToday += float(data_points['sysOut']) * (5/60)

    mix_detail['calculatedPacToGridTodayKwh'] = round(pacToGridToday,2)
    mix_detail['calculatedPacToUserTodayKwh'] = round(pacToUserToday,2)
    mix_detail['calculatedPdischargeTodayKwh'] = round(pdischargeToday,2)
    mix_detail['calculatedPpvTodayKwh'] = round(ppvToday,2)
    mix_detail['calculatedSysOutTodayKwh'] = round(sysOutToday,2)

    #Option to print mix_detail again now we've made the additions
    #pp.pprint(mix_detail)

    dashboard_data = api.dashboard_data(plant_id)
    #pp.pprint(dashboard_data)

    indent_print("*TODAY TOTALS BREAKDOWN*", 4)
    indent_print("Self generation total (batteries & solar - from API) (kwh): %s"%(mix_detail['eCharge']),6)
    indent_print("Load consumed from solar (kwh): %s"%(mix_detail['eChargeToday']),6)
    indent_print("Load consumed from batteries (kwh): %s"%(mix_detail['echarge1']),6)
    indent_print("Self consumption total (batteries & solar - from API) (kwh): %s"%(mix_detail['eChargeToday1']),6)
    indent_print("Load consumed from grid (kwh): %s"%(mix_detail['etouser']),6)
    indent_print("Total imported from grid (Load + AC charging) (kwh): %s"%(dashboard_data['etouser'].replace('kWh','')),6)
    calculated_consumption = float(mix_detail['eChargeToday']) + float(mix_detail['echarge1']) + float(mix_detail['etouser'])
    indent_print("Load consumption (calculated) (kwh): %s"%(round(calculated_consumption,2)),6)
    indent_print("Load consumption (API) (kwh): %s"%(mix_detail['elocalLoad']),6)

    indent_print("Exported (kwh): %s"%(mix_detail['eAcCharge']), 6)

    solar_to_battery = round(float(mix_info['epvToday']) - float(mix_detail['eAcCharge']) - float(mix_detail['eChargeToday']),2)
    indent_print("Solar battery charge (calculated) (kwh): %s"%(solar_to_battery), 6)
    ac_to_battery = round(float(mix_info['eBatChargeToday']) - solar_to_battery,2)
    indent_print("AC battery charge (calculated) (kwh): %s"%(ac_to_battery), 6)
    print("")

    indent_print("*TODAY TOTALS COMPARISONS*", 4)

    indent_print("Export to Grid (kwh) - TRUSTED:", 6)
    indent_print("mix_totals['etoGridToday']: %s"%(mix_totals['etoGridToday']), 8)
    indent_print("mix_detail['eAcCharge']: %s"%(mix_detail['eAcCharge']), 8)
    indent_print("mix_detail['calculatedPacToGridTodayKwh']: %s"%(mix_detail['calculatedPacToGridTodayKwh']), 8)
    print("")

    indent_print("Imported from Grid (kwh) - TRUSTED:", 6)
    indent_print("dashboard_data['etouser']: %s"%(dashboard_data['etouser'].replace('kWh','')), 8)
    indent_print("mix_detail['calculatedPacToUserTodayKwh']: %s"%(mix_detail['calculatedPacToUserTodayKwh']), 8)
    print("")

    indent_print("Battery discharge (kwh) - TRUSTED:", 6)
    indent_print("mix_info['eBatDisChargeToday']: %s"%(mix_info['eBatDisChargeToday']), 8)
    indent_print("mix_totals['edischarge1Today']: %s"%(mix_totals['edischarge1Today']), 8)
    indent_print("mix_detail['echarge1']: %s"%(mix_detail['echarge1']), 8)
    indent_print("mix_detail['calculatedPdischargeTodayKwh']: %s"%(mix_detail['calculatedPdischargeTodayKwh']), 8)
    print("")

    indent_print("Solar generation (kwh) - TRUSTED:", 6)
    indent_print("mix_info['epvToday']: %s"%(mix_info['epvToday']), 8)
    indent_print("mix_totals['epvToday']: %s"%(mix_totals['epvToday']), 8)
    indent_print("mix_detail['calculatedPpvTodayKwh']: %s"%(mix_detail['calculatedPpvTodayKwh']), 8)
    print("")

    indent_print("Load Consumption (kwh) - TRUSTED:", 6)
    indent_print("mix_totals['elocalLoadToday']: %s"%(mix_totals['elocalLoadToday'],), 8)
    indent_print("mix_detail['elocalLoad']: %s"%(mix_detail['elocalLoad']), 8)
    indent_print("mix_detail['calculatedSysOutTodayKwh']: %s"%(mix_detail['calculatedSysOutTodayKwh']), 8)
    print("")


    #This call gets all of the instantaneous values from the system e.g. current load, generation etc.
    mix_status = api.mix_system_status(device_sn, plant_id)
    #pp.pprint(mix_status)
    #NOTE - There are some other values available in mix_status, however these are the most useful ones
    indent_print("*CURRENT VALUES*",4)
    indent_print("==Batteries==",4)
    indent_print("Charging Batteries at (kw): %s"%(mix_status['chargePower']),6)
    indent_print("Discharging Batteries at (kw): %s"%(mix_status['pdisCharge1']),6)
    indent_print("Batteries %%: %s"%(mix_status['SOC']),6)

    indent_print("==PVs==",4)
    indent_print("PV1 wattage: %s"%(mix_status['pPv1']),6)
    indent_print("PV2 wattage: %s"%(mix_status['pPv2']),6)
    calc_pv_total = (float(mix_status['pPv1']) + float(mix_status['pPv2']))/1000
    indent_print("PV total wattage (calculated) - KW: %s"%(round(calc_pv_total,2)),6)
    indent_print("PV total wattage (API) - KW: %s"%(mix_status['ppv']),6)

    indent_print("==Consumption==",4)
    indent_print("Local load/consumption - KW: %s"%(mix_status['pLocalLoad']),6)

    indent_print("==Import/Export==",4)
    indent_print("Importing from Grid - KW: %s"%(mix_status['pactouser']),6)
    indent_print("Exporting to Grid - KW: %s"%(mix_status['pactogrid']),6)