solarlog-cli 0.6.0__tar.gz → 0.7.0__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 (43) hide show
  1. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.coverage +0 -0
  2. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.github/workflows/pylint.yml +1 -1
  3. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.github/workflows/python-publish.yml +1 -1
  4. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.github/workflows/ruff.yml +1 -1
  5. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.github/workflows/tests.yml +2 -2
  6. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.github/workflows/typing.yml +1 -1
  7. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/PKG-INFO +1 -1
  8. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/pyproject.toml +1 -1
  9. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/requirements.txt +1 -1
  10. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/src/solarlog_cli/solarlog_client.py +65 -58
  11. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/src/solarlog_cli/solarlog_connector.py +36 -19
  12. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/src/solarlog_cli/solarlog_models.py +7 -1
  13. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/__snapshots__/test_solarlog_cli.ambr +6 -0
  14. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/test_solarlog_cli.py +32 -2
  15. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.devcontainer/devcontainer.json +0 -0
  16. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.gitignore +0 -0
  17. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.vscode/settings.json +0 -0
  18. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/.vscode/tasks.json +0 -0
  19. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/LICENSE +0 -0
  20. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/README.md +0 -0
  21. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/pytest.ini +0 -0
  22. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/src/solarlog_cli/__init__.py +0 -0
  23. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/src/solarlog_cli/py.typed +0 -0
  24. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/src/solarlog_cli/solarlog_exceptions.py +0 -0
  25. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/__init__.py +0 -0
  26. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/conftest.py +0 -0
  27. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/basic_data.json +0 -0
  28. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/basic_data_during_update.json +0 -0
  29. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/basic_data_no_power.json +0 -0
  30. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/battery_data.json +0 -0
  31. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/battery_data_without_battery.json +0 -0
  32. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/device_data_1.json +0 -0
  33. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/device_data_2.json +0 -0
  34. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/device_data_3.json +0 -0
  35. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/device_data_4.json +0 -0
  36. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/device_list.json +0 -0
  37. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/device_list_access_denied.json +0 -0
  38. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/energy_per_inverter.json +0 -0
  39. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/extended_data.json +0 -0
  40. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/power_per_inverter.json +0 -0
  41. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/fixtures/user_salts.json +0 -0
  42. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/ruff.toml +0 -0
  43. {solarlog_cli-0.6.0 → solarlog_cli-0.7.0}/tests/syrupy.py +0 -0
@@ -7,7 +7,7 @@ jobs:
7
7
  runs-on: ubuntu-latest
8
8
  strategy:
9
9
  matrix:
10
- python-version: ["3.12"]
10
+ python-version: ["3.13"]
11
11
  steps:
12
12
  - name: ⤵️ Checkout the repository
13
13
  uses: actions/checkout@v4.1.7
@@ -25,7 +25,7 @@ jobs:
25
25
  - name: Set up Python
26
26
  uses: actions/setup-python@v3
27
27
  with:
28
- python-version: '3.12'
28
+ python-version: '3.13'
29
29
  - name: Install dependencies
30
30
  run: |
31
31
  python -m pip install --upgrade pip
@@ -18,7 +18,7 @@ jobs:
18
18
  - name: 🏗 Set up Python
19
19
  uses: actions/setup-python@v5.0.0
20
20
  with:
21
- python-version: "3.12"
21
+ python-version: "3.13"
22
22
  cache: "pip"
23
23
  - name: 🏗 Install requirements
24
24
  run: python3 -m pip install -r requirements.txt
@@ -9,7 +9,7 @@ on:
9
9
  workflow_dispatch:
10
10
 
11
11
  env:
12
- DEFAULT_PYTHON: "3.12"
12
+ DEFAULT_PYTHON: "3.13"
13
13
 
14
14
  jobs:
15
15
  pytest:
@@ -17,7 +17,7 @@ jobs:
17
17
  runs-on: ubuntu-latest
18
18
  strategy:
19
19
  matrix:
20
- python: ["3.12"]
20
+ python: ["3.13"]
21
21
  steps:
22
22
  - name: ⤵️ Check out code from GitHub
23
23
  uses: actions/checkout@v4.1.7
@@ -10,7 +10,7 @@ on:
10
10
  - main
11
11
 
