Skip to content

Commit f8c1b2d

Browse files
authored
22 add higher level entities (#23)
* Proper python module * New higher level types * Fix names * Fix names * Fix names * Fix names * Fix names * Add and improve helpers * Improve example code * Pretty * Bump major version * Create example_entities.py * Update minor version * Ignore complexity error for now
1 parent f5051f4 commit f8c1b2d

14 files changed

Lines changed: 2250 additions & 1038 deletions

‎.github/workflows/python-app.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
3535
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
3636
# --exit-zero removed to enforce zero lint errors
37-
flake8 . --extend-ignore=E128,E124,F403,F405 --count --max-complexity=10 --max-line-length=127 --statistics
37+
flake8 . --extend-ignore=C901,E128,E124,F403,F405 --count --max-complexity=10 --max-line-length=127 --statistics
3838
- name: Test with pytest
3939
run: |
4040
pytest --capture=tee-sys -v

‎example.py‎

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
"""Example application."""
1+
"""
2+
Example application.
3+
Demonstrates usage of the SoliscloudAPI class to interact with the Soliscloud
4+
API. It also shows how to use the Helpers class for common tasks.
5+
Fill in your own API key and secret in config.json before running.
6+
"""
7+
28
import asyncio
39
import logging
410
import json
511

612
from aiohttp import ClientSession
713

8-
from soliscloud_api import SoliscloudAPI
9-
from soliscloud_api.helpers import Helpers
14+
from soliscloud_api import SoliscloudAPI, SoliscloudError, \
15+
SoliscloudHttpError, SoliscloudTimeoutError, SoliscloudApiError, \
16+
Helpers
1017

1118

1219
logging.basicConfig(level=logging.DEBUG)
@@ -29,52 +36,54 @@ async def main():
2936
soliscloud = SoliscloudAPI(
3037
'https://soliscloud.com:13333', websession)
3138

32-
# Retrieves list of Stations, a.k.a. plants,
33-
# containing the inverters.
39+
# Retrieve list of Stations, a.k.a. plants
3440
station_list = await soliscloud.user_station_list(
35-
api_key, api_secret, page_no=1, page_size=100)
36-
# Australian accounts require nmi, uncomment if required.
37-
# (NOT TESTED!)
38-
# station_list = await soliscloud.user_station_list(
39-
# api_key, api_secret, page_no=1,
40-
# page_size=100, nmi_code=api_nmi)
41+
api_key, api_secret, page_no=1, page_size=100,
42+
# Australian accounts require nmi, uncomment if required.
43+
# (NOT TESTED!)
44+
# nmi_code=api_nmi
45+
)
4146
station_list_json = json.dumps(station_list, indent=2)
42-
# Use helper class as alternative
47+
# Use helper class as alternative to directly retrieve station id's
4348
station_ids = await Helpers.get_station_ids(
4449
soliscloud, api_key, api_secret)
4550

46-
# Get inverters for all stations
51+
# Get inverter data for all stations
4752
inverter_list = await soliscloud.inverter_list(
48-
api_key, api_secret, page_no=1, page_size=100)
49-
# Australian accounts require nmi, uncomment if required.
50-
# (NOT TESTED!)
51-
# inverter_list = await soliscloud.inverter_list(
52-
# api_key, api_secret, page_no=1,
53-
# page_size=100, nmi_code=api_nmi)
53+
api_key, api_secret, page_no=1, page_size=100,
54+
# Australian accounts require nmi, uncomment if required.
55+
# (NOT TESTED!)
56+
# nmi_code=api_nmi
57+
)
5458
inverter_list_json = json.dumps(inverter_list, indent=2)
55-
# Use helper class as alternative
56-
inverter_ids = await Helpers.get_inverter_ids(
57-
soliscloud, api_key, api_secret)
59+
# Use helper class to retrieve all inverter id's
60+
inverter_ids = Helpers.get_inverter_ids_from_response(
61+
inverter_list)
5862

59-
inverter_detail = await soliscloud.inverter_detail(
60-
api_key, api_secret, inverter_id=inverter_ids[0])
61-
inverter_detail_json = json.dumps(inverter_detail, indent=2)
63+
# Get detailed data for all inverters
64+
idl = await soliscloud.inverter_detail_list(api_key, api_secret)
65+
idl_json = json.dumps(idl, indent=2)
66+
67+
# Use serial number of first inverter to get details
68+
# (should be same as first in inverter_list)
69+
inverter_x = await soliscloud.inverter_detail(
70+
api_key, api_secret, inverter_sn=inverter_list[0]['sn'])
71+
inverter_detail_json = json.dumps(inverter_x, indent=2)
6272

6373
# Get data collectors for all stations
6474
collector_list = await soliscloud.collector_list(
65-
api_key, api_secret, page_no=1, page_size=100)
66-
# Australian accounts require nmi, uncomment if required.
67-
# (NOT TESTED!)
68-
# collector_list = await soliscloud.collector_list(
69-
# api_key, api_secret, page_no=1,
70-
# page_size=100, nmi_code=api_nmi)
75+
api_key, api_secret, page_no=1, page_size=100,
76+
# Australian accounts require nmi, uncomment if required.
77+
# (NOT TESTED!)
78+
# nmi_code=api_nmi
79+
)
7180
collector_list_json = json.dumps(collector_list, indent=2)
7281

