Get GoodWe data with Powershell

Get GoodWe data with Powershell

I recently had a few solar panels installed over the roof of my house and right after that I thought, how can I get GoodWe data with Powershell?

Edit 20190613: GoodWe has switched over to the SEMS Portal and ever since the script stopped working. Thankfully, SEMS has an API available, have a look at this post on how to get started, it’s very simple: Get SEMS/GoodWe data with Powershell. Also, you may still be able to use the method shown in this article, if your inverter is still registered with goodwe’s old portal. In my case it started working right after I logged on to http://eu.goodwe-power.com (but I kept https://www.goodwe-power.com/.. in the $url). I also tested by replacing https://goodwe-power.com in the url with http://eu.goodwe-power.com and it worked as well.

GoodWe is the brand of the inverter installed, which connects to my home wifi and sends data automatically to the GoodWe Portal. The model I have is the GW4200D-NS.

I have to say that I wasn’t happy with the app I was provided with, neither was I happy with the portal, which refreshes the Real Time Data every 15 minutes! What kind of real time is that? However, to be fairly honest, why would you want to see actual Read Time readings? Well, because I want to. 🙂

Before looking for a solution on my own, I always search online, I don’t want to re-invent the wheel, so I found a post where I got the main idea: https://brnrd.eu/misc/2016-03-13/goodwe-logging-to-pvoutput.html . This post describes a way of grabbing the data from a non-Windows environment.

Important: I am not (nor is the post above) grabbing the data directly from the inverter, but I am leveraging the GoodWe portal information. An idea I have is to sniff the traffic the inverter sends to goodwe, capture it and re-utilise it, however I’m not too interested in that yet as the solution I have works fine.

Edit 20180605: GoodWe has started using HTTPS, so the previous script got broken because of this. I’ve updated it (just changed the URL from http to https) and the script is working as usual.

Dirty Notes

I’ll try to make it quick as the guy from the post above and myself have done most of the dirty work, I will just say that this required testing and some in-html reading. Thanks to the builtin Chrome Developer functions (F12), I was able to see quiet a few information, including the URL powershell had to grab its data from.

Two ways we can do this

  1. Grabbing the xls file for the current month.
    • GoodWe has an “Historic Data” tab that you can Export as well. I did find a way to get it exported it and then I grabbed the info from there. Unfortunately it required Excel for me to leverage the powershell cmdlets and also the DLL out there to work with XLS files (not xlsx) won’t work after a certain file size, so after the first half of the month (14MB or so), it would have stopped working giving errors. As I was not interested in getting Excel installed just for this, and I wanted a better way (than downloading 14+MB every minute), I went for option 2.
  2. Grab the data from the loaded Graph in the webpage, which contains updated data every 5 minutes.
    • goodwe-graph

URL

The post on brnrd.eu says to use the URL “https://www.goodwe-power.com/PowerStationPlatform/PowerStationReport/QueryTypeChanged” which updates every 10 minutes or so. However, after some digging, I found another URL that would refresh the data every 5: https://www.goodwe-power.com/PowerStationPlatform/PowerStationReport/QueryTypeChangedFor5Minutes

goodwe-url-5minutes

Process

What we need

  • The Inverter SN, something like 913100PQS071Z0112 (I made that up)
  • The Power Station ID, something like 33nn3332-4c19-232b-9h14-gbh0c2w490q1 (I made also this one up)

We also need other info, which don’t need to be provided by you, I’ll go through them later on.

How to get the Inverter SN and the Power Station ID

I suggest you to use Chrome or Firefox.

Inverter SN

