solarlog-cli 0.1.6__tar.gz → 0.2.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.2.0/.coverage +0 -0
  2. solarlog_cli-0.2.0/.devcontainer/devcontainer.json +44 -0
  3. solarlog_cli-0.2.0/.github/workflows/pylint.yml +27 -0
  4. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/.github/workflows/ruff.yml +8 -11
  5. solarlog_cli-0.2.0/.github/workflows/tests.yml +70 -0
  6. solarlog_cli-0.2.0/.github/workflows/typing.yml +33 -0
  7. solarlog_cli-0.2.0/.gitignore +6 -0
  8. solarlog_cli-0.2.0/.vscode/settings.json +6 -0
  9. solarlog_cli-0.2.0/.vscode/tasks.json +78 -0
  10. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/PKG-INFO +2 -1
  11. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/pyproject.toml +2 -1
  12. solarlog_cli-0.2.0/pytest.ini +2 -0
  13. solarlog_cli-0.2.0/requirements.txt +6 -0
  14. solarlog_cli-0.2.0/src/solarlog_cli/py.typed +0 -0
  15. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/src/solarlog_cli/solarlog_client.py +35 -38
  16. solarlog_cli-0.2.0/src/solarlog_cli/solarlog_connector.py +142 -0
  17. solarlog_cli-0.2.0/src/solarlog_cli/solarlog_models.py +52 -0
  18. solarlog_cli-0.2.0/tests/__init__.py +9 -0
  19. solarlog_cli-0.2.0/tests/__snapshots__/test_solarlog_cli.ambr +83 -0
  20. solarlog_cli-0.2.0/tests/conftest.py +22 -0
  21. solarlog_cli-0.2.0/tests/fixtures/basic_data.json +23 -0
  22. solarlog_cli-0.2.0/tests/fixtures/basic_data_during_update.json +23 -0
  23. solarlog_cli-0.2.0/tests/fixtures/basic_data_no_power.json +23 -0
  24. solarlog_cli-0.2.0/tests/fixtures/device_data_1.json +7 -0
  25. solarlog_cli-0.2.0/tests/fixtures/device_data_2.json +7 -0
  26. solarlog_cli-0.2.0/tests/fixtures/device_data_3.json +7 -0
  27. solarlog_cli-0.2.0/tests/fixtures/device_data_4.json +7 -0
  28. solarlog_cli-0.2.0/tests/fixtures/device_list.json +9 -0
  29. solarlog_cli-0.2.0/tests/fixtures/energy_per_inverter.json +9 -0
  30. solarlog_cli-0.2.0/tests/fixtures/extended_data.json +9 -0
  31. solarlog_cli-0.2.0/tests/fixtures/power_per_inverter.json +8 -0
  32. solarlog_cli-0.2.0/tests/ruff.toml +15 -0
  33. solarlog_cli-0.2.0/tests/syrupy.py +67 -0
  34. solarlog_cli-0.2.0/tests/test_solarlog_cli.py +219 -0
  35. solarlog_cli-0.1.6/.github/workflows/pylint.yml +0 -24
  36. solarlog_cli-0.1.6/.gitignore +0 -1
  37. solarlog_cli-0.1.6/requirements.txt +0 -1
  38. solarlog_cli-0.1.6/src/solarlog_cli/solarlog_connector.py +0 -129
  39. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/.github/workflows/python-publish.yml +0 -0
  40. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/LICENSE +0 -0
  41. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/README.md +0 -0
  42. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/src/solarlog_cli/__init__.py +0 -0
  43. {solarlog_cli-0.1.6 → solarlog_cli-0.2.0}/src/solarlog_cli/solarlog_exceptions.py +0 -0