7382
except (
74-
SoliscloudAPI.SolisCloudError,
75-
SoliscloudAPI.HttpError,
76-
SoliscloudAPI.TimeoutError,
77-
SoliscloudAPI.ApiError,
83+
SoliscloudError,
84+
SoliscloudHttpError,
85+
SoliscloudTimeoutError,
86+
SoliscloudApiError,
7887
) as error:
7988
print(f"Error: {error}")
8089
else:
@@ -88,14 +97,32 @@ async def main():
8897
print(f"{inverter_list_json}")
8998

9099
print("InverterDetails call success:")
91-
print(f"{inverter_detail_json}")
100+
print(inverter_detail_json)
101+
for key in ['iA', 'uA', 'pA', 'iB', 'uB', 'pB', 'iC', 'uC', 'pC']:
102+
print(f"{key}: {inverter_x[key]}")
92103

93104
print("Helper call success:")
94105
print(f"{inverter_ids}")
95106

96107
print("CollectorList call success:")
97108
print(f"{collector_list_json}")
98109

110+
print("InverterDetailList call success:")
111+
print(idl_json)
112+
for key in [
113+
'iAc1',
114+
'uAc1',
115+
'pA',
116+
'iB',
117+
'uB',
118+
'pB',
119+
'iC',
120+
'uC',
121+
'pC',
122+
'apparentPower'
123+
]:
124+
print(f"{key}: {idl[0][key]}")
125+
99126
loop = asyncio.new_event_loop()
100127
loop.run_until_complete(main())
101128
loop.close()

‎example_entities.py‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""
2+
Example application.
3+
Demonstrates the use of entity classes as a higher level interface to the
4+
Soliscloud API. Fill in your own API key and secret in config.json before
5+
running.
6+
By using the entity classes you can more easily access the data
7+
attributes of the plant, inverters and collectors.
8+
9+
There are 2 ways to create the entity classes:
10+
1. Use the class method 'initialize_from_data' to create entity instances
11+
from data retrieved from the API. It will create one or more entity
12+
instances from the data passed in. This method will not retrieve any data
13+
from the API, so you need to do that yourself first. It will not
14+
recursively create all entities, i.e. plants, inverters and collectors.
15+
You need to call it separately for each entity class.
16+
2. Use the class method 'initialize_from_session' to create entity instances
17+
by passing in the aiohttp session and API credentials. This method will
18+
retrieve the data from the API and create the entity instances. It
19+
will recursively create all entities, i.e. plants, inverters
20+
and collectors when called on the Plant class and inverters and collectors
21+
when called on the Inverter class.
22+
"""
23+
from __future__ import annotations
24+
25+
import asyncio
26+
import logging
27+
import json
28+
29+
from aiohttp import ClientSession
30+
31+
from soliscloud_api import SoliscloudError, SoliscloudHttpError, \
32+
SoliscloudTimeoutError, SoliscloudApiError
33+
from soliscloud_api import Plant, Inverter, Collector # noqa: F401
34+
from soliscloud_api import SoliscloudAPI as api
35+
36+
37+
logging.basicConfig(level=logging.DEBUG)
38+
39+
40+
async def main():
41+
"""Run main function."""
42+
# Put your own key and secret in the config.json file
43+
with open('config.json', 'r') as file:
44+
data = json.load(file)
45+
46+
api_key = data['key']
47+
api_secret = bytearray(data['secret'], 'utf-8')
48+
# Australian accounts require nmi, uncomment if required.
49+
# (NOT TESTED!)
50+
# api_nmi = data['nmi']
51+
52+
async with ClientSession() as websession:
53+
try:
54+
the_api = api('https://soliscloud.com:13333', websession)
55+
data = await the_api.inverter_list(
56+
api_key, api_secret, page_no=1, page_size=100)
57+
# use plant_id of your own plant here to get inverters for that plant
58+
# use inverter_id to only get one specific inverter
59+
inverters = Inverter.initialize_from_data(
60+
data, plant_id='your plant id goes here')
61+
plants = await Plant.initialize_from_session(
62+
websession, api_key, api_secret)
63+
except (
64+
SoliscloudError,
65+
SoliscloudHttpError,
66+
SoliscloudTimeoutError,
67+
SoliscloudApiError,
68+
) as error:
69+
print(f"Error: {error}")
70+
else:
71+
p = plants[0]
72+
print(f"Plant id: {p.plant_id}")
73+
print(f"Plant name: {p.data['station_name']}")
74+
print(f"Number of inverters: {len(p.inverters)}")
75+
for inv in inverters:
76+
print(f"Inverter id: {inv.inverter_id}")
77+
# The attributes if the inverter are in inv.data
78+
# If an attribute has a unit then the value is of
79+
# dimensioned type
80+
print(f"Total energy: {inv.data['etotal']}")
81+
print(f"Total energy value: {inv.data['etotal'].value}")
82+
print(f"Total energy unit: {inv.data['etotal'].unit}")
83+
loop = asyncio.new_event_loop()
84+
loop.run_until_complete(main())
85+
loop.close()

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "soliscloud-api"
7-
version = "1.2.0"
7+
version = "1.3.0"
88
authors = [
99
{ name="Peter van Hulten", email="peter.vanhulten@gmx.net" },
1010
]

0 commit comments

Comments
 (0)