Connecting Goodwe Solar Panel Inverter to Openhab

Tags: #<Tag:0x00007fc1f9587c40> #<Tag:0x00007fc1f9587b50>

I saw some requests on how to connect the Goodwe Solar Panel Inverter to openhab using the Goodwe’s API. Therefore, I would like to share my solution with you.

Some prerequisites:

  • You should have the SEMSPORTAL up and running with your Inverter
  • I propose you set up a second user in the portal for openhab. (if you log in with the same user twice at the same time, the portal will terminate the session.)
  • Find your PowerStationId in the SEMSPORTAL. You can see it in the URL when you log in and it looks something like this: abcdef10-8ccf-23df-8d12-b123456b123b
  • Install the exec binding and JSON transformation binding in openhab.

First of all, you need to write a small shell script. Make sure you put in you semsportal accountname, password and your PowerStationID:

/etc/openhab2/scripts/semsapi.sh

#!/bin/bash

RESULT=$(curl https://www.semsportal.com/api/v2/Common/CrossLogin --silent --header "Content-Type: application/json" --header "Connect: keep-alive" --header "User-Agent: PVMaster/2.1.0 (iPhone; iOS 13.0; Scale/2.00)" --header "Accept-Language: en;q=1" --header "Token: {\"version\":\"v2.1.0\",\"client\":\"ios\",\"language\":\"en\"}" --data-binary "{\"account\":\"secondopenhabuser@gmail.com\",\"pwd\":\“yourpassword\"}")

HEADER=$(echo "$RESULT"|jq ".data"|tr '\n' ' ')

RETURN=$(curl https://www.semsportal.com/api/v2/PowerStation/GetMonitorDetailByPowerstationId --silent --header "Content-Type: application/json" --header "Accept: */*" --header "User-Agent: PVMaster/2.1.0 (iPhone; iOS 13.0; Scale/2.00)" --header "Accept-Language: DE;q=1" --header 'Token: '"$HEADER" --data-binary "{\"powerStationId\":\"abcdef10-8ccf-23df-8d12-b123456b123b\"}")

echo "$RETURN" | jq ".data"

You can minimize the output by tweaking with the jq command at the end. For now, it returns all available data. Make sure the script is executable and test it. You should see a long JSON-Output with all the values from your inverter.

Next, let’s get this output into openhab. So, let’s configure the exec binding to start the script every minute:

/etc/openhab2/things/exec.things

exec:command:semsportal_json [command="bash /etc/openhab2/scripts/semsapi.sh",interval=60, timeout=10, autorun=false]

/etc/openhab2/items/goodwe.items

String PV_JSON_Out "[%s]" {channel="exec:command:semsportal_json:output"}

Here are some example values I read from my Inverter. Adjust to you needs:

/etc/openhab2/items/goodwe.items

Number:Energy   UG_PV_Total_Output              "Total Output [%.1f kWh]"                   <energy>                                
Number:Energy   UG_PV_Grid                      "Grid [%.1f W]"                             <energy>                                                                                             
Number:Energy   UG_PV_Output_Power              "Output Power [%.1f W]"                     <energy>                                
Number:Energy   UG_PV_Home_Load                 "Home Load [%.1f W]"                        <energy>                                
Number:Energy   UG_PV_Todays_Output             "Today's Output [%.1f kWh]"                 <energy>                                
Number:Energy   UG_PV_Battery                   "Battery Output [%.1f W]"                   <energy>                                
Number          UG_PV_SoC                       "Battery SoC [%d %%]"                       <battery>

And this is the rule that does all the magic in openhab, put this in a rule file, e.g.
/etc/openhab2/rules/goodwe.rules

rule "PV JSON transform"
when 
    Item PV_JSON_Out changed 
then
    val totalOutput = transform("JSONPATH","$.inverter[0].etotal",PV_JSON_Out.state.toString)
    val todaysOutput = transform("JSONPATH","$.inverter[0].eday",PV_JSON_Out.state.toString)
    val grid = transform("JSONPATH","$.powerflow.grid",PV_JSON_Out.state.toString)
    val outputPower = transform("JSONPATH","$.powerflow.pv",PV_JSON_Out.state.toString)
    val homeLoad = transform("JSONPATH","$.powerflow.load",PV_JSON_Out.state.toString)
    val battery = transform("JSONPATH","$.powerflow.bettery",PV_JSON_Out.state.toString)
    val soc = transform("JSONPATH","$.powerflow.soc",PV_JSON_Out.state.toString)

    UG_PV_Total_Output.postUpdate(totalOutput)
    UG_PV_Todays_Output.postUpdate(todaysOutput)
    UG_PV_Grid.postUpdate(grid.toString.replace('(',' ').replace(')',''))
    UG_PV_Output_Power.postUpdate(outputPower.toString.replace('(',' ').replace(')','')) 
    UG_PV_Home_Load.postUpdate(homeLoad.replace('(',' ').replace(')',''))
    UG_PV_Battery.postUpdate(battery.replace('(',' ').replace(')',''))
    UG_PV_SoC.postUpdate(soc)
end

That’s all. Let me know, if you got it working or need some help. Happy to see your ideas on what to do with all the information.

  • RogerG
3 Likes

hey rogerG ,

Some people are very new to openhab , like me :slight_smile: i would love to implement my solar panels again . in the past, before they changed to the sems portal this was very easy . But i dont understand anything with the shell scripting. i need a little more step by step detail how to implement this :confused:

thanks in advance.

Thank you for the description @RogerG007 this is super helpful!

I think I have everything in place but for some reason I get an error that the exec cannot find the script file. I have tried changing the exec.things to match my directory but it still throws an error. Can you help me with how I point out where my script is or do I have it in the wrong place? I’m running a windows machine and have it under C:\openhab\conf\scripts

Hi Johan,

the problem is the windows machine. I’m sorry but the shell script won’t work with windows that easily.

It should be possible to get it running though, but you need either the cURL or cygWin (which includes cURL). Both available for free and I believe there are already some discussions around these tools in the forum.

Nevertheless let me see if I can provide you an alternative script for Windows, it shouldn’t be too difficult. However I can’t really test it in full, as I don’t have openhab running on Windows.

I’ll come back to you asap.

RogerG

Ok, I figured it was related to that.

Would be super nice if you want to help with alternative. I’m of course happy to test!

Hi Roger,

I’m using Linux Mint as an OS and when I try to run the script to test if it works it tells me that it has an

./semsapi.sh: line 6: unexpected EOF while looking for matching `" ’
./semsapi.sh: line 7: syntax error: unexpected end of file

This happens with my username and password and also the exact copy of the lines on this post.

I haven’t been able to find what can possible be wrong about the lines

Below my screenshot of the output

Also, where do you put the rules? beneath the Number:Energy in the same goodwe.items?

I have followd the steps, bur nothing hapens in the paperui.

I think my goodwe.items is not correct.

String PV_JSON_Out "[%s]" {channel="exec:command:semsportal_json:output"}

Number:Energy   UG_PV_Total_Output              "Total Output [%.1f kWh]"                   <energy>                                
Number:Energy   UG_PV_Grid                      "Grid [%.1f W]"                             <energy>                                                                                             
Number:Energy   UG_PV_Output_Power              "Output Power [%.1f W]"                     <energy>                                
Number:Energy   UG_PV_Home_Load                 "Home Load [%.1f W]"                        <energy>                                
Number:Energy   UG_PV_Todays_Output             "Today's Output [%.1f kWh]"                 <energy>                                
Number:Energy   UG_PV_Battery                   "Battery Output [%.1f W]"                   <energy>                                
Number          UG_PV_SoC                       "Battery SoC [%d %%]"                       <battery>

rule "PV JSON transform"
when 
    Item PV_JSON_Out changed 
then
    val totalOutput = transform("JSONPATH","$.inverter[0].etotal",PV_JSON_Out.state.toString)
    val todaysOutput = transform("JSONPATH","$.inverter[0].eday",PV_JSON_Out.state.toString)
    val grid = transform("JSONPATH","$.powerflow.grid",PV_JSON_Out.state.toString)
    val outputPower = transform("JSONPATH","$.powerflow.pv",PV_JSON_Out.state.toString)
    val homeLoad = transform("JSONPATH","$.powerflow.load",PV_JSON_Out.state.toString)
    val battery = transform("JSONPATH","$.powerflow.bettery",PV_JSON_Out.state.toString)
    val soc = transform("JSONPATH","$.powerflow.soc",PV_JSON_Out.state.toString)

    UG_PV_Total_Output.postUpdate(totalOutput)
    UG_PV_Todays_Output.postUpdate(todaysOutput)
    UG_PV_Grid.postUpdate(grid.toString.replace('(',' ').replace(')',''))
    UG_PV_Output_Power.postUpdate(outputPower.toString.replace('(',' ').replace(')','')) 
    UG_PV_Home_Load.postUpdate(homeLoad.replace('(',' ').replace(')',''))
    UG_PV_Battery.postUpdate(battery.replace('(',' ').replace(')',''))
    UG_PV_SoC.postUpdate(soc)
end

Where am I going wrong?

Hi Patrick,

you need to put the rule-bit of code not in the goodwe.items file but into a goodwe.rules file (/etc/openhab2/rules/goodwe.rules).
I’ll update my post above to make that more clear.

Hi Jos,

I’m really sorry I missed your post and questions.

You need to put your rules in a rule file, e.g. /etc/openhab2/rules/goodwe.rules.

And you are right there was a copy & paste problem with my script using the wrong quotation marks. I’ve updated the script above and you should not have that error anymore.

RogerG007

hello, i tryied your guide, but im doing something wrong…
/etc/openhab2/scripts/semsapi.sh a copied your script into file and updated login, password and id.
then i bind excec binding and json.
then i tryied run the script and i have few errors - below.
in the exec bind i have settings:
command: bash /etc/openhab2/scripts/semsapi.sh
transform: REGEX((.*))

where could be mistake?
thanks a lot, a im new in OH, just trying, that is good platform for me…everythings work fine, but i dont understant this not so much…
/etc/openhab2/scripts/semsapi.sh: line 2: $’\r’: command not found /etc/openhab2/scripts/semsapi.sh: line 3: curl: command not found /etc/openhab2/scripts/semsapi.sh: line 4: $’\r’: command not found /etc/openhab2/scripts/semsapi.sh: line 5: jq: command not found /etc/openhab2/scripts/semsapi.sh: line 6: $’\r’: command not found /etc/openhab2/scripts/semsapi.sh: line 7: curl: command not found /etc/openhab2/scripts/semsapi.sh: line 8: $’\r’: command not found /etc/openhab2/scripts/semsapi.sh: line 9: jq: command not found /etc/openhab2/scripts/semsapi.sh: line 2: $’\r’: command not found /etc/openhab2/scripts/semsapi.sh: line 3: curl: command not found /etc/openhab2/scripts/semsapi.sh: line 4: $’\r’: command not found /etc/openhab2/scripts/semsapi.sh: line 5: jq: command not found /etc/openhab2/scripts/semsapi.sh: line 6: $’\r’: command not found /etc/openhab2/scripts/semsapi.sh: line 7: curl: command not found /etc/openhab2/scripts/semsapi.sh: line 8: $’\r’: command not found /etc/openhab2/scripts/semsapi.sh: line 9: jq: command not found