thomluther / anker-solix-api

Python library for Anker Solix API
MIT License
38 stars 12 forks source link

Question about encryption & (hopefully) some useful data #18

Closed TheRealSimon42 closed 4 months ago

TheRealSimon42 commented 4 months ago

Hey Guys, I am a Creator of Home Assistant Content in Germany and I'm currently trying to figure out, how to set the output values of the Anker Solix Solarbank.

I got so far, that I tried reverse-Engineering the App-Communication via "Surge" (Can get Flutter-App Traffic), but it seems like the Body is somehow encrypted. Here are some details, hoping it helps:

Request Response
DE8B602F-2203-49A9-AE32-CA6BD0A2C2F7_1_102_o 271DD43C-C2F4-48FF-80AE-D49EA5F97E6F_1_102_o
26694898-7CD0-4EF0-931B-A08A79585FEE_1_102_o 2ACB43DC-C5AD-42A2-80E4-FB7A65A8EF4C_1_102_o

Full Body (Request)

MTcwODEwMzc5NzQwNDkwOP/5wqXxK2EGqFpTU0MKvYV8+4IPoaFWGz54ERQjoOYZJBgyqb+CdG3KGgsvZEmNIbEIOSK/EdNHQdRq4Ybq3TqvribSUVlzFCWsaSvVQXHvImu5dqFZ45VMR2gCW0JVIDqBk4UuoHI9dVRsV70DWqb8rH1iZ1dqzdRn99obqwQZSdNPld6umOZ271AjgufiWOfXBP8HaMcgq8NTJUjH4WuHsaQF1v64rYtY0E0byDM4B9kklQ4DRIdwJryNFd9IhjK7a2UL5EU/TK/eWpB6wEXLEKc5pleLkij9QVy+r8VQ+vW9M9F69U5yBVnWQ8IBrCZFB/TuIMmJYjNp6JWh7rVlMpYYHaag77981HTmhAYlpP7AGDhAqiUCOUxv0hgHi6btchPfsHVynZ5wuANGwu2ipTb296zQXOSYgbBzHDJbro9aAZB560XUHrW4ICDFqdQ48rFRvqozHDxehIv94pR6qzGz5MlVdTbzUjgj8weIGDnA2jWNTLirW/lEkBnoI2Wmo2TBREgru1698XXhDnqj+tiwuzDTtfcK/SL9dMs8aZccyETrF98z/rKeW/nXPDIGtoUvEO73HpNoZ42OAu6zv7XvcmxSiAErL+fKpbHdZ6rrjntLNu/qEDxRX6dy8n3EHSbkBAQDNnWGnN50SxaNnxLnYRJFl5UHKV7J0JZmc2p7iH2zT2NIi5nOJrNJ4sbj/5XQF3YUTvxaXVAeuWjAS3LGgc2khL3RjBYQbJbh6HiqmUnE9bQFEw5tKrcil9dXNPta230kH7wzWmKaL50sSEjP7XSBSOyba+TbygrBrFi61O6woi5FKBw5RODZ/ew7egV5au6Q9VBCHWJpwaiGklwUGnPCyOWRuSxfi+xd288rBldD3chPOIZRA6dRPgLHtI6b68E8oki5UDCO54ixlZKILOhL7cOMBUvmKIsVwro7RKgiix+vgdYRYBbgI5DbFUVQoFvhLOH5FxjQp+j/CJl4JJYc3OU+Y8FkKQFOB1VTqB3rMiEoA9noX8HjW2FEvagu4ny73KaYMRKFrwfCZ95ngtGTVwUkHTvw0tJ1f69obA9ktFLv7O8l4s6PwmYRUs+5e8BRd31eATJogBD5XVwhoOPAzu3RHtFW9g2Vdg0HA+Llop0estt3etPgizdcFrQSVIZoPt1n44tOFrYOYo+LUaLKviNv00/XlrtQRnZOW2YfkHTNNiKkG/hvkoeMj0Qgyse3rNioSvCHWlnTiiwvvxiTmhJ4SUr4Aq1BNUuI8ks6PQQjS5LWylXIzE/79O+cYdPhy8n7utgF8+k2IFrKpNtuuryx6QgZXG+WAJdTz5Cf09b6BKcFQE1XCbALWEN5K7zobu6Y2w9fJ+GYv21pwucha6kQ0emLrRUmuc1f4Qp2q1z+5hI/Z3efzihtLhenbzzi0fVazoZoOsKk2U4TGCrL9Lm/4ltke1Jud4AviKYEVZV5+lYeO6L7qgUF3k2v7PO5kb6TNHselHGEMH4YIJbZeRQ/nt0hldrMmWlNsZeJu2ZKUP/jjvBfY4C5ich6VFw4T/ke1AKV3lazJaRlkwJYZ3N07SXE+NGjmRW9colg1oY3wkGUT6FX1+O99eqG2svywAF51/Yp/xc65Zfr9QIYXckUqpAHegsKwRfHMfaeQSWnK9rokLro75DDuaf3XZutKPnL0c/138IWv1VDrSfE+/ZniKUHa3OA64U5aMQnnD6bZOY3v3Qq8FUg2cGkiOIirRlVRoDLbadxXg0s9Tv7fNcTGCvMIFJ4NdLV4g0TDb0uJYjRgCXDo4MKLHEY/EagQjHSZ4WwUzyxVWZ2RZawcy/Y7KnmtPQsfo/WWOxmcqDYBqbiX6C96A==