The easy way to get this is by going to the Inverter and looking at the label and look for the S/N. Or else, you can do the following:

  • Log on the GoodWe Portal (https://goodwe-power.com)
  • Under Overview, you’ll find the SN there at the bottom.
Power Station ID

For this one, we will just need to view the GoodWe Portal source code.

  • Log on the GoodWe Portal (https://goodwe-power.com)
  • Right click and “View Source Page”
    • goodwe-view-page-source
  • Search the page for <input id=”ID” name=”ID”
    • There it is, you’re interested in what’ within “value” (the part I obfuscated in the screenshot).
    • goodwe-powerstationID-page-source

The Script

Just change the InvertSN and the PowerStationID from the script below and you should be good.

# Main Parameters
$url = "https://www.goodwe-power.com/PowerStationPlatform/PowerStationReport/QueryTypeChangedFor5Minutes"
$InverterSN = "913100PQS071Z0112"
$PowerStationID = "33nn3332-4c19-232b-9h14-gbh0c2w490q1"
$QueryType=0
$sleepTime = 30 #Time to sleep at every cicle >> This will change later on as well!!

#Infinite Loop
While (1)
{
#Get the date at every cycle
$DateFrom = Get-Date -Format yyy-MM-dd
# Get the info
# Build the Post parameters
$postparams = @{InventerSN=$InverterSN; DateFrom=$DateFrom; PowerStationID=$PowerStationID; QueryType=$QueryType}
$content = (Invoke-WebRequest -Uri $url -Method Post -Body $postparams).content.Replace('{"YAxis":"','').Replace('quot;','').Replace('[','').Replace(']','').Replace('{','').Replace('},','').Replace('","XAxis":"','|').Split('>> |')[0].Replace('name:','|').Split('|')

# Get the latest reading above 0
$ReadindAboveZeroCounter = 0 #This will store the value of $i in the For cycle ahead

$Content_PGridW_values = (($content[1] -split (',data:'))[1]).split(',') #This gets the values only for PGrid(W)

For ($i=0; $i -lt ($Content_PGridW_values.count); $i++){

	If ($Content_PGridW_values[$i] -gt 0){
		$ReadindAboveZeroCounter = $i
	}
	
}

#At this stage, if $ReadindAboveZeroCounter equals 0, it means that there are only Zeros

$LastReadingTime = "" # This variable will hold the time of the latest value

If ($ReadindAboveZeroCounter -eq 0){ #If there are only 0s

	$Current_PGridW = 0
	$Current_Temperature = 0
	#If there are only Zeros, then current eday will equal 0 too
	$Current_EDay = 0
	
	#Now we need to find the latest ETotal from the day before!
		$PreviousDay = (get-date).AddDays(-1).ToString("yyy-MM-dd")
		# Build the Post parameters
		$postparams = @{InventerSN=$InverterSN; DateFrom=$PreviousDay; PowerStationID=$PowerStationID; QueryType=$QueryType}
		# Get the info from PreviousDay
		$content_previousDay = (Invoke-WebRequest -Uri $url -Method Post -Body $postparams).content.Replace('{"YAxis":"','').Replace('quot;','').Replace('[','').Replace(']','').Replace('{','').Replace('},','').Replace('","XAxis":"','|').Split('>> |')[0].Replace('name:','|').Split('|')
		
		$ReadindAboveZeroCounter_PreviousDay = 0
		$Content_ETotal_values = (($content_previousDay[16] -split (',data:'))[1]).split(',')
		
		#In theory, this FOR will have to find a value, unless the previous day the system was shutdown for some reason.
		For ($i=0; $i -lt ($Content_ETotal_values.count); $i++){

			If ($Content_ETotal_values[$i] -gt 0){
				$ReadindAboveZeroCounter_PreviousDay = $i
			}
			
		}
		
	$Current_ETotal = $Content_ETotal_values[$ReadindAboveZeroCounter_PreviousDay]
	$LastReadingTime = "Yesterday"

}
Else{
	#In this case, $ReadindAboveZeroCounter should have the latest reading!
	
	$Current_PGridW = $Content_PGridW_values[$ReadindAboveZeroCounter]
	$Current_Temperature = ((($content[15] -split (',data:'))[1]).split(','))[$ReadindAboveZeroCounter]
	$Current_EDay = ((($content[18] -split (',data:'))[1]).split(','))[$ReadindAboveZeroCounter]
	$Current_ETotal = ((($content[16] -split (',data:'))[1]).split(','))[$ReadindAboveZeroCounter]
	
	#Build the $LastReadingTime
	#As the data is gathered every 5 minutes, then Minutes passed are 5 multiplied the position of $i (so $ReadindAboveZeroCounter)
	$MinutesLastReading = $ReadindAboveZeroCounter*5
	#Convert the minutes in Hours/Days
	$TimeSpan = New-TimeSpan -Minutes $MinutesLastReading
	$LastReadingTime = $TimeSpan.ToString("hh\:mm")

}


#Build hash with info
$Latest_Hash = @{}
    $Latest_Hash += @{"Time" = $LastReadingTime}
    $Latest_Hash += @{"PGrid(W)" = $Current_PGridW}
    $Latest_Hash += @{"ETotal(kWh)" = $Current_ETotal}
    $Latest_Hash += @{"Temperature(C)" = $Current_Temperature}
    $Latest_Hash += @{"EDay(kWh)" = $Current_EDay}

#Display hash
$Latest_Hash.ForEach({[PSCustomObject]$_}) | Format-Table -AutoSize

Sleep -Seconds $sleepTime
}

Basically the script will grab the data from the website for you and also format it in a way that gets 4 arrays of data:

  • PGrid(W) >> It’s the current production in Watt/h
  • Temperature (C) >> The temperature in Celsius
  • ETotal (kWh) >> The total amount of energy in KWh produced so far by the system.
  • EDay (kWh) >> The amount of energy in KWh produced today by the system

I’ve added a little check in the script: let’s say the script is running and it’s midnight, so when the inverter is off, the script will notice that PGrid(W) returns only zeros, so it reports everything to 0, except for the Time, which is set to “Yesterday” and except for ETotal (kWh) which the script will grab from the previous day.

The time in the script is taken from the number of minute passed: The amount of data reported by the web interface is every 5 minutes, which means we will have 289 entries in 24 hours (including 00:00 and 24:00). The script uses a counter to see which one is the last value, let’s say it’s the entry number 100, multiplies by 5 minutes and converts it in time we understand. That is done by this bit:

$TimeSpan = New-TimeSpan -Minutes $MinutesLastReading
$LastReadingTime = $TimeSpan.ToString("hh\:mm")

It’s important to notice that the PGrid changes way more often than just once every 5 minutes, here’s an example:

goodwe-powershell-monitoring-output

As you can see, for the past 5 times, the time is stuck at 13:40, however the PGrid(W) changes every 1 minute circa (the script runs every 30 seconds or so).

Now, the script just displays the information on screen and it’s adjusted for anybody who wants to grab the data, however I made another script (very similar) which I won’t show you (at least not today) that basically will drop all of the info in a php file that is integrated in the index.php of an IIS website and that will show me a simple output. Something very primitive for now (that is displayed very well on a mobile):

goodwe-php-monitoring

I hope this was informative and will help you building your own monitoring, in Windows 🙂 I didn’t want to go too deep into the details, if not this post would’ve became an e-book.

IT Droplets

IT Droplets