A basic overview of scraping information from the Goodwe SEMS portal to use in other systems.

– Last Updated 20/12/2022 : I have been informed this code no longer works. Goodwe have moved to V3 of their API. The download at the bottom of the page should have working code but i will not have chance to update this article to reflect the changes until the holidays.
(Note – I have found the documentation for the Goodwe API officially so this page will change over the coming weeks to use a more official implementation)

What Does an API Do?
An API (Application Programming Interface) is basically one of the many ways to get data in and out of a system. It can involve human input (to change settings) or can be automated (basically you use one machine to control the other) through various rules and commands.
Goodwe have released their own API to the public which allows users to both read & write to the system to control it as required. This can be something as simple as pulling the latest PV output power to display on a webpage to controlling charge & discharge of the system for something as complex as Octopus Agile.
This page tries to explain with working examples the some of the API and examples of what can be done with them.
An example of the typical Goodwe API output is shown below:

{
    "sn":  "---REDACTED----",
    "powerstation_id":  "1c105535---REDACTED----0b72a1e4",
    "name":  "GW 2500 BP",
    "model_type":  "GW2500-BP",
    "change_type":  0,
    "change_time":  0,
    "capacity":  2.548,
    "eday":  0.0,
    "iday":  0.0,
    "etotal":  0.0,
    "itotal":  0.0,
    "hour_total":  658.0,
    "status":  1,
    "turnon_time":  1644745427997,
    "pac":  677.8,
    "tempperature":  19.1,
    "vpv1":  338.9,
    "vpv2":  null,
    "vpv3":  null,
    "vpv4":  null,
    "ipv1":  2.0,
    "ipv2":  null,
    "ipv3":  null,
    "ipv4":  null,
    "vac1":  338.8,
    "vac2":  null,
    "vac3":  null,
    "iac1":  0.1,
    "iac2":  null,
    "iac3":  null,
    "fac1":  50.03,
    "fac2":  null,
    "fac3":  null,
    "istr1":  null,
    "istr2":  null,
    "istr3":  null,
    "istr4":  null,
    "istr5":  null,
    "istr6":  null,
    "istr7":  null,
    "istr8":  null,
    "istr9":  null,
    "istr10":  null,
    "istr11":  null,
    "istr12":  null,
    "istr13":  null,
    "istr14":  null,
    "istr15":  null,
    "istr16":  null,
    "last_time":  1649234737283,
    "vbattery1":  49.4,
    "ibattery1":  -0.6,
    "pmeter":  -317.0,
    "soc":  27.0,
    "soh":  0.0,
    "bms_discharge_i_max":  0.0,
    "bms_charge_i_max":  0.0,
    "bms_warning":  0,
    "bms_alarm":  0,
    "battary_work_mode":  3,
    "workmode":  64,
    "vload":  null,
    "iload":  null,
    "firmwareversion":  10003.0,
    "bmssoftwareversion":  null,
    "pbackup":  null,
    "seller":  0.0,
    "buy":  0.0,
    "yesterdaybuytotal":  null,
    "yesterdaysellertotal":  null,
    "yesterdayct2sellertotal":  null,
    "yesterdayetotal":  null,
    "yesterdayetotalload":  null,
    "yesterdaylastime":  0,
    "thismonthetotle":  0.0,
    "lastmonthetotle":  0.0,
    "ram":  null,
    "outputpower":  33.8,
    "fault_messge":  0,
    "battery1sn":  null,
    "battery2sn":  null,
    "battery3sn":  null,
    "battery4sn":  null,
    "battery5sn":  null,
    "battery6sn":  null,
    "battery7sn":  null,
    "battery8sn":  null,
    "pf":  null,
    "pv_power":  0.0,
    "reactive_power":  0.0,
    "leakage_current":  0,
    "isbuettey":  true,
    "isbuetteybps":  false,
    "isbuetteybpu":  true,
    "isESUOREMU":  false,
    "backUpPload_S":  null,
    "backUpVload_S":  null,
    "backUpIload_S":  null,
    "backUpPload_T":  null,
    "backUpVload_T":  null,
    "backUpIload_T":  null,
    "eTotalBuy":  null,
    "eDayBuy":  null,
    "eBatteryCharge":  null,
    "eChargeDay":  null,
    "eBatteryDischarge":  null,
    "eDischargeDay":  null,
    "battStrings":  null,
    "meterConnectStatus":  null,
    "mtActivepowerR":  null,
    "mtActivepowerS":  null,
    "mtActivepowerT":  null,
    "ezPro_connect_status":  null,
    "dataloggersn":  null,
    "equipment_name":  null,
    "hasmeter":  true,
    "meter_type":  null,
    "pre_hour_lasttotal":  null,
    "pre_hour_time":  null,
    "current_hour_pv":  0.0,
    "extend_properties":  null,
    "eP_connect_status_happen":  null,
    "eP_connect_status_recover":  null,
    "total_sell":  0.0,
    "total_buy":  0.0,
    "errors":  [

               ],
    "safetyConutry":  33.0,
    "deratingMode":  null
}

OK so that’s pretty boring but it does tell you a lot of key information about what the inverter is doing “right now” – So what you could do is take that information and create something like the display below (note the import/export figures across the top and the gauges on the lower right hand side.) By regularly updating the data throughout the day (called “polling”) to create yourself a nice little home energy monitor or even this website.

Background Information

So before we get into pulling information from the API itself we need to cover a few basic things first.
I’ve already done this kind of thing for the Givenergy API. So if you head over to that page and have a read of the background information the theories about how and API works are the same.

For now, you could copy ALL the earlier example above (“Typical Goodwe API Output”) and paste into the JSON Path Finder site: (remember you’ll need to clear the example text first on the JSON Path Finder)
You should see something like the below:

This shows you the data keys & values the API has on your system which can be used for other purposes. The Path to the data is shown at the top (in this case we have selected vpv1 which is 338.9 Volts.

Example 1 (Getting Data OUT):

So onto the good stuff. Start up Powershell ISE (On windows click the start menu then just start typing Powershell. It’s usually the second one in the list and is the lighter blue of the 2 items windows search will probably give you – if you get a dark blue command line window then you’ve opened the wrong one!)

Either download the examples at the end of this page or Copy and paste the below into the ISE: then File>Save As>(Wherever you want & whatever name you want.) NOTE: You will need to create a new folder next to the place you’ve saved the file called “Data”
Powershell files are suffixed .PS1 (they can also be opened, edited or written in Notepad should you wish)

#####User details here#####
##Givenergy Portal API Key Goes Below between " "


$email = "[email protected]"
$password = "password_here"
$Powerstation_Id = "Portal_ID_here"


########end user input#############


##Login to SEMS API ##
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("sec-ch-ua", "`" Not A;Brand`";v=`"99`", `"Chromium`";v=`"99`", `"Microsoft Edge`";v=`"99`"")
$headers.Add("Accept", "application/json, text/javascript, */*; q=0.01")
$headers.Add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
$headers.Add("X-Requested-With", "XMLHttpRequest")
$headers.Add("sec-ch-ua-mobile", "?0")
$headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.39")
$headers.Add("sec-ch-ua-platform", "`"Windows`"")
$headers.Add("Origin", "https://eu.semsportal.com")
$headers.Add("Sec-Fetch-Site", "same-origin")
$headers.Add("Sec-Fetch-Mode", "cors")
$headers.Add("Sec-Fetch-Dest", "empty")
$headers.Add("Referer", "https://eu.semsportal.com/home/login")
$headers.Add("Accept-Language", "en-GB,en;q=0.9,en-US;q=0.8")

$body = "account=$email&pwd=$password&code="

$response = Invoke-WebRequest 'https://eu.semsportal.com/Home/Login' -Method 'POST' -Headers $headers -Body $body -SessionVariable session
$response.Content | Out-File -FilePath.\Login.txt
$session | Out-File -FilePath.\Session.txt
Write-Output "Login Response Saved to: Login.txt" 


$headers2 = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers2.Add("sec-ch-ua", "`" Not A;Brand`";v=`"99`", `"Chromium`";v=`"99`", `"Microsoft Edge`";v=`"99`"")
$headers2.Add("Accept", "*/*")
$headers2.Add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
$headers2.Add("X-Requested-With", "XMLHttpRequest")
$headers2.Add("sec-ch-ua-mobile", "?0")
$headers2.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.39")
$headers2.Add("sec-ch-ua-platform", "`"Windows`"")
$headers2.Add("Origin", "https://eu.semsportal.com")
$headers2.Add("Sec-Fetch-Site", "same-origin")
$headers2.Add("Sec-Fetch-Mode", "cors")
$headers2.Add("Sec-Fetch-Dest", "empty")
$headers2.Add("Referer", "https://eu.semsportal.com/PowerStation/PowerStatusSnMin/$Powerstation_Id")
$headers2.Add("Accept-Language", "en-GB,en;q=0.9,en-US;q=0.8")

$body2 = "str=%7B%22api%22%3A%22v1%2FPowerStation%2FGetMonitorDetailByPowerstationId%22%2C%22param%22%3A%7B%22powerStationId%22%3A%22$Powerstation_Id%22%7D%7D"

$response2 = Invoke-RestMethod 'https://eu.semsportal.com/GopsApi/Post?s=v1/PowerStation/GetMonitorDetailByPowerstationId' -Method 'POST' -Headers $headers2 -Body $body2 -WebSession $session
$response2.data.inverter[0].invert_full | ConvertTo-Json -Depth 10 | Out-File -FilePath .\Data\GoodweData.txt -Encoding ASCII

Write-Output "Data Saved to: GoodweData.txt"
Write-Output "All done - Closing Powershell in 5...." 
start-sleep -s 5

Exit 

All you need to worry about is changing the following variables:
$email = “[email protected]
$password = “password_here”
$Powerstation_Id = “Portal_ID_here”


The first two are self explanatory – the login details you use for the SEMS portal. Powerstation ID (string of letters & numbers) is a little trickier but thankfully the SEMS portal is a fairly blunt instrument so you just need to copy the last part of the portal URL after you’ve logged in normally on your PC – Example below:

Once you’ve done that – hit save and your good to go.

Running the Script

So now we know what does what, we can run the script.
Making sure its saved, navigate to the file and right click > Run With Powershell.
(You should get a blue command interface pop up)
It may or may not ask you if you want to run this for security reasons. Select “y” (or I think from memory it’s “a” to accept for all)
The script should run and if successful, you will end up with a text file in the “Data” folder named “GoodweData.txt”
If you open it you will have your own latest inverter data – and your fist call to the API.

Now you should in theory be able to change the URL in the script to any other GET type URL for the Goodwe API. Remembering to change the output filename will allow you to have multiple scripts being able to be run in the same folder. I will include further examples at the end of this page later.

I have however in the download included a small Batch script (“Goodwe_Loop.Bat”) you can use to call the API in a loop every 5 mins (the Goodwe Data doesn’t update any faster than this so there is no need to poll it any less than 5 mins).
It also has the ability to FTP the resulting data file to another server should this be required (default to this is OFF)
Again this can be edited in Notepad to your needs by changing the following:

rem - ::::::::Change Settings as needed below:::::::

set refresh=300        (how often the loop runs in seconds)

set ftp=false          (use FTP to send the data somewhere - set to true to switch on)
set FTPIP=123.123.123.123      (the IP of the server to send to - ignore if not using FTP mode)
set FTPUSRPW=FTP_username:FTP_Password   (the Username & Password of the FTP server, seperated by ":"

rem - ::::::::Do not Change anything below this line:::::::::

Finally

Hopefully this has been a fairly useful introduction to the Goodwe API and how to use it’s basic calls.
Have a play with some of the other calls from the API by changing the URLs requested to get a feel for how it behaves. Remember you can also trigger these scripts up from Windows Task Scheduler, so you can run them at specific times of the day if you leave your PC running.

To get the best from the API, you will want to actually do something based on conditions of something else (i.e. if this happens > then set the inverter to do that…. kind of thing.) I’ll sort some more complex examples of this on another post later on.

Downloads

Example scripts for many of the API calls can be found below:

Version 1.1 20-12-2022

10 Responses

  1. Hello,
    is there a formal documentation by GoodWe describing Open API responses?
    Thank you very much in advance

  2. Agree with Bernhard, first time I found something simple, complete and WORKING for Goodwe. Thanks a lot.

Leave a Reply

Your email address will not be published. Required fields are marked *