sonnenbatterie 0.7.dev7__tar.gz → 0.7.dev9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {sonnenbatterie-0.7.dev7/sonnenbatterie.egg-info → sonnenbatterie-0.7.dev9}/PKG-INFO +1 -1
  2. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/setup.cfg +1 -1
  3. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie/sonnenbatterie.py +21 -15
  4. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9/sonnenbatterie.egg-info}/PKG-INFO +1 -1
  5. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie.egg-info/SOURCES.txt +1 -0
  6. sonnenbatterie-0.7.dev9/test/test_login_new.py +49 -0
  7. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/LICENSE +0 -0
  8. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/README.md +0 -0
  9. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/pyproject.toml +0 -0
  10. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/setup.py +0 -0
  11. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie/__init__.py +0 -0
  12. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie/const.py +0 -0
  13. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie.egg-info/dependency_links.txt +0 -0
  14. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie.egg-info/requires.txt +0 -0
  15. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie.egg-info/top_level.txt +0 -0
  16. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie2/__init__.py +0 -0
  17. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie2/const.py +0 -0
  18. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/sonnenbatterie2/sonnenbatterie2.py +0 -0
  19. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_api_v1.py +0 -0
  20. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_api_v2.py +0 -0
  21. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_battery_reserve.py +0 -0
  22. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_battery_reserve_async.py +0 -0
  23. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_operating_mode.py +0 -0
  24. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_operating_mode_api_v2.py +0 -0
  25. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_operating_mode_async.py +0 -0
  26. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_operating_mode_async_api_v2.py +0 -0
  27. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_retrieval_loop.py +0 -0
  28. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_set_flow.py +0 -0
  29. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_set_flow_async.py +0 -0
  30. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_set_flow_v2.py +0 -0
  31. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_set_flow_v2_async.py +0 -0
  32. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_timeofuse.py +0 -0
  33. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_timeofuse_async.py +0 -0
  34. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_timeofuse_lib.py +0 -0
  35. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_timeofuse_v2.py +0 -0
  36. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/test/test_timeofuse_v2_async.py +0 -0
  37. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/timeofuse/__init__.py +0 -0
  38. {sonnenbatterie-0.7.dev7 → sonnenbatterie-0.7.dev9}/timeofuse/timeofuse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sonnenbatterie
3
- Version: 0.7.dev7
3
+ Version: 0.7.dev9
4
4
  Summary: "Access Sonnenbatterie REST API"
5
5
  Home-page: https://github.com/weltmeyer/python_sonnenbatterie
6
6
  Author: Jan Weltmeyer
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = sonnenbatterie
3
- version = 0.7.dev7
3
+ version = 0.7.dev9
4
4
  author = Jan Weltmeyer
5
5
  description = "Access Sonnenbatterie REST API"
6
6
  long_description = file: README.md
@@ -290,8 +290,6 @@ class AsyncSonnenBatterie:
290
290
  saltResponseCode = salt.status
291
291
 
292
292
 
293
-
294
-
295
293
  if saltResponseCode!=200: #use old variant where no salt is availlable
296
294
  #Old path (no salt): PBKDF2 over sha512(password) + challenge → hex
297
295
  response=hashlib.pbkdf2_hmac('sha512',pw_sha512.encode('utf-8'),challenge.encode('utf-8'),7500,64).hex()
@@ -314,6 +312,16 @@ class AsyncSonnenBatterie:
314
312
  self.sb2 = AsyncSonnenBatterieV2(ip_address=self.ipaddress, api_token=self.token)
315
313
 
316
314
 
315
+
316
+ def create_response_from_values(self, username, password, challenge, salt):
317
+ pw_sha512_hex = hashlib.sha512(password.encode("utf-8")).hexdigest()
318
+ pw_bytes = pw_sha512_hex.encode("utf-8")
319
+ dk = hashlib.pbkdf2_hmac("sha512", pw_bytes, salt.encode("utf-8"), 7500, dklen=64)
320
+ derived_hex = dk.hex()
321
+ key = derived_hex.encode("utf-8")
322
+ response = hmac.new(key, challenge.encode("utf-8"), hashlib.sha256).hexdigest()
323
+ return response
324
+
317
325
  async def create_session_token_new(self):
318
326
  # Step 1: challenge
319
327
  async with self._session.get(f"{self.baseurl}challenge") as r:
@@ -330,19 +338,18 @@ class AsyncSonnenBatterie:
330
338
  r.raise_for_status()
331
339
  salt = (await r.json())["salt"]
332
340
 
333
- # Step 3: derive key
334
- pw_sha512_hex = hashlib.sha512(self.password.encode("utf-8")).hexdigest()
335
- pw_bytes = pw_sha512_hex.encode("utf-8")
336
- dk = hashlib.pbkdf2_hmac("sha512", pw_bytes, salt.encode("utf-8"), 7500, dklen=64)
337
- derived_hex = dk.hex()
338
-
341
+
339
342
  # Step 4: loop: POST /session, maybe retry with new_challenge