12
12
  env:
13
- DEFAULT_PYTHON: "3.12"
13
+ DEFAULT_PYTHON: "3.13"
14
14
 
15
15
  jobs:
16
16
  mypy:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: solarlog_cli
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Python library to access the Solar-Log
5
5
  Project-URL: Repository, https://github.com/dontinelli/solarlog_cli.git
6
6
  Project-URL: Issues, https://github.com/dontinelli/solarlog_cli/issues
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "solarlog_cli"
3
- version = "0.6.0"
3
+ version = "0.7.0"
4
4
  authors = [
5
5
  { name="dontinelli", email="73341522+dontinelli@users.noreply.github.com" },
6
6
  ]
@@ -1,4 +1,4 @@
1
- aiohttp>=3.9.5
1
+ aiohttp>=3.13.3
2
2
  aioresponses == 0.7.6
3
3
  bcrypt >= 4.3.0
4
4
  mashumaro>=3.13
@@ -17,11 +17,12 @@ from .solarlog_exceptions import (
17
17
  SolarLogUpdateError,
18
18
  )
19
19
 
20
- from .solarlog_models import SolarlogData
20
+ from .solarlog_models import EnergyData, SolarlogData
21
21
 
22
22
  SOLARLOG_REQUEST_PAYLOAD = '{ "801": { "170": null } }'
23
23
  _LOGGER = logging.getLogger(__name__)
24
24
 
25
+
25
26
  class Client:
26
27
  """Client class to access Solar-Log."""
27
28
 
@@ -30,7 +31,6 @@ class Client:
30
31
  def __init__(self, host: str, session: ClientSession | None, password: str = "") -> None:
31
32
  self.host: str = host
32
33
  self.password: str = password
33
- self.token: str = ""
34
34
 
35
35
  self.request_timeout = 30
36
36
 
@@ -39,9 +39,9 @@ class Client:
39
39
  else:
40
40
  self.session = session
41
41
 
42
+ self._hashed_pwd: bool = False
42
43
  self._close_session: bool = True
43
44
 
44
-
45
45
  async def test_connection(self) -> bool:
46
46
  """Test the connection to Solar-Log."""
47
47
  if self.session is None:
@@ -68,12 +68,12 @@ class Client:
68
68
 
69
69
  payload: str = f"u=user&p={self.password}"
70
70
 
71
- response = await self.execute_http_request(payload,"login")
71
+ response = await self.execute_http_request(payload, "login")
72
72
 
73
73
  text = await response.text()
74
- _LOGGER.debug("Response: %s",text)
74
+ _LOGGER.debug("Response: %s", text)
75
75
  if text.count("FAILED - User was wrong"):
76
- #Response means, that no password is required
76
+ # Response means, that no password is required
77
77
  self.password = ""
78
78
  return False
79
79
 
@@ -87,19 +87,21 @@ class Client:
87
87
  response = await self.execute_http_request(payload)
88
88
 
89
89
  text = await response.text()
90
- _LOGGER.debug("Response to request for user salts: %s",text)
90
+ _LOGGER.debug("Response to request for user salts: %s", text)
91
91
  r_dict: dict[str, Any] = json.loads(text)
92
92
 
93
- salt: str = r_dict.get('550',{}).get('104')
94
- _LOGGER.debug("Salt to hash pwd: %s",salt)
93
+ salt: str = r_dict.get('550', {}).get('104')
94
+ _LOGGER.debug("Salt to hash pwd: %s", salt)
95
95
 
96
96
  try:
97
97
  if salt != 'QUERY IMPOSSIBLE 000' and salt is not None:
98
- hashed_password = bcrypt.hashpw(self.password.encode(), salt.encode())
98
+ hashed_password = bcrypt.hashpw(
99
+ self.password.encode(), salt.encode())
99
100
  payload = f"u=user&p={hashed_password.decode('utf-8')}"
100
- response = await self.execute_http_request(payload,"login")
101
+ response = await self.execute_http_request(payload, "login")
101
102
  text = await response.text()
102
- _LOGGER.debug("Response of login with hashed pwd: %s",text)
103
+ _LOGGER.debug(
104
+ "Response of login with hashed pwd: %s", text)
103
105
  if text.count("FAILED - Password was wrong"):
104
106
  _LOGGER.debug("Wrong password (hashed)")
105
107
  raise SolarLogAuthenticationError
@@ -107,15 +109,19 @@ class Client:
107
109
  except Exception as exception:
108
110
  raise SolarLogAuthenticationError from exception
109
111
 
110
- self.token = response.cookies["SolarLog"].value
112
+ self._hashed_pwd = True
111
113
 
112
- _LOGGER.debug("response: %s",text)
113
- _LOGGER.debug("cookies: %s",response.cookies)
114
- _LOGGER.debug("Login successful, token: %s",self.token)
114
+ self.session.cookie_jar.update_cookies(
115
+ {"SolarLog": response.cookies["SolarLog"].value})
116
+
117
+ _LOGGER.debug("response: %s", text)
118
+ _LOGGER.debug("cookies: %s", response.cookies)
119
+ _LOGGER.debug("Login successful, token: %s",
120
+ response.cookies["SolarLog"].value)
115
121
 
116
122
  return True
117
123
 
118
- async def execute_http_request(self, body: str, path: str = "getjp") -> ClientResponse:
124
+ async def execute_http_request(self, body: str, path: str = "getjp", timeout: float | None = None) -> ClientResponse: # pylint: disable=line-too-long
119
125
  """Helper function to process the HTTP Get call."""
120
126
  if self.session is None:
121
127
  self.session = ClientSession()
@@ -124,11 +130,8 @@ class Client:
124
130
  url = f"{self.host}/{path}"
125
131
 
126
132
  header = {"Content-Type": "text/html", "X-SL-CSRF-PROTECTION": "1"}
127
- if self.token != "":
128
- header |= {"Cookie": f"SolarLog={self.token}"}
129
- body = f"token={self.token}; " + body
130
133
 
131
- _LOGGER.debug("HTTP-request header: %s",header)
134
+ _LOGGER.debug("HTTP-request header: %s", header)
132
135
  _LOGGER.debug("HTTP-request body: %s", body)
133
136
 
134
137
  try:
@@ -136,7 +139,7 @@ class Client:
136
139
  url=url,
137
140
  headers=header,
138
141
  data=body,
139
- timeout=ClientTimeout(total=self.request_timeout),
142
+ timeout=ClientTimeout(total=timeout or self.request_timeout),
140
143
  )
141
144
  except asyncio.TimeoutError as exception:
142
145
  msg = f"Timeout occurred while connecting to Solar-Log at {self.host}"
@@ -153,14 +156,14 @@ class Client:
153
156
  {"Content-Type": content_type, "response": text},
154
157
  )
155
158
 
156
- _LOGGER.debug("HTTP-request successful: %s",response)
159
+ _LOGGER.debug("HTTP-request successful: %s", response)
157
160
  return response
158
161
 
159
162
  async def parse_http_response(self, response: ClientResponse) -> dict[str, Any]:
160
163
  """Helper function to parse the HTTP response."""
161
164
 
162
- text = await response.text()
163
- _LOGGER.debug("Parsing http response: %s",text)
165
+ text = await response.text(errors="replace")
166
+ _LOGGER.debug("Parsing http response: %s", text)
164
167
 
165
168
  if text.count('{"QUERY IMPOSSIBLE 000"}'):
166
169
  raise SolarLogUpdateError(f"Server response: {text}")
@@ -188,54 +191,56 @@ class Client:
188
191
  raw_data = raw_data["801"]["170"]
189
192
 
190
193
  data = SolarlogData(
191
- last_updated = datetime.strptime(raw_data["100"], "%d.%m.%y %H:%M:%S"),
192
- power_ac = raw_data["101"],
193
- power_dc = raw_data["102"],
194
- voltage_ac = raw_data["103"],
195
- voltage_dc = raw_data["104"],
196
- yield_day = raw_data["105"],
197
- yield_yesterday = raw_data["106"],
198
- yield_month = raw_data["107"],
199
- yield_year = raw_data["108"],
200
- yield_total = raw_data["109"],
201
- consumption_ac = raw_data["110"],
202
- consumption_day = raw_data["111"],
203
- consumption_yesterday = raw_data["112"],
204
- consumption_month = raw_data["113"],
205
- consumption_year = raw_data["114"],
206
- consumption_total = raw_data["115"],
207
- total_power = raw_data["116"],
194
+ last_updated=datetime.strptime(
195
+ raw_data["100"], "%d.%m.%y %H:%M:%S"),
196
+ power_ac=raw_data["101"],
197
+ power_dc=raw_data["102"],
198
+ voltage_ac=raw_data["103"],
199
+ voltage_dc=raw_data["104"],
200
+ yield_day=raw_data["105"],
201
+ yield_yesterday=raw_data["106"],
202
+ yield_month=raw_data["107"],
203
+ yield_year=raw_data["108"],
204
+ yield_total=raw_data["109"],
205
+ consumption_ac=raw_data["110"],
206
+ consumption_day=raw_data["111"],
207
+ consumption_yesterday=raw_data["112"],
208
+ consumption_month=raw_data["113"],
209
+ consumption_year=raw_data["114"],
210
+ consumption_total=raw_data["115"],
211
+ total_power=raw_data["116"],
208
212
  )
209
213
 
210
214
  return data
211
215
 
212
- async def get_battery_data(self) -> list[float]:
213
- """Get power data from Solar-Log"""
216
+ async def get_battery_data(self, timeout: float | None = None) -> list[float]:
217
+ """Get battery data from Solar-Log"""
214
218
 
215
219
  raw_data: dict = await self.parse_http_response(
216
- await self.execute_http_request('{ "858": null }')
220
+ await self.execute_http_request('{ "858": null }', timeout=timeout)
217
221
  )
218
222
 
219
223
  data: list[float] = raw_data["858"]
220
224
 
221
225
  return data
222
226
 
223
- async def get_power_per_inverter(self) -> dict[int, float]:
227
+ async def get_power_per_inverter(self, timeout: float | None = None) -> dict[int, float]:
224
228
  """Get power data from Solar-Log"""
225
229
 
226
230
  raw_data: dict = await self.parse_http_response(
227
- await self.execute_http_request('{ "782": null }')
231
+ await self.execute_http_request('{ "782": null }', timeout=timeout)
228
232
  )
229
233
 
230
- data = {int(key): val for key, val in raw_data["782"].items() if val != "0"}
234
+ data = {int(key): val for key,
235
+ val in raw_data["782"].items() if val != "0"}
231
236
 
232
237
  return data
233
238
 
234
- async def get_energy_per_inverter(self) -> dict[int, float]:
239
+ async def get_energy_per_inverter(self, timeout: float | None = None) -> dict[int, float]:
235
240
  """Get power data from Solar-Log"""
236
241
 
237
242
  raw_data: dict = await self.parse_http_response(
238
- await self.execute_http_request('{ "854": null }')
243
+ await self.execute_http_request('{ "854": null }', timeout=timeout)
239
244
  )
240
245
  data_list = raw_data["854"][-1][-1]
241
246
 
@@ -247,25 +252,27 @@ class Client:
247
252
 
248
253
  return data
249
254
 
250
- async def get_energy(self, data: SolarlogData) -> SolarlogData:
255
+ async def get_energy(self, timeout: float | None = None) -> EnergyData | None:
251
256
  """Get energy data from Solar-Log"""
252
257
 
253
258
  raw_data: dict = await self.parse_http_response(
254
- await self.execute_http_request('{ "878": null }')
259
+ await self.execute_http_request('{ "878": null }', timeout=timeout)
255
260
  )
256
261
 
257
262
  if raw_data["878"] != "QUERY IMPOSSIBLE 000":
258
- data.production_year = raw_data["878"][-1][1]
259
- data.self_consumption_year = raw_data["878"][-1][3]
263
+ return EnergyData(
264
+ production=raw_data["878"][-1][1],
265
+ self_consumption=raw_data["878"][-1][3]
266
+ )
260
267
 
261
- return data
268
+ return None
262
269
 
263
- async def get_device_list(self) -> dict[int, str]:
270
+ async def get_device_list(self, timeout: float | None = None) -> dict[int, str]:
264
271
  """Get list of all connected devices."""
265
272
 
266
273
  # get list of all inverters connected to Solar-Log
267
274
  raw_data: dict = await self.parse_http_response(
268
- await self.execute_http_request('{ "740": null }')
275
+ await self.execute_http_request('{ "740": null }', timeout=timeout)
269
276
  )
270
277
  raw_data = raw_data["740"]
271
278
 
@@ -276,7 +283,7 @@ class Client:
276
283
  # get name of the inverter
277
284
  raw_data = await self.parse_http_response(
278
285
  await self.execute_http_request(
279
- f"""{{ "141": {{ "{key}": {{ "119": null }} }} }}"""
286
+ f"""{{ "141": {{ "{key}": {{ "119": null }} }} }}""", timeout=timeout
280
287
  )
281
288
  )
282
289
  device_list |= {int(key): raw_data["141"][key]["119"]}
@@ -12,7 +12,7 @@ from .solarlog_exceptions import(
12
12
  SolarLogConnectionError,
13
13
  SolarLogUpdateError,
14
14
  )
15
- from .solarlog_models import BatteryData, InverterData, SolarlogData
15
+ from .solarlog_models import BatteryData, EnergyData, InverterData, SolarlogData
16
16
 
17
17
  _LOGGER = logging.getLogger(__name__)
18
18
 
@@ -82,7 +82,28 @@ class SolarLogConnector:
82
82
  return await self.client.login()
83
83
 
84
84
  async def update_data(self) -> SolarlogData:
85
- """Get data from Solar-Log."""
85
+ """Get all data from Solar-Log."""
86
+
87
+ data: SolarlogData = await self.update_basic_data()
88
+
89
+ if self.extended_data:
90
+ energy_data: EnergyData | None = await self.client.get_energy()
91
+
92
+ if energy_data is not None:
93
+ data.production_year = energy_data.production
94
+ data.self_consumption_year = energy_data.self_consumption
95
+
96
+ if self._device_list != {}:
97
+ data.inverter_data = await self.update_inverter_data()
98
+
99
+ data.battery_data = await self.update_battery_data()
100
+
101
+ _LOGGER.debug("Extended data updated: %s",data)
102
+
103
+ return data
104
+
105
+ async def update_basic_data(self) -> SolarlogData:
106
+ """Get basic data from Solar-Log."""
86
107
 
87
108
  data: SolarlogData = await self.client.get_basic_data()
88
109
 
@@ -94,15 +115,6 @@ class SolarLogConnector:
94
115
  data.last_updated = data.last_updated.replace(tzinfo=self.timezone)
95
116
 
96
117
  _LOGGER.debug("Basic data updated: %s",data)
97
- if self.extended_data:
98
- data = await self.client.get_energy(data)
99
-
100
- if self._device_list != {}:
101
- data.inverter_data = await self.update_inverter_data()
102
-
103
- data.battery_data = await self.update_battery_data()
104
-
105
- _LOGGER.debug("Extended data updated: %s",data)
106
118
 
107
119
  #calculated values (for downward compatibility)
108
120
  data.alternator_loss = data.power_dc - data.power_ac
@@ -119,11 +131,10 @@ class SolarLogConnector:
119
131
 
120
132
  return data
121
133
 
122
-
123
- async def update_battery_data(self) -> BatteryData | None:
134
+ async def update_battery_data(self, timeout: float | None = None) -> BatteryData | None:
124
135
  """Update device specific data."""
125
136
 
126
- raw_data = await self.client.get_battery_data()
137
+ raw_data = await self.client.get_battery_data(timeout)
127
138
 
128
139
  if raw_data == []:
129
140
  return None
@@ -139,12 +150,18 @@ class SolarLogConnector:
139
150
 
140
151
  return battery_data
141
152
 
142
- async def update_device_list(self) -> dict[int, InverterData]:
153
+ async def update_energy_data(self, timeout: float | None = None) -> EnergyData | None:
154
+ """Update energy data (production and self consumption)."""
155
+
156
+ return await self.client.get_energy(timeout)
157
+
158
+ async def update_device_list(self, timeout: float | None = None) -> dict[int, InverterData]:
143
159
  """Update list of devices."""
160
+
144
161
  if not self.extended_data:
145
162
  return {}
146
163
 
147
- devices = await self.client.get_device_list()
164
+ devices = await self.client.get_device_list(timeout)
148
165
 
149
166
  self._device_list = {
150
167
  key: InverterData(name=value,enabled=self.device(key).enabled)
@@ -154,16 +171,16 @@ class SolarLogConnector:
154
171
 
155
172
  return self._device_list
156
173
 
157
- async def update_inverter_data(self) -> dict[int, InverterData]:
174
+ async def update_inverter_data(self, timeout: float | None = None) -> dict[int, InverterData]:
158
175
  """Update device specific data."""
159
176
 
160
- raw_data = await self.client.get_power_per_inverter()
177
+ raw_data = await self.client.get_power_per_inverter(timeout)
161
178
  for key, value in raw_data.items():
162
179
  key = int(key)
163
180
  if self._device_list.get(key,InverterData).enabled:
164
181
  self._device_list[key].current_power = float(value)
165
182
 
166
- raw_data = await self.client.get_energy_per_inverter()
183
+ raw_data = await self.client.get_energy_per_inverter(timeout)
167
184
  for key, value in raw_data.items():
168
185
  if self._device_list.get(key,InverterData).enabled:
169
186
  self._device_list[key].consumption_year = float(value)
@@ -13,6 +13,12 @@ class BatteryData():
13
13
  level: float = 0
14
14
  voltage: float = 0
15
15
 
16
+ @dataclass
17
+ class EnergyData():
18
+ """Energy Data model."""
19
+
20
+ production: float | None = None
21
+ self_consumption: float | None = None
16
22
 
17
23
  @dataclass
18
24
  class InverterData():
@@ -21,7 +27,7 @@ class InverterData():
21
27
  name: str = ""
22
28
  enabled: bool = False
23
29
  current_power: float | None = None
24
- consumption_year: float | None= None
30
+ consumption_year: float | None = None
25
31
 
26
32
 
27
33
  @dataclass
@@ -87,3 +87,9 @@
87
87
  }),
88
88
  })
89
89
  # ---
90
+ # name: test_update_energy_data[asyncio]
91
+ dict({
92
+ 'production': 8852462,
93
+ 'self_consumption': 2071,
94
+ })
95
+ # ---
@@ -144,7 +144,6 @@ async def test_login_and_data_retreival(responses: aioresponses) -> None:
144
144
  "http://solarlog.com", password="pwd")
145
145
 
146
146
  assert await solarlog_connector.login()
147
- assert solarlog_connector.client.token == "token"
148
147
 
149
148
  responses.post(
150
149
  "http://solarlog.com/getjp",
@@ -176,7 +175,6 @@ async def test_login_hashed_pwd(responses: aioresponses) -> None:
176
175
  "http://solarlog.com", password="pwd")
177
176
 
178
177
  assert await solarlog_connector.login()
179
- assert solarlog_connector.client.token == "token"
180
178
 
181
179
  await solarlog_connector.client.close()
182
180
  assert solarlog_connector.client.session.closed
@@ -299,6 +297,38 @@ async def test_update_data_without_battery(
299
297
  await solarlog_connector.client.close()
300
298
  assert solarlog_connector.client.session.closed
301
299
 
300
+ async def test_update_energy_data(
301
+ responses: aioresponses,
302
+ snapshot: SnapshotAssertion
303
+ ) -> None:
304
+ """Test update energy data."""
305
+
306
+ responses.post(
307
+ "http://solarlog.com/getjp",
308
+ body=load_fixture("extended_data.json"),
309
+ )
310
+ responses.post(
311
+ "http://solarlog.com/getjp",
312
+ body='{"878": "QUERY IMPOSSIBLE 000"}',
313
+ )
314
+
315
+ solarlog_connector = SolarLogConnector(
316
+ "http://solarlog.com",
317
+ True,
318
+ "UTC",
319
+ {0: True, 1: True, 2: False, 3: True},
320
+ )
321
+
322
+ data = await solarlog_connector.update_energy_data()
323
+
324
+ assert data == snapshot
325
+
326
+ data = await solarlog_connector.update_energy_data()
327
+
328
+ assert data is None
329
+
330
+ await solarlog_connector.client.close()
331
+ assert solarlog_connector.client.session.closed
302
332
 
303
333
  @pytest.mark.parametrize(
304
334
  ("status", "request_timeout", "error"),
File without changes
File without changes
File without changes
File without changes