I already tried to write a function to get it decrypted, but no luck so far. Maybe someone could figure out a way, on how to do this? The Command should show (when decrypted) how to set the Power-Output of the current timeframe to 100W or 140W, not quite sure which command this was 😅.

By the way, here in this other Repo it seems like already implemented: https://github.com/energychain/AnkerSolixE1600-APIServices/blob/main/index.js#L289C1-L289C44

thomluther commented 4 months ago

Hi @TheRealSimon42 Glad to hear from you. I follow your YT channel (which is great btw), and saw that you are starting with the Solarbank :-) You may be interested to join following discussion channel, which discusses lots of stuff and problems around the Solarbank (german): https://www.photovoltaikforum.com/thread/207101-anker-solix-balkonkraftwerk-speicher/

I know the other solix api repos, they are all based on node.js and java-script, therefore I converted them to this python library. This lib is also the base for a Home Assistant integration I'm working on. This is about 70% finished and I hope to release it via HACS in a couple of weeks.

Anyway, my focus so far was on Monitoring only, since the modification queries needs parameters that I'm not aware of and I have no clue how to reverse engineer the App traffic. And as you discovered, its decrypted as well.

The device set query you mention is already implemented, but I have not tested it yet (My solarbank is still in 'Winterschlaf') It should work the same way it is working with the java-script api. Point is, that you cannot simply submit a new home load value, but you need to submit the schedule with new parameters, either for the active slot or maybe the whole schedule.

So basically you probably need to first query the schedule: async def get_device_parm( self, siteId: str, paramType: str = "4", fromFile: bool = False ) -> dict:

Then you can change the value in the Json reponse and resubmit the whole json with the paramData dictionary async def set_device_parm( self, siteId: str, paramData: dict, paramType: str = "4", command: int = 17, toFile: bool = False, ) -> dict:

Let me know if that will work for you. I have in plan to create a helper function for the value setting anyway, but need first experience and feedback, what options will be accepted for the paramData in the set_device_parm method. BTW, there is also the get_device_load and set_device_load endpoints. The get_device_load endpoint provides the same schedule dict as the get_site parm. So you can use that for the first query as well: async def get_device_load( self, siteId: str, deviceSn: str, fromFile: bool = False ) -> dict:

However, I have no idea if set_device_load requires additional parameters, or just the same paramData as the set_device_parm methods.... Those endpoints are probably newer, and never explored by the original node.js libraries.

thomluther commented 4 months ago

@TheRealSimon42 , if you want to explore the API, I recommend to use the test_api module from this lib first and enable debug mode (uncomment the line in the test_api). When you then login with your account credentials, you can see the full header that is used for subsequent API requests. With that header, you can basically use any Rest client of your choice to make further queries against the server. They may provide more information in the error which parameters are missing than the standard websession client of this lib does (Still have to figure out how to reveal such extra error information, that may be helpful to compose the correct parameters for a query.) The tokens will work as long as you do not login with another API client (e.g. the App), since the server only allow 1 active login token and each login request will get a new one. The API uses a token cache in a file, therefore login must be requested only if the cached tokens don't exist or became invalid for any reason.

thomluther commented 4 months ago

One last comment on this. Looking at the header fields used by the app, it seems it uses more x-* fields than the api actually does. Therefore the api receives unencrypted bodies, and does neither encrypt them on requests, however the App seem to use more encryption on the bodies...

Since EDHC is used (also during the login request), there is no common way to decrypt a given content, unless you have the shared secret that was negotiated between the client and server during the login request.