340
343
  for _ in range(2):
341
- key = derived_hex.encode("utf-8")
342
- response = hmac.new(key, challenge.encode("utf-8"), hashlib.sha256).hexdigest()
343
- payload = {"user": self.username, "challenge": challenge, "response": response}
344
+ response = self.create_response_from_values(self.username,self.password,challenge,salt)
345
+ body = urlencode(payload).encode("utf-8")
346
+ async with self._session.post(
347
+
348
+ url = self.baseurl+'session',
349
+ data = {"user":self.username,"challenge":challenge,"response":response},
350
+ timeout=self._timeout,
344
351
 
345
- async with self._session.post(f"{self.baseurl}session", json=payload) as r:
352
+ ) as r:
346
353
  txt = await r.text()
347
354
  if r.status >= 400:
348
355
  raise RuntimeError(
@@ -351,9 +358,7 @@ class AsyncSonnenBatterie:
351
358
  f"Payload: {json.dumps(payload)}\n"
352
359
  f"challenge: {challenge}\n"
353
360
  f"salt: {salt}\n"
354
- f"pw_sha_hex: {pw_sha512_hex}\n"
355
- f"derived_hex: {derived_hex}\n"
356
- f"response_hex: {response}\n"
361
+ f"response: {response}\n"
357
362
  f"Server reply: {txt}"
358
363
  )
359
364
  r.raise_for_status()
@@ -365,6 +370,7 @@ class AsyncSonnenBatterie:
365
370
 
366
371
  if "authentication_token" in data and data["authentication_token"]:
367
372
  self.token = data["authentication_token"]
373
+ return
368
374
 
369
375
  raise RuntimeError(f"Unexpected /session response: {json.dumps(data)}")
370
376
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sonnenbatterie
3
- Version: 0.7.dev7
3
+ Version: 0.7.dev9
4
4
  Summary: "Access Sonnenbatterie REST API"
5
5
  Home-page: https://github.com/weltmeyer/python_sonnenbatterie
6
6
  Author: Jan Weltmeyer
@@ -26,6 +26,7 @@ test/test_api_v1.py
26
26
  test/test_api_v2.py
27
27
  test/test_battery_reserve.py
28
28
  test/test_battery_reserve_async.py
29
+ test/test_login_new.py
29
30
  test/test_operating_mode.py
30
31
  test/test_operating_mode_api_v2.py
31
32
  test/test_operating_mode_async.py
@@ -0,0 +1,49 @@
1
+
2
+ #!/usr/bin/env python3
3
+ # I suspect that I haven't got to grips with the way phthon does things, but soppusely this will setup the path to allod for the sonnen batteri moduel to be in a separate location
4
+ # To me having to do this for testing seems a horrendous hack
5
+ import asyncio
6
+ import os
7
+ import sys
8
+ import time
9
+ import json
10
+ import sys
11
+ import base64, binascii, hashlib, hmac, string
12
+ script_path = os.path.realpath(os.path.dirname(__name__))
13
+ os.chdir(script_path)
14
+ sys.path.append("..")
15
+ from pprint import pprint
16
+ import hashlib
17
+
18
+ # this is based on the test code by rust dust
19
+
20
+ def main():
21
+ challenge="39bdd8a304b84c76"
22
+ challenge="d43aeb06a6394daa"
23
+ username="User"
24
+ password="sonnenUser3552!"
25
+ salt="04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb_02bbe1e15021947b232050cc88b07772"
26
+ testResponse=create_response_from_values(username,password,challenge,salt)
27
+ wantedResponse="39b5cb8cc21772b482cdbbcbd135f4a05af4974f3e1b9e4c8aa846d6e64bcc1a"
28
+
29
+
30
+ if testResponse==wantedResponse:
31
+ print("It works!")
32
+ else:
33
+ print("doesnt work :(")
34
+
35
+ print("Response: "+testResponse)
36
+
37
+
38
+ def create_response_from_values(username, password, challenge, salt):
39
+ pw_sha512_hex = hashlib.sha512(password.encode("utf-8")).hexdigest()
40
+ pw_bytes = pw_sha512_hex.encode("utf-8")
41
+ dk = hashlib.pbkdf2_hmac("sha512", pw_bytes, salt.encode("utf-8"), 7500, dklen=64)
42
+ derived_hex = dk.hex()
43
+ key = derived_hex.encode("utf-8")
44
+ response = hmac.new(key, challenge.encode("utf-8"), hashlib.sha256).hexdigest()
45
+ return response
46
+
47
+
48
+ if __name__ == '__main__':
49
+ main()