Open tim-ad08 opened 3 years ago
There doesn't appear to be an open API for the Wallbox. Given it talks directly to the inverter maybe its possible to get sensor values from the Solar API but I can't find anything documented. If you find something I suggest you update this request so it can be looked into further.
Thank you, if I find, I will.
Mit freundlichen Grüßen Tim Adam Am 5. Sept. 2021, 05:46 +0200 schrieb Colin Williams @.***>:
There doesn't appear to be an open API for the Wallbox. Given it talks directly to the inverter maybe its possible to get sensor values from the Solar API but I can't find anything documented. If you find something I suggest you update this request so it can be looked into further. — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android.
From what I have managed to find so far there is no API for the Wattpilot. It talks directly to the inverter via WiFi to obtain information from the smartmeter/inverter. So I would not be surprised if the only way to control and read info from the Wattpilot is by using their App for the Wattpilot.
In one Fronius document they also write that it requires a Symo Hybrid or Gen24 inverter, not a regular Symo, to be able to regulate based on surplus PV power. I do hope that is not true because I am really interested in this charger and I have a Symo.
This is from the Prerequsites in the "Data communication with the inverter" section from their manual: https://manuals.fronius.com/html/4204260400/en.html#0_m_0000024045
The inverter is supported (Fronius GEN24, Fronius Symo Hybrid, Fronius SnapINverter, except Light versions).
I'd like to share my findings about how the Solar.Wattpilot App communicates with Fronius Wattpilot.
It provides a websocket connection at port 80 on the IP address that is connected to the WIFI.
Using this websocket debug tool and the URL ws://<local_ip>/ws
I was able to successfully connect and receive these JSON messages - a hello message and an authorization required message.
Here is the log output:
$ _INFO_:Connect success, url = ws://<local_ip>/ws
$ _INFO_:Received message: {"type":"hello","serial":"<serialnr>","friendly_name":"Wattpilot_<serialnr>","manufacturer":"fronius","devicetype":"wattpilot","version":"34.5","protocol":2,"secured":true}
$ _INFO_:Received message: {"type":"authRequired","token1":"siHWIFSGNfQQuqHXR9J3nrJOdbaHAZui","token2":"1dsfbEciJtkyCPCd01rbAC8RuKel7b3n"}
<serialnr>
is a 8-digit number.
token1
and token2
are changed on every connection
The next step would be to find out how to do the authentication but that seems to be a bit more challenging ;-). In the Android App the authentication is done using the serial number and a password. Using trial and error the authentication message seems to have this format:
$ _INFO_:send message, content = {"type":"auth","serial":"<serialnr>","token3":"asdf","hash":"asdf"}
$ _INFO_:Received message: {"type":"authError","message":"Wrong password"}
Unfortunately I have no idea how to calculate token3
and hash
, but maybe someone else finds a way to successfully authenticate ...
The normal Symo works. I have a Wattpilot installed working with a Symo 10
@ahochsteger
The auth request for connected devices looks like this:
{
"type": "auth",
"token3": "ac7d78c4852b1c...",
"hash": "a18652ee70ddf.."
}
Currently, I also have no idea how to compute the token. I assume it needs to be created with some key that got exchanged during the setup process and the tokens provided from the previous response. Currently, I also have no idea how to compile the message hash.
The auth response looks like:
{
"type": "authSuccess",
"token3": "ac7d78c4852b1c...",
"hash": "a18652ee70ddf..."
}
The device then sends a message of type fullStatus.
{
"type": "fullStatus",
"partial": true,
"status": {
"mod": 1,
"rfb": 1663,
"stao": null,
"alw": false,
"acu": null,
"acui": null,
"adi": true,
"dwo": null,
"tpa": 0,
"sse": "32453543",
"eto": 39809,
"etop": 39809,
"wifis": [
...
],
... some other fields
}
}
The device then sends messages with type deltaStatus
{
"type": "deltaStatus",
"status": {
"rfb": 1663,
"ehs": 280924,
"efh": 146636,
"efh32": 146636,
"efh8": 107956,
"utc": "2021-12-22T22:39:01.118",
"loc": "2021-12-22T23:39:01.118 +01:00",
"rbt": 33320614,
"tma": [
8.75,
14
],
"fhz": 49.988,
"tpcm": [
5,
0,
3,
1,
1,
0,
1,
1,
34,
2,
2,
1,
0,
41,
0,
1,
0,
0,
1,
0,
0
]
}
}
If you change e. g. amps by sending
{
"type": "securedMsg",
"data": "{\"type\":\"setValue\",\"requestId\":\"1\",\"key\":\"amp\",\"value\":14}",
"requestId": "1sm",
"hmac": "07cb34eb9c49fa9c2f64a1b2cfd..."
}
It will respond like this
{"type":"response","requestId":"1","success":true,"status":{"amp":14}}
Exploring the API is quite easy if you can tcpdump the local traffic e. g. of the app from your access point. But without understanding how the token for the auth request is compiled, it makes no sense to dig deeper into the other messages. Decompiling e. g. the Android app APK could provide additional insights. But that's not my area of expertise.
I think you have an error in the auth request:
Hallo (Wallbox->Client):
{
"type":"hello",
"message":"Hello app",
"serial":"12345678",
"devicetype":"wattpilot",
"manufacturer":"fronius",
"protocol":2
}
Auth Request (Wallbox->Client):
{
"type":"authRequired",
"token1":"1234567890ABCDEFGHIJKabcdefghijk",
"token2":"abcdefghijk1234567890ABCDEFGHIJK"
}
Authentification (Client->Wallbox):
{
"type":"auth",
"token3":"4f...",
"hash":"2b..."
}
Auth Success (Wallbox->Client):
{
"type":"authSuccess",
"message":"Successfully authenticated"
}
token1, token2, token3 are 32character Strings consisting of [a-Z0-9]. Hash is 64 characters [a-Z0-9].
sqlite database of Android App contains the following data:
[{
"type":2,
"serial":"12345678",
"password":"5H...",
"name":"Wattpilot_12345678"
}]
Password again is 32 char [a-Z0-9].
I also could not reconstruct how token3 is generated.
Endpoint is either
Update send to cloud:
{
"type":"setValue",
"requestId":"15",
"key":"bac",
"value":false
}
Update send to local IP:
{
"type":"securedMsg",
"data": {\"type\":\"setValue\",\"requestId\":\"1\",\"key\":\"trx\",\"value\":0}",
"requestId":"1sm",
"hmac":"a5..." (64 characters [a-Z0-9])
}
I have no clue how token3 or hmac is calculated tho....
I took a look at the Android APK to find out how the token3 and the hmac hash are generated. As far as I understand it, only the appearance is defined in the Java code. The app itself is a react native app bundled to assets/index.android.bundle.
I embedded the code in an html file and then threw it into the Chrome debugger.
Can it be better analyzed if the app is run in the Android emulator?
Update: The app runs Hermes JavaScript engine. The code in the bundle is Hermes bytecode. It is possible to disassemble with hbctool but that's still not easy to debug.
@hudeldudel I admire you attempt to reverse engineer this...and I hope that you succeed :)
It's sad that Fronius has opted to make the Wattpilot a separate entity with no official API. They took a good product (go-echarger) and turned it into an inferior product...apart from the smartmeter integration. I did ask Fronius about their weird statement regarding inverter support in the documentation and just like @sirathan mentioned above, the regular SYMO works.
Personally I have ditched the Wattpilot, that I almost bought, and I will go for the go-echarger instead. The only thing I will not get out-of-the-box compared to the Wattpilot is the smartmeter integration to aid in maximizing charging without blowing fuses. But since it has an API and I am already running HA fixing that is a no brainer.
@nilrog I have stopped trying to reverse engineer. It's gotten to a point where I don't think it's worth it anymore for me.
My two main use cases are not working unless there is some usable API:
Case 1. should work for people that already own the required smart meter. There will probably be one available for me soon. Alternatively, I could now rather fake the API of the inverter including mDNS discovery etc. in order to trick and control the wallbox. Or I could fake the missing smart meter by translating my SML measurements to Modbus RTC Sunspec and pass it to the GEN24. But I don't like the last solution because I don't know what can happen with it.
Case 2. may be achieved by setting appropriate values with the workarounds for case 1.
I can't motivate myself to do this at the moment because I'm dissatisfied for now. Not offering an API is just so weak for such kind of product.
Knowing what I know now, I wouldn't have bought the Fronius Wattpilot either.
But Fronius might surprise us and deliver some API with a firmware update. Fingers crossed...
From the disassembled code (and a lot of guessing), I figured out that the hash is computed as follow (where the + is a string concatenation): hash = CryptoJS.SHA256(token3 + token2 + CryptoJS.SHA256(token1 + password)) and was able to confirm it with the values from an actual authentication exchange. Regarding the token3, I would assume it's just some random value to add some salt in the hashing.
@ebiiii Thank you very much. I can also confirm this as correct, just confirmed this with some older dump of the auth exchange and also connected fine with random- 32Byte Hex Value for token3.
Password is not the Device-Password but the value stored in the App-sqlite DB. Not sure yet how this is obtained.
another update: With @ebiiii hint i was able to send updates to the Wallbox and set property "cae" to True. (Enable Cloud API) "cak" property contains a api-key afterwards which is usable as descripted in official documentation: https://github.com/goecharger/go-eCharger-API-v2/blob/main/cloudapi-de.md
-> Wattpilot already contains a working e-go CloudAPI but the command to enable it is disabled in the App as of now.
Updates send to the wattpilot are secured with hmac-sha256
message:
{
"type":"setValue",
"requestId":"1",
"key":"cae",
"value":True
}
securedMsg:
{
"type":"securedMsg",
"requestId": "1sm" -> RequestID of contained message + "sm" (e.g. "1sm")
"data": -> message,
"hmac": ->HMAC-SHA256 with key=password and data=message with original encoding
}
Edit becasue somehow I wrote in German ...
I have activated the cloud api with this method but it seems Wattpilot is not connecting to it. I get the API key from the fullStatus dump. I see on my internal DNS server that wattpilot only ever contacts iot.wattpilot.io and the go-e API returns statuscode 403 (either wrong token or charger is not connected to API).
The serial I have has 8 digits, the go-e API docu talks about 6 digit serials. Is that maybe an issue?
At least I have my own nodejs based code now to read and write values. Thanks for all the reverse engineering!
Because I did not see it mentioned: The hashed password is just a 'simple' sha512 password derivative. It uses the password as password and the serial number of the wattpilot as salt. The result is shorted to the first 32 characters. I create it like this:
pbkdf2Sync(this._password, msg.serial, 100000, 256, 'sha512').toString('base64').substring(0, 32);
EDIT Ah, also found your github repo, which does the same in python :D
Because I did not see it mentioned: The hashed password is just a 'simple' sha512 password derivative. It uses the password as password and the serial number of the wattpilot as salt. The result is shorted to the first 32 characters. I create it like this:
pbkdf2Sync(this._password, msg.serial, 100000, 256, 'sha512').toString('base64').substring(0, 32);
EDIT Ah, also found your github repo, which does the same in python :D
My repo? I have added some code here which peforms the auth (also in the way you mentioned (100.000 rounds of sha512 hmac).
https://github.com/joscha82/wattpilot
I enabled and tested the eGo API a while ago and found it working, i cannot remember which URL i used, i believe i used the ego URL just with the longer serial. However, i am not a friend of utilizing the eGo Cloud API as this may be unlicensed (and consumes ressources from eGo) as long as the service is not officially enabled by fronius. My example code however should be able to perform all actions: Read all Properties and set all properties and should work local and over the internet (by utilizing the wattpilot websocket endpoint in the cloud insteat of the Local Websocket). Cloud Websocket behaviours almost identical to the local websocket endpoint, only change is that the hallo message contains other properties and that send messages are not required to be signed (as the connection itself is ssl encrypted).
Yeah, that is the repo I meant :)
My nodejs solution (not yet pushed it anywhere) basically does something very similar to your solution. I only need something to toggle the loading mode (eco, next trip, charge) and I need to change which car is connected anyway :)
My nodejs solution (not yet pushed it anywhere) basically does something very similar to your solution. I only need something to toggle the loading mode (eco, next trip, charge) and I need to change which car is connected anyway :)
Yes same intention here: active eco mode when SoC > 40%, enable Trip Mode when < 40%, disable both modes when Soc < 20%.
Disable Charging if distance car <> home > 200m and enable otherwise
@joscha82 here's a PR to your great work to extend it with an interactive shell that allows inspecting of all available Wattpilot properties and changing them as well: https://github.com/joscha82/wattpilot/pull/1
@joscha82 Great effort in making this! I'm trying to enable cae on my Wallbox but only get an error:
It's probably user error on my part, but do you know what might be wrong?
@okoohler, have you tried using set cae true
(lower-case) instead?
There's a difference between Python and JSON (True
vs. true
) that may not be so obvious.
@ahochsteger thanks for your reply. Yes, I've tried lower case and even 1 (as in 0 or 1 for false/true).
@okoohler thanks for reporting it was indeed a bug in setting boolean values. It's already fixed here: https://github.com/joscha82/wattpilot/pull/5
Thank you for the update, works great!
Den sön 3 apr. 2022 kl 15:15 skrev Andreas Hochsteger < @.***>:
@okoohler https://github.com/okoohler thanks for reporting it was indeed a bug in setting boolean values. It's already fixed here: joscha82/wattpilot#5 https://github.com/joscha82/wattpilot/pull/5
— Reply to this email directly, view it on GitHub https://github.com/safepay/sensor.fronius/issues/48#issuecomment-1086866747, or unsubscribe https://github.com/notifications/unsubscribe-auth/AYL5ZQUZ6KHHBXLEG4MJIG3VDGKXPANCNFSM445Z5SXQ . You are receiving this because you were mentioned.Message ID: @.***>
@joscha82, @okoohler and this PR adds simple MQTT support - so initial integration with Home Assistant using it's MQTT support might already be possible with a bit of tweaking: https://github.com/joscha82/wattpilot/pull/6
Still the best would be to add it to the fronius integration ... Any chance for it, @safepay?
hi, ist there any plan for an integration witch shows the current state of the Fronius Wallbox in Home-assistant. The Wallbox is connected with the Smart meter via WiFi.
https://www.fronius.com/de-de/germany/solarenergie/eigenheim/produkte-und-loesungen/e-mobilitaet/wattpilot-e-auto-ladebox-fuer-zuhause