TheRealSimon42 commented 4 months ago

Wow, thanks for all the feedback & praise on my videos ♥️

I'll get back to it when I have time tonight or next week to see if I can make any progress and keep you updated.

A Home Assistant integration would of course be amazing 🙌

Maybe it would also be a way to start (since you probably have to send an array of the planned time slots via the API, with the changed data) that you initially specify as a limitation of the integration that you can only have one schedule with one entry. This way, you wouldn't have to come up with any logic on how to display the time slots in Home Assistant, for example. Apart from as a string, I frankly couldn't think of much else (with JSON.stringify or something)

thomluther commented 4 months ago

Hi @TheRealSimon42 , I'm still putting structure on the schedule setting. I just learned, that the schedule can be queried and probably also set just with the solarbank sn parameter, however when 2 banks are configured in a system (which is the max. count per system), they both have the same schedule and pre-set with 50% of the scheduled slot. So the schedule itself is still a property of the system (site_id), but I will monitor and report it separately with each solarbank device. That allows to avoid changes when individual schedule settings will be supported in future.

My idea to implement settings for home in a future release is to initially provide 2 options. A number entity to change the value of the actual slot, and a switch that specifies whether the number change should be applied to all slots or just the active one. A change can then first use the last schedule reported for the device and modify only the actual or all slot values and set it as a whole dict again. That should work without messing up any defined slots, but will need testing anyway. So nothing for the first integration release I track this helper function in the api with #19

stuertz commented 4 months ago

@TheRealSimon42 Hi, just my 50cents: your request body looks like its base64 encoded. But after decoding, it looks like some binary format. x-ecryption-info set to algo-ecdh lets me think the data is Diffie Hellmann encrypted, which can only be decryted if you have the private key. So that aproach seems to be a dead end. - Sorry

thomluther commented 4 months ago

Correct, tha'st what I mentioned previously. The login negotiation is the same. Elliptic Curve Diffi Hellman (ECDH) public key exchange to generate unique shared secret just for the individual server-client connection which uses a login token. One of the request fields must also be AES encrypted (with first part of the shared key) and base64 encoded and must be included in the request headers (I believe the binary user id that was generated with the token) I assume the same mechanism would need to be used for the body to encrypt/decrypt, and the encryption is indicated by the additional header fields. As long as we don't need them for the Api, its easier. But when the mechanism is really the same as for the login request, we could probably implement it in the Api if needed. However, for traffic sniffing on the App device you have no chance with ECDH, since the shared key actually used is unknown and decryption is not possible. Only way is to explore the Api endpoint separately via various parameter settings. I have now the server error message included, this gives some indications about missing required parameter fields and also when the value is wrong format. This way, I could yesterday figure out how to set the Auto-Update settings via Api. Similar approach might work for other set endpoints. Disadvantage is, that you don't get aware of optional parameters for the queries. All relevant endpoints I found in the code I put into the api comments. Since none of them revealed the solarbank temperature yet, I suspect that this is just presented with an optional parameter on existing queries. Temp is still an important monitor value for the solarbank, to understand when and why battery charge is limited.

thomluther commented 4 months ago

Hi @TheRealSimon42 I have watched your video about the Solarbank installation, Great Have you been in contact with Anker about Smart Home integration and Api?

In the past, their support always made gave vague feedback that they may provide something in the future. But recently someone in the forum got direct feedback that Anker Solix has no plans to integrate into Smart Home or provide any interfaces.

So I'm concerned about their official standing to community usage of their Api.... In worst case, they may lock it down if it becomes too public or the server requests grow into dimensions they did not expect. Since you mentioned that you want to make another video about the solarbank integration into HA, I assume you can use my Integration that will become available in March. However, if there will be to much attention by Anker to this inofficial Api usage, I'm concerned this will not be available for a long time... I might be wrong, but it would not be the first vendor putting restrictions or repository removal enforcements to HA community developpers. Anker doesn't seem to be very interested into Smart Home integration or official Apis. Also for their Eufy Brand there was never an official Api. On the other hand, they seem to tolerate the community Apis and integrations that exists since years...

thomluther commented 4 months ago

Hi @TheRealSimon42 I released the HA integration today. I think this will be usefull for you as well, many community users did desperately wait for some integration for Anker Solix device. After Anker support meanwhile announced that they do not have any plans to provide Smart Home integration, I would be interested if you got any feedback from Anker on that topic and what their standing might be to the unofficial Api in case you publish this to a broader community? See my previous post regarding this topic.