Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: Fronius Wallbox als Sensor #48

Open
tim-ad08 opened this issue May 15, 2021 · 25 comments
Open

Request: Fronius Wallbox als Sensor #48

tim-ad08 opened this issue May 15, 2021 · 25 comments

Comments

@tim-ad08
Copy link

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

@colwilliamsnz
Copy link
Collaborator

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.

@tim-ad08
Copy link
Author

tim-ad08 commented Sep 5, 2021 via email

@nilrog
Copy link
Contributor

nilrog commented Sep 8, 2021

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).

@ahochsteger
Copy link

ahochsteger commented Oct 1, 2021

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 ...

@sirathan
Copy link

The normal Symo works. I have a Wattpilot installed working with a Symo 10

@hudeldudel
Copy link

@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.

@joscha82
Copy link

joscha82 commented Dec 23, 2021

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 <IP_of_Wattpilot>/ws or https://app.wattpilot.io/app/<serialnumber_of_wattpilot>?version=x.y.z. Updates send to local IP (unencrypted http) contain a hmac to secure the message itself. Updates send over https via cloud are not secured:

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....

@hudeldudel
Copy link

hudeldudel commented Jan 3, 2022

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.

  1. The code is probably obfuscated.
  2. The JavaScript code cannot be executed in Chrome on Mac: Uncaught SyntaxError: Invalid or unexpected token

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.

@nilrog
Copy link
Contributor

nilrog commented Jan 25, 2022

@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.

@hudeldudel
Copy link

hudeldudel commented Jan 25, 2022

@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:

  1. Since the Fronius Smart Meter for my GEN 24 is currently not available, I wanted to control the charging power based on my existing SML measurements.
  2. I also wanted to stop charging at a SOC of 80%. The SOC is obtained via the vehicle's 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...

@ebiiii
Copy link

ebiiii commented Feb 5, 2022

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.

@joscha82
Copy link

joscha82 commented Feb 6, 2022

@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.

@joscha82
Copy link

joscha82 commented Feb 6, 2022

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
}

@mze9412
Copy link

mze9412 commented Feb 24, 2022

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!

@mze9412
Copy link

mze9412 commented Feb 24, 2022

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

@joscha82
Copy link

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).

@mze9412
Copy link

mze9412 commented Feb 24, 2022

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 :)

@joscha82
Copy link

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

@ahochsteger
Copy link

@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:
joscha82/wattpilot#1

@okoohler
Copy link

@joscha82 Great effort in making this! I'm trying to enable cae on my Wallbox but only get an error:
Skärmavbild 2022-03-23 kl  12 37 36
It's probably user error on my part, but do you know what might be wrong?

@ahochsteger
Copy link

@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.

@okoohler
Copy link

@ahochsteger thanks for your reply. Yes, I've tried lower case and even 1 (as in 0 or 1 for false/true).

@ahochsteger
Copy link

@okoohler thanks for reporting it was indeed a bug in setting boolean values.
It's already fixed here:
joscha82/wattpilot#5

@okoohler
Copy link

okoohler commented Apr 3, 2022 via email

@ahochsteger
Copy link

@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:
joscha82/wattpilot#6

Still the best would be to add it to the fronius integration ...
Any chance for it, @safepay?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants