solarlog-cli 0.3.2__tar.gz → 0.5.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 (42) hide show
  1. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.coverage +0 -0
  2. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/PKG-INFO +2 -2
  3. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/pyproject.toml +1 -1
  4. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/src/solarlog_cli/solarlog_client.py +24 -11
  5. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/src/solarlog_cli/solarlog_connector.py +27 -2
  6. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/src/solarlog_cli/solarlog_models.py +11 -0
  7. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/__snapshots__/test_solarlog_cli.ambr +6 -0
  8. solarlog_cli-0.5.0/tests/fixtures/battery_data.json +3 -0
  9. solarlog_cli-0.5.0/tests/fixtures/battery_data_without_battery.json +3 -0
  10. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/test_solarlog_cli.py +63 -0
  11. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.devcontainer/devcontainer.json +0 -0
  12. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.github/workflows/pylint.yml +0 -0
  13. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.github/workflows/python-publish.yml +0 -0
  14. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.github/workflows/ruff.yml +0 -0
  15. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.github/workflows/tests.yml +0 -0
  16. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.github/workflows/typing.yml +0 -0
  17. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.gitignore +0 -0
  18. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.vscode/settings.json +0 -0
  19. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/.vscode/tasks.json +0 -0
  20. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/LICENSE +0 -0
  21. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/README.md +0 -0
  22. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/pytest.ini +0 -0
  23. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/requirements.txt +0 -0
  24. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/src/solarlog_cli/__init__.py +0 -0
  25. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/src/solarlog_cli/py.typed +0 -0
  26. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/src/solarlog_cli/solarlog_exceptions.py +0 -0
  27. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/__init__.py +0 -0
  28. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/conftest.py +0 -0
  29. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/basic_data.json +0 -0
  30. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/basic_data_during_update.json +0 -0
  31. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/basic_data_no_power.json +0 -0
  32. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/device_data_1.json +0 -0
  33. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/device_data_2.json +0 -0
  34. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/device_data_3.json +0 -0
  35. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/device_data_4.json +0 -0
  36. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/device_list.json +0 -0
  37. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/device_list_access_denied.json +0 -0
  38. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/energy_per_inverter.json +0 -0
  39. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/extended_data.json +0 -0
  40. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/fixtures/power_per_inverter.json +0 -0
  41. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/ruff.toml +0 -0
  42. {solarlog_cli-0.3.2 → solarlog_cli-0.5.0}/tests/syrupy.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: solarlog_cli
3
- Version: 0.3.2
3
+ Version: 0.5.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.3.2"
3
+ version = "0.5.0"
4
4
  authors = [
5
5
  { name="dontinelli", email="73341522+dontinelli@users.noreply.github.com" },
6
6
  ]
@@ -26,15 +26,17 @@ class Client:
26
26
 
27
27
  # pylint: disable=too-many-positional-arguments
28
28
 
29
- def __init__(self, host: str, password: str = "") -> None:
29
+ def __init__(self, host: str, session: ClientSession | None, password: str = "") -> None:
30
30
  self.host: str = host
31
31
  self.password: str = password
32
32
  self.token: str = ""
33
33
 
34
34
  self.request_timeout = 30
35
- self.session = ClientSession(
36
- timeout=ClientTimeout(total=self.request_timeout)
37
- )
35
+
36
+ if not session:
37
+ self.session = ClientSession()
38
+ else:
39
+ self.session = session
38
40
 
39
41
  self._close_session: bool = True
40
42
 
@@ -42,14 +44,15 @@ class Client:
42
44
  async def test_connection(self) -> bool:
43
45
  """Test the connection to Solar-Log."""
44
46
  if self.session is None:
45
- self.session = ClientSession(
46
- timeout=ClientTimeout(total=self.request_timeout)
47
- )
47
+ self.session = ClientSession()
48
48
  self._close_session = True
49
49
 
50
50
  url = f"{self.host}/getjp"
51
51
 
52
- response = await self.session.post(url, json=SOLARLOG_REQUEST_PAYLOAD)
52
+ response = await self.session.post(
53
+ url, json=SOLARLOG_REQUEST_PAYLOAD,
54
+ timeout=ClientTimeout(total=self.request_timeout)
55
+ )
53
56
 
54
57
  if response.status == 200:
55
58
  return True
@@ -85,9 +88,7 @@ class Client:
85
88
  async def execute_http_request(self, body: str, path: str = "getjp") -> ClientResponse:
86
89
  """Helper function to process the HTTP Get call."""
87
90
  if self.session is None:
88
- self.session = ClientSession(
89
- timeout=ClientTimeout(total=self.request_timeout)
90
- )
91
+ self.session = ClientSession()
91
92
  self._close_session = True
92
93
 
93
94
  url = f"{self.host}/{path}"
@@ -105,6 +106,7 @@ class Client:
105
106
  url=url,
106
107
  headers=header,
107
108
  data=body,
109
+ timeout=ClientTimeout(total=self.request_timeout),
108
110
  )
109
111
  except asyncio.TimeoutError as exception:
110
112
  msg = f"Timeout occurred while connecting to Solar-Log at {self.host}"
@@ -177,6 +179,17 @@ class Client:
177
179
 
178
180
  return data
179
181
 
182
+ async def get_battery_data(self) -> list[float]:
183
+ """Get power data from Solar-Log"""
184
+
185
+ raw_data: dict = await self.parse_http_response(
186
+ await self.execute_http_request('{ "858": null }')
187
+ )
188
+
189
+ data: list[float] = raw_data["858"]
190
+
191
+ return data
192
+
180
193
  async def get_power_per_inverter(self) -> dict[int, float]:
181
194
  """Get power data from Solar-Log"""
182
195
 
@@ -4,13 +4,15 @@ from datetime import timezone, tzinfo
4
4
  import logging
5
5
  from zoneinfo import ZoneInfo
6
6
 
7
+ from aiohttp import ClientSession
8
+
7
9
  from .solarlog_client import Client
8
10
  from .solarlog_exceptions import(
9
11
  SolarLogAuthenticationError,
10
12
  SolarLogConnectionError,
11
13
  SolarLogUpdateError,
12
14
  )
13
- from .solarlog_models import SolarlogData, InverterData
15
+ from .solarlog_models import BatteryData, InverterData, SolarlogData
14
16
 
15
17
  _LOGGER = logging.getLogger(__name__)
16
18
 
@@ -28,8 +30,9 @@ class SolarLogConnector:
28
30
  tz: str = "",
29
31
  device_enabled: dict[int, bool] | None = None,
30
32
  password: str = "",
33
+ session: ClientSession | None = None,
31
34
  ):
32
- self.client = Client(host, password)
35
+ self.client = Client(host, session, password)
33
36
  self.extended_data: bool = extended_data
34
37
 
35
38
  self._device_list: dict[int, InverterData] = {}
@@ -92,6 +95,8 @@ class SolarLogConnector:
92
95
  if self._device_list != {}:
93
96
  data.inverter_data = await self.update_inverter_data()
94
97
 
98
+ data.battery_data = await self.update_battery_data()
99
+
95
100
  _LOGGER.debug("Extended data updated: %s",data)
96
101
 
97
102
  #calculated values (for downward compatibility)
@@ -109,6 +114,26 @@ class SolarLogConnector:
109
114
 
110
115
  return data
111
116
 
117
+
118
+ async def update_battery_data(self) -> BatteryData | None:
119
+ """Update device specific data."""
120
+
121
+ raw_data = await self.client.get_battery_data()
122
+
123
+ if raw_data == []:
124
+ return None
125
+
126
+ battery_data = BatteryData(
127
+ voltage=raw_data[0],
128
+ level=raw_data[1],
129
+ charge_power=raw_data[2],
130
+ discharge_power=raw_data[3],
131
+ )
132
+
133
+ _LOGGER.debug("Battery data updated: %s",battery_data)
134
+
135
+ return battery_data
136
+
112
137
  async def update_device_list(self) -> dict[int, InverterData]:
113
138
  """Update list of devices."""
114
139
  if not self.extended_data:
@@ -4,6 +4,16 @@ from datetime import datetime
4
4
 
5
5
  from mashumaro import DataClassDictMixin
6
6
 
7
+ @dataclass
8
+ class BatteryData():
9
+ """Battery Data model."""
10
+
11
+ charge_power: float = 0
12
+ discharge_power: float = 0
13
+ level: float = 0
14
+ voltage: float = 0
15
+
16
+
7
17
  @dataclass
8
18
  class InverterData():
9
19
  """Inverter Data model."""
@@ -46,6 +56,7 @@ class SolarlogData(DataClassDictMixin):
46
56
  usage: float | None = None
47
57
 
48
58
  #extended data
59
+ battery_data: BatteryData | None = None
49
60
  inverter_data: dict[int, InverterData] = field(default_factory=dict)
50
61
  production_year: float | None = None
51
62
  self_consumption_year: float | None = None
@@ -2,6 +2,12 @@
2
2
  # name: test_update_data[asyncio]
3
3
  dict({
4
4
  'alternator_loss': 100,
5
+ 'battery_data': dict({
6
+ 'charge_power': 1074,
7
+ 'discharge_power': 0,
8
+ 'level': 79,
9
+ 'voltage': 0,
10
+ }),
5
11
  'capacity': 27.901119402985074,
6
12
  'consumption_ac': 3110,
7
13
  'consumption_day': 47819,
@@ -0,0 +1,3 @@
1
+ {
2
+ "858": [0,79,1074,0]
3
+ }
@@ -1,6 +1,7 @@
1
1
  """Tests for solarlog_cli."""
2
2
 
3
3
  from aioresponses import aioresponses
4
+ from aiohttp import ClientSession
4
5
 
5
6
  import pytest
6
7
  from syrupy.assertion import SnapshotAssertion
@@ -48,6 +49,26 @@ async def test_connection(
48
49
  assert solarlog_connector.client.session.closed
49
50
 
50
51
 
52
+ async def test_existing_session(
53
+ responses: aioresponses,
54
+ ) -> None:
55
+ """Test connection."""
56
+ responses.post(
57
+ "localhost/getjp",
58
+ status=200,
59
+ )
60
+
61
+ solarlog_connector = SolarLogConnector("localhost", session=ClientSession())
62
+
63
+ assert await solarlog_connector.test_connection()
64
+
65
+ assert solarlog_connector.host == "localhost"
66
+
67
+ assert solarlog_connector.client.session is not None
68
+ assert not solarlog_connector.client.session.closed
69
+ await solarlog_connector.client.close()
70
+ assert solarlog_connector.client.session.closed
71
+
51
72
  async def test_extended_data_available(
52
73
  responses: aioresponses,
53
74
  ) -> None:
@@ -155,6 +176,10 @@ async def test_update_data(
155
176
  "http://solarlog.com/getjp",
156
177
  body=load_fixture("energy_per_inverter.json"),
157
178
  )
179
+ responses.post(
180
+ "http://solarlog.com/getjp",
181
+ body=load_fixture("battery_data.json"),
182
+ )
158
183
 
159
184
  solarlog_connector = SolarLogConnector(
160
185
  "http://solarlog.com",
@@ -170,6 +195,44 @@ async def test_update_data(
170
195
  await solarlog_connector.client.close()
171
196
  assert solarlog_connector.client.session.closed
172
197
 
198
+ async def test_update_data_without_battery(
199
+ responses: aioresponses,
200
+ ) -> None:
201
+ """Test update data."""
202
+ responses.post(
203
+ "http://solarlog.com/getjp",
204
+ body=load_fixture("basic_data.json"),
205
+ )
206
+ responses.post(
207
+ "http://solarlog.com/getjp",
208
+ body=load_fixture("extended_data.json"),
209
+ )
210
+ responses.post(
211
+ "http://solarlog.com/getjp",
212
+ body=load_fixture("power_per_inverter.json"),
213
+ )
214
+ responses.post(
215
+ "http://solarlog.com/getjp",
216
+ body=load_fixture("energy_per_inverter.json"),
217
+ )
218
+ responses.post(
219
+ "http://solarlog.com/getjp",
220
+ body=load_fixture("battery_data_without_battery.json"),
221
+ )
222
+
223
+ solarlog_connector = SolarLogConnector(
224
+ "http://solarlog.com",
225
+ True,
226
+ "UTC",
227
+ {0: True, 1: True, 2: False, 3: True},
228
+ )
229
+
230
+ data = await solarlog_connector.update_data()
231
+
232
+ assert data.battery_data is None
233
+
234
+ await solarlog_connector.client.close()
235
+ assert solarlog_connector.client.session.closed
173
236
 
174
237
  @pytest.mark.parametrize(
175
238
  ("status", "request_timeout", "error"),
File without changes
File without changes
File without changes
File without changes