Binary file
@@ -0,0 +1,44 @@
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/docker-in-docker
3
+ {
4
+ "name": "Docker in Docker",
5
+ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6
+ "image": "mcr.microsoft.com/devcontainers/base:bullseye",
7
+
8
+ "features": {
9
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {
10
+ "moby": true,
11
+ "azureDnsAutoDetection": true,
12
+ "installDockerBuildx": true,
13
+ "installDockerComposeSwitch": true,
14
+ "version": "latest"
15
+ },
16
+ "ghcr.io/devcontainers/features/github-cli:1": {
17
+ "installDirectlyFromGitHubRelease": true,
18
+ "version": "latest"
19
+ },
20
+ "ghcr.io/devcontainers/features/python:1": {
21
+ "installTools": true,
22
+ "version": "latest"
23
+ },
24
+ "ghcr.io/devcontainers-community/npm-features/prettier:1": {
25
+ "version": "latest"
26
+ },
27
+ "ghcr.io/hspaans/devcontainer-features/pytest:1": {
28
+ "version": "latest",
29
+ "plugins": "pytest-testinfra"
30
+ }
31
+ }
32
+
33
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
34
+ // "forwardPorts": [],
35
+
36
+ // Use 'postCreateCommand' to run commands after the container is created.
37
+ // "postCreateCommand": "docker --version",
38
+
39
+ // Configure tool-specific properties.
40
+ // "customizations": {},
41
+
42
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
43
+ // "remoteUser": "root"
44
+ }
@@ -0,0 +1,27 @@
1
+ name: Pylint
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ matrix:
10
+ python-version: ["3.12"]
11
+ steps:
12
+ - name: ⤵️ Checkout the repository
13
+ uses: actions/checkout@v4.1.7
14
+ - name: 🏗 Set up Python ${{ matrix.python-version }}
15
+ uses: actions/setup-python@v5.0.0
16
+ with:
17
+ python-version: ${{ matrix.python-version }}
18
+ cache: "pip"
19
+ - name: 🏗 Install requirement
20
+ run: |
21
+ python -m pip install --upgrade pip
22
+ pip install -r requirements.txt
23
+ - name: 🏗 Install pylint
24
+ run: python3 -m pip install pylint
25
+ - name: 🚀 Analysing the code with pylint
26
+ run: |
27
+ pylint $(git ls-files '*.py')
@@ -13,19 +13,16 @@ jobs:
13
13
  name: "Ruff"
14
14
  runs-on: "ubuntu-latest"
15
15
  steps:
16
- - name: "Checkout the repository"
17
- uses: "actions/checkout@v4.1.1"
18
-
19
- - name: "Set up Python"
16
+ - name: ⤵️ Checkout the repository
17
+ uses: actions/checkout@v4.1.7
18
+ - name: 🏗 Set up Python
20
19
  uses: actions/setup-python@v5.0.0
21
20
  with:
22
21
  python-version: "3.12"
23
22
  cache: "pip"
24
-
25
- - name: "Install requirements"
23
+ - name: 🏗 Install requirements
26
24
  run: python3 -m pip install -r requirements.txt
27
-
28
- - name: "Run"
29
- run: |
30
- python3 -m pip install ruff
31
- python3 -m ruff check ./src/solarlog_cli/*
25
+ - name: 🏗 Install ruff
26
+ run: python3 -m pip install ruff
27
+ - name: 🚀 Run
28
+ run: python3 -m ruff check ./src/solarlog_cli/*
@@ -0,0 +1,70 @@
1
+ name: Testing
2
+
3
+ # yamllint disable-line rule:truthy
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ pull_request:
9
+ workflow_dispatch:
10
+
11
+ env:
12
+ DEFAULT_PYTHON: "3.12"
13
+
14
+ jobs:
15
+ pytest:
16
+ name: Python ${{ matrix.python }}
17
+ runs-on: ubuntu-latest
18
+ strategy:
19
+ matrix:
20
+ python: ["3.12"]
21
+ steps:
22
+ - name: ⤵️ Check out code from GitHub
23
+ uses: actions/checkout@v4.1.7
24
+ - name: 🏗 Set up Python ${{ matrix.python }}
25
+ id: python
26
+ uses: actions/setup-python@v5.1.1
27
+ with:
28
+ python-version: ${{ matrix.python }}
29
+ cache: "pip"
30
+ - name: 🏗 Install dependencies
31
+ run: python3 -m pip install -r requirements.txt
32
+ - name: 🏗 Install pytest
33
+ run: python3 -m pip install pytest pytest-cov pytest-aio
34
+ - name: 🚀 Run pytest
35
+ run: pytest --cov src tests
36
+ - name: ⬆️ Upload coverage artifact
37
+ uses: actions/upload-artifact@v4.3.6
38
+ with:
39
+ name: coverage-${{ matrix.python }}
40
+ path: .coverage
41
+
42
+ coverage:
43
+ runs-on: ubuntu-latest
44
+ needs: pytest
45
+ steps:
46
+ - name: ⤵️ Check out code from GitHub
47
+ uses: actions/checkout@v4.1.7
48
+ with:
49
+ fetch-depth: 0
50
+ - name: ⬇️ Download coverage data
51
+ uses: actions/download-artifact@v4.1.8
52
+ - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
53
+ id: python
54
+ uses: actions/setup-python@v5.1.1
55
+ with:
56
+ python-version: ${{ env.DEFAULT_PYTHON }}
57
+ cache: "pip"
58
+ - name: 🏗 Install dependencies
59
+ run: python3 -m pip install -r requirements.txt
60
+ - name: 🏗 Install coverage
61
+ run: python3 -m pip install coverage
62
+ - name: 🚀 Process coverage results
63
+ run: |
64
+ coverage combine coverage*/.coverage*
65
+ coverage xml -i
66
+ - name: 🚀 Upload coverage report
67
+ uses: codecov/codecov-action@v4.5.0
68
+ with:
69
+ fail_ci_if_error: true
70
+ token: ${{ secrets.CODECOV_TOKEN }}
@@ -0,0 +1,33 @@
1
+ name: Typing
2
+
3
+ # yamllint disable-line rule:truthy
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ pull_request:
9
+ branches:
10
+ - main
11
+
12
+ env:
13
+ DEFAULT_PYTHON: "3.12"
14
+
15
+ jobs:
16
+ mypy:
17
+ name: mypy
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - name: ⤵️ Check out code from GitHub
21
+ uses: actions/checkout@v4.1.7
22
+ - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
23
+ id: python
24
+ uses: actions/setup-python@v5.1.1
25
+ with:
26
+ python-version: ${{ env.DEFAULT_PYTHON }}
27
+ cache: "pip"
28
+ - name: 🏗 Install dependencies
29
+ run: python3 -m pip install -r requirements.txt
30
+ - name: 🏗 Install mypy
31
+ run: python3 -m pip install mypy
32
+ - name: 🚀 Run mypy
33
+ run: MYPYPATH=src mypy --namespace-packages --explicit-package-bases src tests
@@ -0,0 +1,6 @@
1
+ src/solarlog_cli/__pycache__
2
+ tests/__pycache__
3
+ .mypy_cache
4
+ .pytest_cache
5
+ .gitignore
6
+ .venv
@@ -0,0 +1,6 @@
1
+ {
2
+ "python.analysis.extraPaths": [
3
+ "./src/solarlog_cli"
4
+ ],
5
+ "python.analysis.typeCheckingMode": "basic"
6
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "tasks": [
4
+ {
5
+ "label": "Pytest",
6
+ "type": "shell",
7
+ "command": "pytest tests",
8
+ "dependsOn": ["Install all Requirements"],
9
+ "group": {
10
+ "kind": "test",
11
+ "isDefault": true
12
+ },
13
+ "presentation": {
14
+ "reveal": "always",
15
+ "panel": "new"
16
+ },
17
+ "problemMatcher": []
18
+ },
19
+ {
20
+ "label": "Ruff",
21
+ "type": "shell",
22
+ "command": "ruff check src/solarlog_cli tests",
23
+ "group": {
24
+ "kind": "test",
25
+ "isDefault": true
26
+ },
27
+ "presentation": {
28
+ "reveal": "always",
29
+ "panel": "new"
30
+ },
31
+ "problemMatcher": []
32
+ },
33
+ {
34
+ "label": "Pylint",
35
+ "type": "shell",
36
+ "command": "pylint src tests",
37
+ "dependsOn": ["Install all Requirements"],
38
+ "group": {
39
+ "kind": "test",
40
+ "isDefault": true
41
+ },
42
+ "presentation": {
43
+ "reveal": "always",
44
+ "panel": "new"
45
+ },
46
+ "problemMatcher": []
47
+ },
48
+ {
49
+ "label": "Code Coverage",
50
+ "detail": "Generate code coverage report.",
51
+ "type": "shell",
52
+ "command": "pytest tests --cov=solarlog_cli --cov-report term-missing --durations-min=1 --durations=0",
53
+ "group": {
54
+ "kind": "test",
55
+ "isDefault": true
56
+ },
57
+ "presentation": {
58
+ "reveal": "always",
59
+ "panel": "new"
60
+ },
61
+ "problemMatcher": []
62
+ },
63
+ {
64
+ "label": "Install all Requirements",
65
+ "type": "shell",
66
+ "command": "pip install -r requirements.txt",
67
+ "group": {
68
+ "kind": "build",
69
+ "isDefault": true
70
+ },
71
+ "presentation": {
72
+ "reveal": "always",
73
+ "panel": "new"
74
+ },
75
+ "problemMatcher": []
76
+ }
77
+ ]
78
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: solarlog_cli
3
- Version: 0.1.6
3
+ Version: 0.2.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
@@ -15,6 +15,7 @@ Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python :: 3
16
16
  Requires-Python: >=3.12
17
17
  Requires-Dist: aiohttp
18
+ Requires-Dist: mashumaro>=3.13
18
19
  Description-Content-Type: text/markdown
19
20
 
20
21
  # Solar-Log-Cli
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "solarlog_cli"
3
- version = "0.1.6"
3
+ version = "0.2.0"
4
4
  authors = [
5
5
  { name="dontinelli", email="73341522+dontinelli@users.noreply.github.com" },
6
6
  ]
@@ -9,6 +9,7 @@ readme = "README.md"
9
9
  requires-python = ">=3.12"
10
10
  dependencies = [
11
11
  "aiohttp",
12
+ "mashumaro>=3.13",
12
13
  ]
13
14
  classifiers = [
14
15
  "Programming Language :: Python :: 3",
@@ -0,0 +1,2 @@
1
+ [pytest]
2
+ pythonpath = src
@@ -0,0 +1,6 @@
1
+ aiohttp>=3.9.5
2
+ aioresponses == 0.7.6
3
+ mashumaro>=3.13
4
+ pytest-aio==1.9.0
5
+ pytest-cov==5.0.0
6
+ syrupy == 4.6.1
File without changes
@@ -5,17 +5,15 @@ from __future__ import annotations
5
5
  import asyncio
6
6
  from datetime import datetime
7
7
  import json
8
- import logging
9
8
  from typing import Any
10
9
 
11
- from aiohttp import ClientSession
10
+ from aiohttp import ClientSession, ClientTimeout
12
11
 
13
12
  from .solarlog_exceptions import SolarLogConnectionError, SolarLogUpdateError
13
+ from .solarlog_models import SolarlogData
14
14
 
15
15
  SOLARLOG_REQUEST_PAYLOAD = {801: {170: None}}
16
16
 
17
- _LOGGER = logging.getLogger(__name__)
18
-
19
17
 
20
18
  class Client:
21
19
  """Client class to access Solar-Log."""
@@ -53,10 +51,12 @@ class Client:
53
51
  }
54
52
 
55
53
  try:
56
- async with asyncio.timeout(self.request_timeout):
57
- response = await self.session.post(
58
- url=url, headers=header, json=json_payload
59
- )
54
+ response = await self.session.post(
55
+ url=url,
56
+ headers=header,
57
+ json=json_payload,
58
+ timeout=ClientTimeout(total=self.request_timeout)
59
+ )
60
60
  except asyncio.TimeoutError as exception:
61
61
  msg = f"Timeout occurred while connecting to Solar-Log at {self.host}"
62
62
  raise SolarLogConnectionError(msg) from exception
@@ -85,31 +85,31 @@ class Client:
85
85
 
86
86
  return json_response
87
87
 
88
- async def get_basic_data(self) -> dict[str, int | float | datetime]:
88
+ async def get_basic_data(self) -> SolarlogData:
89
89
  """Get basic data from Solar-Log."""
90
90
 
91
91
  raw_data: dict = await self.execute_http_request({801: {170: None}})
92
92
  raw_data = raw_data["801"]["170"]
93
93
 
94
- data = {
95
- "last_updated": datetime.strptime(raw_data["100"], "%d.%m.%y %H:%M:%S"),
96
- "power_ac": raw_data["101"],
97
- "power_dc": raw_data["102"],
98
- "voltage_ac": raw_data["103"],
99
- "voltage_dc": raw_data["104"],
100
- "yield_day": raw_data["105"],
101
- "yield_yesterday": raw_data["106"],
102
- "yield_month": raw_data["107"],
103
- "yield_year": raw_data["108"],
104
- "yield_total": raw_data["109"],
105
- "consumption_ac": raw_data["110"],
106
- "consumption_day": raw_data["111"],
107
- "consumption_yesterday": raw_data["112"],
108
- "consumption_month": raw_data["113"],
109
- "consumption_year": raw_data["114"],
110
- "consumption_total": raw_data["115"],
111
- "total_power": raw_data["116"],
112
- }
94
+ data = SolarlogData(
95
+ last_updated = datetime.strptime(raw_data["100"], "%d.%m.%y %H:%M:%S"),
96
+ power_ac = raw_data["101"],
97
+ power_dc = raw_data["102"],
98
+ voltage_ac = raw_data["103"],
99
+ voltage_dc = raw_data["104"],
100
+ yield_day = raw_data["105"],
101
+ yield_yesterday = raw_data["106"],
102
+ yield_month = raw_data["107"],
103
+ yield_year = raw_data["108"],
104
+ yield_total = raw_data["109"],
105
+ consumption_ac = raw_data["110"],
106
+ consumption_day = raw_data["111"],
107
+ consumption_yesterday = raw_data["112"],
108
+ consumption_month = raw_data["113"],
109
+ consumption_year = raw_data["114"],
110
+ consumption_total = raw_data["115"],
111
+ total_power = raw_data["116"],
112
+ )
113
113
 
114
114
  return data
115
115
 
@@ -128,7 +128,7 @@ class Client:
128
128
  raw_data: dict = await self.execute_http_request({854: None})
129
129
  data_list = raw_data["854"][-1][-1]
130
130
 
131
- data = {}
131
+ data: dict[int, float] = {}
132
132
 
133
133
  for item in data_list:
134
134
  if item != 0:
@@ -136,33 +136,30 @@ class Client:
136
136
 
137
137
  return data
138
138
 
139
- async def get_energy(self) -> dict[str, float]:
139
+ async def get_energy(self, data: SolarlogData) -> SolarlogData:
140
140
  """Get power data from Solar-Log"""
141
141
 
142
142
  raw_data: dict = await self.execute_http_request({878: None})
143
143
 
144
- data = {
145
- "production_year": raw_data["878"][-1][1],
146
- # "consumption_year": raw_data["878"][-1][2], # already in basic data
147
- "self_consumption_year": raw_data["878"][-1][3],
148
- }
144
+ data.production_year = raw_data["878"][-1][1]
145
+ data.self_consumption_year = raw_data["878"][-1][3]
149
146
 
150
147
  return data
151
148
 
152
- async def get_device_list(self) -> dict[int, dict[str, str]]:
149
+ async def get_device_list(self) -> dict[int, str]:
153
150
  """Get list of all connected devices."""
154
151
 
155
152
  # get list of all inverters connected to Solar-Log
156
153
  raw_data: dict = await self.execute_http_request({740: None})
157
154
  raw_data = raw_data["740"]
158
155
 
159
- device_list: dict[int, dict[str, str]] = {}
156
+ device_list: dict[int, str] = {}
160
157
 
161
158
  for key, value in raw_data.items():
162
159
  if value != "Err":
163
160
  # get name of the inverter
164
161
  raw_data = await self.execute_http_request({141: {key: {119: None}}})
165
- device_list |= {int(key): {"name": raw_data["141"][key]["119"]}}
162
+ device_list |= {int(key): raw_data["141"][key]["119"]}
166
163
 
167
164
  return device_list
168
165
 
@@ -0,0 +1,142 @@
1
+ """Connector class to manage access to Solar-Log."""
2
+
3
+ from datetime import timezone, tzinfo
4
+ import logging
5
+ from zoneinfo import ZoneInfo
6
+
7
+ from .solarlog_client import Client
8
+ from .solarlog_exceptions import SolarLogUpdateError
9
+ from .solarlog_models import SolarlogData, InverterData
10
+
11
+ _LOGGER = logging.getLogger(__name__)
12
+
13
+
14
+ class SolarLogConnector:
15
+ """Connector class to access Solar-Log."""
16
+
17
+ def __init__( # pylint: disable=dangerous-default-value
18
+ self,
19
+ host: str,
20
+ extended_data: bool = False,
21
+ tz: str = "",
22
+ device_enabled: dict[int, bool] = {},
23
+ ):
24
+ self.client = Client(host)
25
+ self.extended_data: bool = extended_data
26
+
27
+ self._device_list: dict[int, InverterData] = {}
28
+ if device_enabled != {}:
29
+ for key, value in device_enabled.items():
30
+ self._device_list |= {key: InverterData(enabled=value)}
31
+
32
+ self.timezone: tzinfo = timezone.utc if tz == "" else ZoneInfo(tz)
33
+
34
+ async def test_connection(self) -> bool:
35
+ """Test if connection to Solar-Log works."""
36
+
37
+ return await self.client.test_connection()
38
+
39
+ async def update_data(self) -> SolarlogData:
40
+ """Get data from Solar-Log."""
41
+
42
+ data: SolarlogData = await self.client.get_basic_data()
43
+
44
+ if data.last_updated.year == 1999:
45
+ raise SolarLogUpdateError(
46
+ "Invalid data returned (can happen after Solarlog restart)."
47
+ )
48
+
49
+ data.last_updated = data.last_updated.replace(tzinfo=self.timezone)
50
+
51
+ _LOGGER.debug("Basic data updated: %s",data)
52
+ if self.extended_data:
53
+ data = await self.client.get_energy(data)
54
+
55
+ if self._device_list != {}:
56
+ data.inverter_data = await self.update_inverter_data()
57
+
58
+ _LOGGER.debug("Extended data updated: %s",data)
59
+
60
+ #calculated values (for downward compatibility)
61
+ data.alternator_loss = data.power_dc - data.power_ac
62
+ if data.power_dc != 0:
63
+ data.efficiency = data.power_ac / data.power_dc
64
+ if data.power_ac != 0:
65
+ data.usage = data.consumption_ac / data.power_ac
66
+ data.power_available = data.power_ac - data.consumption_ac
67
+ else:
68
+ data.usage = 0.0
69
+ data.power_available = 0.0
70
+ if data.total_power != 0:
71
+ data.capacity = data.power_dc / data.total_power
72
+
73
+ return data
74
+
75
+ async def update_device_list(self) -> dict[int, InverterData]:
76
+ """Update list of devices."""
77
+ if not self.extended_data or self._device_list is None:
78
+ return {}
79
+
80
+ devices = await self.client.get_device_list()
81
+
82
+ self._device_list = {
83
+ key: InverterData(name=value,enabled=self.device(key).enabled)
84
+ for key, value in devices.items()
85
+ }
86
+ _LOGGER.debug("Device list: %s",self._device_list)
87
+
88
+ return self._device_list
89
+
90
+ async def update_inverter_data(self) -> dict[int, InverterData]:
91
+ """Update device specific data."""
92
+
93
+ raw_data = await self.client.get_power_per_inverter()
94
+ for key, value in raw_data.items():
95
+ key = int(key)
96
+ if self._device_list.get(key,InverterData).enabled:
97
+ self._device_list[key].current_power = float(value)
98
+
99
+ raw_data = await self.client.get_energy_per_inverter()
100
+ for key, value in raw_data.items():
101
+ if self._device_list.get(key,InverterData).enabled:
102
+ self._device_list[key].consumption_year = float(value)
103
+
104
+ _LOGGER.debug("Inverter data updated: %s",self._device_list)
105
+
106
+ return self._device_list
107
+
108
+ @property
109
+ def host(self) -> str:
110
+ """Host of Solar-Log."""
111
+ return self.client.host
112
+
113
+ @property
114
+ def device_list(self) -> dict[int, InverterData]:
115
+ """List of all devices of Solar-Log."""
116
+ return self._device_list
117
+
118
+ def device(self, device_id: int) -> InverterData:
119
+ """Get device data."""
120
+ return self._device_list.get(device_id, InverterData())
121
+
122
+ def device_name(self, device_id: int) -> str:
123
+ """Get name of Solar-Log attached device."""
124
+ _LOGGER.debug("Device list: %s; id: %s",self._device_list, device_id)
125
+
126
+ return self._device_list.get(device_id, InverterData()).name
127
+
128
+ def device_enabled(self, device_id: int | None = None) -> bool | dict[int, bool]:
129
+ """Get if device is enabled (if id is provided) or list of all devices."""
130
+ if device_id is None:
131
+ print("no device_id")
132
+ print(self._device_list)
133
+ return {key: value.enabled for key, value in self._device_list.items()}
134
+ return self._device_list[device_id].enabled
135
+
136
+ def set_enabled_devices(self, device_enabled: dict[int, bool]) -> None:
137
+ """Set enabled devices."""
138
+ for key, value in device_enabled.items():
139
+ if self._device_list.get(key) is None:
140
+ self._device_list |= {key: InverterData(enabled=value)}
141
+ else:
142
+ self._device_list[key].enabled = value
@@ -0,0 +1,52 @@
1
+ """Models for SolarLog."""
2
+ from dataclasses import dataclass
3
+ from datetime import datetime
4
+
5
+ from mashumaro import DataClassDictMixin
6
+
7
+
8
+ @dataclass
9
+ class InverterData():
10
+ """Inverter Data model."""
11
+
12
+ name: str = ""
13
+ enabled: bool = False
14
+ current_power: float | None = None
15
+ consumption_year: float | None = None
16
+
17
+
18
+ @dataclass
19
+ class SolarlogData(DataClassDictMixin):
20
+ """Basic Data model."""
21
+
22
+ # pylint: disable=too-many-instance-attributes
23
+
24
+ consumption_ac: float
25
+ consumption_day: float
26
+ consumption_month: float
27
+ consumption_total: float
28
+ consumption_yesterday: float
29
+ consumption_year: float
30
+ last_updated: datetime
31
+ power_ac: float
32
+ power_dc: float
33
+ total_power: float
34
+ voltage_ac: float
35
+ voltage_dc: float
36
+ yield_day: float
37
+ yield_yesterday: float
38
+ yield_month: float
39
+ yield_year: float
40
+ yield_total: float
41
+
42
+ #calculated values
43
+ alternator_loss: float | None = None
44
+ capacity: float | None = None
45
+ efficiency: float | None = None
46
+ power_available: float | None = None
47
+ usage: float | None = None
48
+
49
+ #extended data
50
+ inverter_data: dict[int, InverterData] | None = None
51
+ production_year: float | None = None
52
+ self_consumption_year: float | None = None