Anybody any ideas on a new URL? Obviously the URL's in the below message don't seem to work.
- Spoiler: show
Moderator: leecollings
Code: Select all
#!/usr/bin/env python3
import http.client, urllib.request, json, hashlib
from datetime import datetime
#Trannergy account details
apiSite = "api.solarmanpv.com"
appID = "" #Change to your own appID, to be provided from Trannergy/Solarman
appSecret = "" #Change to your own appSecret, to be provided from Trannergy/Solarman
email = "" #Change to your own account name/mail address
password = b"" #Change password to your own, maintain the b in front of the password as password need to be binary
conn = http.client.HTTPSConnection(apiSite)
password = hashlib.sha256(password).hexdigest()
#domoticz settings
domoticz_host = "" #ip adress of the domoticz host
domoticz_port = "8080"
domoticz_url = "json.htm"
domoticz_ActualPower = "" #idx of new device
#Request access token, manaul chapter/routine 2.1
payload = json.dumps({
"appSecret": appSecret,
"email": email,
"password": password
})
headers = {
'Content-Type': 'application/json'
}
conn.request("POST", "/account/v1.0/token?appId="+appID+"&language=en", payload, headers)
res = conn.getresponse()
data = json.loads(res.read())
accesstoken = data['access_token']
print("Accesstoken :" +accesstoken)
#Request current power + lastupdate time + stationID, manual chapter/routine 4.4
payload = json.dumps({
"page": 1,
"size": 20
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'bearer '+accesstoken
}
conn.request("POST", "/station/v1.0/list?language=en", payload, headers)
res = conn.getresponse()
data = json.loads(res.read())
stationID = str(data['stationList'][0]['id'])
currentpower = str(data['stationList'][0]['generationPower'])
lastupdatetime = int(data['stationList'][0]['lastUpdateTime'])
lastupdatetime = str(datetime.fromtimestamp(lastupdatetime))
print("Current Power :"+currentpower+"W")
print("Last update time :"+lastupdatetime)
print("StationID :"+stationID)
#Request deviceID + deviceSN, manual chapter/routine 4.2
payload = json.dumps({
"deviceType": "INVERTER",
"page": 1,
"size": 10,
"stationId": stationID
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'bearer '+accesstoken
}
conn.request("POST", "/station/v1.0/device?language=en", payload, headers)
res = conn.getresponse()
data = json.loads(res.read())
deviceID = str(data['deviceListItems'][0]['deviceId'])
deviceSN = str(data['deviceListItems'][0]['deviceSn'])
print('Device serial : '+deviceSN)
print('Device ID : '+deviceID)
#Total generated power, manual chapter/routine 3.3
payload = json.dumps({
"deviceSn": deviceSN,
"deviceId": deviceID
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'bearer '+accesstoken
}
conn.request("POST", "/device/v1.0/currentData?language=en", payload, headers)
res = conn.getresponse()
data = json.loads(res.read())
multiply='1000.0'
totalgenpower = float(data['dataList'][16]['value']) * float(multiply)
totalgenpower = str(totalgenpower)
print("Total generated power: " +totalgenpower+"W")
#uploading values to domoticz
url = ("http://" + domoticz_host + ":" + domoticz_port + "/" + domoticz_url+ "?type=command¶m=udevice&idx=" + domoticz_ActualPower+ "&nvalue=0&svalue=" + currentpower+ ";" + totalgenpower)
#urllib.request.urlopen(url)
print(url)
I've requested the new api detail and changed the code. When i test the code i get the neaded data. Only problem i have is that the new api gives me rounded numbers for the generated energy. In my dealy report i see 1kWh bars every hour. is this normal behavior? I've looked through the code but other than the multiply by 1000 (that is needed to get the watts) i can't find any errors.
I use and checked de solarman portal. I've got nice none rounded values in de portal.
Code: Select all
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- saved from url=(0031)http://Inverter-IP/status.html -->
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
.in_body
{
margin-top:0px;
margin-left:0px;
margin-right:0px;
margin-bottom:0px;
background-color:transparent;
}
.div_c
{
margin-left:50px;
margin-right:50px;
margin-top:50px;
margin-bottom:50px;
}
.cu
{
cursor:pointer;
}
.b
{
font-weight:bold;
}
.lab_5
{
font-size:16px;
color:#666666;
margin-left:-20px;
}
.lab_l2
{
float:left;
width:32%;
color:#666666;
margin-bottom:-2px;
font-size:14px;
}
.lab_r2
{
float:left;
width:68%;
color:#666666;
text-align:right;
font-size:14px;
}
.cl
{
clear:left;
}
.line
{
height:1px;
background-color:#666666;
width:100%;
margin-top:5px;
margin-bottom:5px;
}
.sp_5
{
height:5px;
width:500px;
}
.sp_20
{
height:20px;
width:500px;
}
.label
{
float:left;
width:50%;
color:#666666;
margin-bottom:-2px;
font-size:14px;
}
.lab_r
{
float:left;
width:50%;
color:#666666;
text-align:right;
font-size:14px;
}
.lab_l
{
float:left;
width:40%;
color:#666666;
margin-bottom:-2px;
margin-left:10%;
font-size:14px;
}
.line_l
{
height:1px;
background-color:#666666;
width:450px;
margin-top:5px;
margin-bottom:5px;
margin-left:50px;
}
.sub
{
display:inline-block;
width:16px;
text-align:center;
}
</style>
<script type="text/javascript">
var height=0;function fileText(id,value){if(document.getElementById(id)){document.getElementById(id).innerHTML=value}}function changeFont(){reCon("main_div").style.fontFamily=window.parent.reFont()}function child_getH(){var nh=document.body.offsetHeight+100;if(nh<500||nh==null){nh=500}if(height!=nh){height=nh;window.parent.child_height(height)}}function reCon(id){return document.getElementById(id)}function ready(){try{window.parent.show_ifr()}catch(e){}child_getH()}function show(v){var c=document.getElementById(v);if(c!=null){c.style.display=""}}function hide(v){var c=document.getElementById(v);if(c!=null){c.style.display="none"}};
</script>
<script type="text/javascript">
var webdata_sn = "100204********* ";
var webdata_msvn = "004B";
var webdata_ssvn = "0030";
var webdata_pv_type = "0204";
var webdata_rate_p = "";
var webdata_now_p = "20";
var webdata_today_e = "13.10";
var webdata_total_e = "372.0";
var webdata_alarm = "";
var webdata_utime = "0";
var cover_mid = "404058****";
var cover_ver = "MW_08_512_0501_1.82";
var cover_wmode = "STA";
var cover_ap_ssid = "AP_404******";
var cover_ap_ip = "10.10.100.254";
var cover_ap_mac = "34EAE734****";
var cover_sta_ssid = "*********";
var cover_sta_rssi = "74%";
var cover_sta_ip = "192.168.****";
var cover_sta_mac = "34EAE734****";
var status_a = "1";
var status_b = "0";
var status_c = "0";
function initPageText(){var list=window.parent.reList("status");fileText("st1",list["t1"]);fileText("st2",list["t2"]);fileText("st3",list["t3"]);for(var i=1;i<=27;i++){if(i!=14){fileText("tx"+i,list[i])}}changeFont();child_getH()}function upfold(v){if(document.getElementById("up_"+v+"_div").style.display=="none"){show("up_"+v+"_div");reCon("p_"+v).innerHTML="-"}else{hide("up_"+v+"_div");reCon("p_"+v).innerHTML="+"}}function init_main_page(){var on=window.parent.reTip("1");var off=window.parent.reTip("2");document.getElementById("cover_mid").innerHTML=cover_mid;document.getElementById("cover_ver").innerHTML=cover_ver;document.getElementById("cover_ap_status").innerHTML=off;document.getElementById("cover_sta_status").innerHTML=off;if(cover_wmode!="STA"){document.getElementById("cover_ap_status").innerHTML=on;document.getElementById("cover_ap_ssid").innerHTML=cover_ap_ssid;document.getElementById("cover_ap_ip").innerHTML=cover_ap_ip;document.getElementById("cover_ap_mac").innerHTML=cover_ap_mac}if(cover_wmode!="AP"){document.getElementById("cover_sta_status").innerHTML=on;document.getElementById("cover_sta_ssid").innerHTML=cover_sta_ssid;document.getElementById("cover_sta_rssi").innerHTML=cover_sta_rssi;document.getElementById("cover_sta_ip").innerHTML=cover_sta_ip;document.getElementById("cover_sta_mac").innerHTML=cover_sta_mac}if(webdata_sn==""){webdata_sn="---"}fileText("webdata_sn",webdata_sn);if(webdata_msvn==""){webdata_msvn="---"}fileText("webdata_msvn",webdata_msvn);if(webdata_ssvn==""){webdata_ssvn="---"}fileText("webdata_ssvn",webdata_ssvn);if(webdata_pv_type==""){webdata_pv_type="---"}fileText("webdata_pv_type",webdata_pv_type);if(webdata_rate_p==""){webdata_rate_p="---"}fileText("webdata_rate_p",webdata_rate_p+" W");if(webdata_now_p==""||webdata_now_p==0){webdata_now_p="---"}fileText("webdata_now_p",webdata_now_p+" W");if(webdata_today_e==""){webdata_today_e="---"}fileText("webdata_today_e",webdata_today_e+" kWh");if(webdata_total_e==""){webdata_total_e="---"}fileText("webdata_total_e",webdata_total_e+" kWh");if(webdata_alarm==""){webdata_alarm="---"}fileText("webdata_alarm",webdata_alarm);if(webdata_utime==""){if(document.getElementById("webdata_sn").innerHTML=="---"){webdata_utime="---"}else{webdata_utime=value+window.parent.reTip("5")}}fileText("webdata_utime",webdata_utime);var st_en=window.parent.reTip("3");var st_dis=window.parent.reTip("4");var st_un=window.parent.reTip("41");if(status_a=="1"){document.getElementById("cover_remote_status_a").innerHTML=st_en}else{if(status_a=="0"){document.getElementById("cover_remote_status_a").innerHTML=st_dis}else{document.getElementById("cover_remote_status_a").innerHTML=st_un}}if(status_b=="1"){document.getElementById("cover_remote_status_b").innerHTML=st_en}else{if(status_b=="0"){document.getElementById("cover_remote_status_b").innerHTML=st_dis}else{document.getElementById("cover_remote_status_b").innerHTML=st_un}}};
</script>
</head>
<body class="in_body" onload="init_main_page();">
<div class="div_c" id="main_div" style="font-family: Arial;">
<div class="lab_5 cu b" onclick="upfold(1);child_getH();"><span class="sub" id="p_1">-</span><span id="st1" style="margin-left:3px">Inverter information</span></div>
<div class="sp_5"></div>
<div id="up_1_div">
<div class="lab_l2" id="tx1">Inverter serial number</div>
<div class="lab_r2" id="webdata_sn">100204********* </div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" id="tx2">Firmware version (main)</div>
<div class="lab_r2" id="webdata_msvn">004B</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" id="tx3">Firmware version (slave)</div>
<div class="lab_r2" id="webdata_ssvn">0030</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" id="tx4">Inverter model</div>
<div class="lab_r2" id="webdata_pv_type">0204</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" id="tx5">Rated power</div>
<div class="lab_r2" id="webdata_rate_p">--- W</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" style="color:#666666;font-weight:bold;" id="tx6">Current power</div>
<div class="lab_r2" id="webdata_now_p" style="color:#666666;font-weight:bold;">20 W</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" style="color:#666666;font-weight:bold;" id="tx7">Yield today</div>
<div class="lab_r2" id="webdata_today_e" style="color:#666666;font-weight:bold;">13.10 kWh</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" style="color:#666666;font-weight:bold;" id="tx8">Total yield</div>
<div class="lab_r2" id="webdata_total_e" style="color:#666666;font-weight:bold;">372.0 kWh</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" style="color:#666666;font-weight:bold;" id="tx9">Alerts</div>
<div class="lab_r2" id="webdata_alarm" style="color:#666666;font-weight:bold;">---</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l2" style="color:#666666;font-weight:bold;" id="tx10">Last updated</div>
<div class="lab_r2" id="webdata_utime" style="color:#666666;font-weight:bold;">0</div>
<div class="cl"></div>
<div class="line"></div>
</div>
<div class="sp_20"></div>
<div class="lab_5 cu b" onclick="upfold(2);child_getH();"><span class="sub" id="p_2">+</span><span id="st2" style="margin-left:3px">Device information</span></div>
<div class="sp_5"></div>
<div id="up_2_div" style="display:none">
<div class="label" id="tx11">Device serial number</div>
<div class="lab_r" id="cover_mid">4*********</div>
<div class="cl"></div>
<div class="line"></div>
<div class="label" id="tx12">Firmware version</div>
<div class="lab_r" id="cover_ver">MW_08_512_0501_1.82</div>
<div class="cl"></div>
<div class="line"></div>
<div class="label" id="tx13">Wireless AP mode</div>
<div class="lab_r" id="cover_ap_status" style="color:#666666;font-weight:bold;">Disable</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l" id="ap_ssid">SSID</div>
<div class="lab_r" id="cover_ap_ssid"></div>
<div class="cl"></div>
<div class="line_l"></div>
<div class="lab_l" id="tx15">IP address</div>
<div class="lab_r" id="cover_ap_ip"></div>
<div class="cl"></div>
<div class="line_l"></div>
<div class="lab_l" id="tx16">MAC address</div>
<div class="lab_r" id="cover_ap_mac"></div>
<div class="cl"></div>
<div class="line_l"></div>
<div class="label" id="tx17">Wireless STA mode</div>
<div class="lab_r" id="cover_sta_status" style="color:#666666;font-weight:bold;">Enable</div>
<div class="cl"></div>
<div class="line"></div>
<div class="lab_l" id="tx18">Router SSID</div>
<div class="lab_r" id="cover_sta_ssid">********</div>
<div class="cl"></div>
<div class="line_l"></div>
<div class="lab_l" id="tx19">Signal Quality</div>
<div class="lab_r" id="cover_sta_rssi">74%</div>
<div class="cl"></div>
<div class="line_l"></div>
<div class="lab_l" id="tx20">IP address</div>
<div class="lab_r" id="cover_sta_ip">192.*.*.*</div>
<div class="cl"></div>
<div class="line_l"></div>
<div class="lab_l" id="tx21">MAC address</div>
<div class="lab_r" id="cover_sta_mac">34EAE*******</div>
<div class="cl"></div>
<div class="line_l"></div>
</div>
<div class="sp_20"></div>
<div class="lab_5 cu b" onclick="upfold(3);child_getH();"><span class="sub" id="p_3">+</span><span id="st3" style="margin-left:3px">Remote server information</span></div>
<div class="sp_5"></div>
<div id="up_3_div" style="display:none">
<div class="label" id="tx25">Remote server A</div>
<div class="lab_r" id="cover_remote_status_a">Connected</div>
<div class="cl"></div>
<div class="line"></div>
<div class="label" id="tx26">Remote server B</div>
<div class="lab_r" id="cover_remote_status_b">Not connected</div>
<div class="cl"></div>
<div class="line"></div>
</div>
</div>
<script type="text/javascript">
initPageText();
ready();
</script>
</body></html>
Code: Select all
...\scripts>python test.py
Traceback (most recent call last):
File "test.py", line 41, in <module>
resultJson = resultData.json()
File "C:\Python27\lib\site-packages\requests\models.py", line 898, in json
return complexjson.loads(self.text, **kwargs)
File "C:\Python27\lib\json\__init__.py", line 339, in loads
return _default_decoder.decode(s)
File "C:\Python27\lib\json\decoder.py", line 364, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Python27\lib\json\decoder.py", line 382, in raw_decode
raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded
Code: Select all
resultJson = resultData.json()
Grover01 wrote: ↑Thursday 14 October 2021 17:31 In followup of the Trannergy platform migration, as previously noticed by different users, I contacted the customer service as mentioned in the notification mail you should have received. Customer service indeed is confirming the implementation of a different API. While using the script as shared at the start of this post, it indeed will result in errors, and you would not get this fixed using the method initially used.
With a minimum amount of words, the customer services created an appID and appSercret which should make it possible to talk to the new API. Additionally they also shared a manual with limited but useful information on how to talk to the API.
With my 20 years rusty knowledge of programming, I started as a complete new-be in Python to see if I could get this working.....and got it fixed.
Steps to get this implemented:
1) Contact customer support ([email protected]) and ask them to create an AppID and AppSecret connected to your loginname for your current account. And yes, this customer service is also for Trannergy.
2) Easiest way forward is to make a backup copy of your current, in this case, trannergy.py file
3) Copy & paste below code in the existing .py file
4) Adjust the #Trannergy account detail section to your need
5) Adjust the #Domoticz settings. You can copy them from your previous configuration
6) Test the script first
7) When successful, remove the # in front of the before last line
Happy coding
Note: Code is using Python 3, and you need the libs as mentioned at the top of the script.Code: Select all
#!/usr/bin/env python3 import http.client, urllib.request, json, hashlib from datetime import datetime #Trannergy account details apiSite = "api.solarmanpv.com" appID = "" #Change to your own appID, to be provided from Trannergy/Solarman appSecret = "" #Change to your own appSecret, to be provided from Trannergy/Solarman email = "" #Change to your own account name/mail address password = b"" #Change password to your own, maintain the b in front of the password as password need to be binary conn = http.client.HTTPSConnection(apiSite) password = hashlib.sha256(password).hexdigest() #domoticz settings domoticz_host = "" #ip adress of the domoticz host domoticz_port = "8080" domoticz_url = "json.htm" domoticz_ActualPower = "" #idx of new device #Request access token, manaul chapter/routine 2.1 payload = json.dumps({ "appSecret": appSecret, "email": email, "password": password }) headers = { 'Content-Type': 'application/json' } conn.request("POST", "/account/v1.0/token?appId="+appID+"&language=en", payload, headers) res = conn.getresponse() data = json.loads(res.read()) accesstoken = data['access_token'] print("Accesstoken :" +accesstoken) #Request current power + lastupdate time + stationID, manual chapter/routine 4.4 payload = json.dumps({ "page": 1, "size": 20 }) headers = { 'Content-Type': 'application/json', 'Authorization': 'bearer '+accesstoken } conn.request("POST", "/station/v1.0/list?language=en", payload, headers) res = conn.getresponse() data = json.loads(res.read()) stationID = str(data['stationList'][0]['id']) currentpower = str(data['stationList'][0]['generationPower']) lastupdatetime = int(data['stationList'][0]['lastUpdateTime']) lastupdatetime = str(datetime.fromtimestamp(lastupdatetime)) print("Current Power :"+currentpower+"W") print("Last update time :"+lastupdatetime) print("StationID :"+stationID) #Request deviceID + deviceSN, manual chapter/routine 4.2 payload = json.dumps({ "deviceType": "INVERTER", "page": 1, "size": 10, "stationId": stationID }) headers = { 'Content-Type': 'application/json', 'Authorization': 'bearer '+accesstoken } conn.request("POST", "/station/v1.0/device?language=en", payload, headers) res = conn.getresponse() data = json.loads(res.read()) deviceID = str(data['deviceListItems'][0]['deviceId']) deviceSN = str(data['deviceListItems'][0]['deviceSn']) print('Device serial : '+deviceSN) print('Device ID : '+deviceID) #Total generated power, manual chapter/routine 3.3 payload = json.dumps({ "deviceSn": deviceSN, "deviceId": deviceID }) headers = { 'Content-Type': 'application/json', 'Authorization': 'bearer '+accesstoken } conn.request("POST", "/device/v1.0/currentData?language=en", payload, headers) res = conn.getresponse() data = json.loads(res.read()) multiply='1000.0' totalgenpower = float(data['dataList'][16]['value']) * float(multiply) totalgenpower = str(totalgenpower) print("Total generated power: " +totalgenpower+"W") #uploading values to domoticz url = ("http://" + domoticz_host + ":" + domoticz_port + "/" + domoticz_url+ "?type=command¶m=udevice&idx=" + domoticz_ActualPower+ "&nvalue=0&svalue=" + currentpower+ ";" + totalgenpower) #urllib.request.urlopen(url) print(url)
Calling my Ginlong-inverter/LAN-stick with that url-string yields a reaction, but different than expected.http://<inverter-ip>/js/status.js
Code: Select all
2022-11-07 21:20:24.962 Error: PP Omnik: Call to function 'onMessage' failed, exception details:
2022-11-07 21:20:24.967 Error: PP Omnik: Traceback (most recent call last):
2022-11-07 21:20:24.967 Error: PP Omnik: File "/home/bolt/domoticz/plugins/Domoticz-Omnik-Local-Web-Plugin/plugin.py", line 221, in onMessage
2022-11-07 21:20:24.967 Error: PP Omnik: _plugin.onMessage(Connection, Data)
2022-11-07 21:20:24.967 Error: PP Omnik: File "/home/bolt/domoticz/plugins/Domoticz-Omnik-Local-Web-Plugin/plugin.py", line 133, in onMessage
2022-11-07 21:20:24.967 Error: PP Omnik: strData = Data["Data"].decode("utf-8", "ignore")
2022-11-07 21:20:24.967 Error: PP Omnik: KeyError: 'Data'
Users browsing this forum: No registered users and 1 guest