Merge pull request #34 from stuertz/precommit
refactor: use pre-commit with some opinonated linters
This commit is contained in:
commit
dd8d55ccc3
|
@ -14,3 +14,5 @@ coverage.xml
|
|||
**/authcache
|
||||
**/exports
|
||||
**/credentials*
|
||||
/node_modules/
|
||||
/client.py
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
repos:
|
||||
- repo: https://github.com/timothycrosley/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/ambv/black
|
||||
rev: 24.2.0
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 7.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
args: ["--format", "pylint"]
|
||||
- repo: https://github.com/pycqa/pylint
|
||||
rev: v3.0.3
|
||||
hooks:
|
||||
- id: pylint
|
||||
args: ["--output-format", "parseable"]
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.5.0
|
||||
hooks:
|
||||
- id: check-ast
|
||||
- id: check-case-conflict
|
||||
- id: mixed-line-ending
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v4.0.0-alpha.8
|
||||
hooks:
|
||||
- id: prettier
|
||||
default_language_version:
|
||||
python: python3
|
12
README.md
12
README.md
|
@ -15,8 +15,8 @@ This is an experimental Python library for Anker Solix Power devices (Solarbank,
|
|||
|
||||
The library is currently supported on
|
||||
|
||||
* Python 3.11
|
||||
* Python 3.12
|
||||
- Python 3.11
|
||||
- Python 3.12
|
||||
|
||||
# Required libraries
|
||||
|
||||
|
@ -71,6 +71,7 @@ if __name__ == '__main__':
|
|||
```
|
||||
|
||||
The AnkerSolixApi class provides 2 main methods:
|
||||
|
||||
- `AnkerSolixApi.update_sites()` to query overview data for all accessible sites and store data in dictionaries `AnkerSolixApi.sites` and `AnkerSolixApi.devices` for quick access.
|
||||
This method could be run in regular intervals (30sec or more) to fetch new data of the systems
|
||||
- `AnkerSolixApi.update_device_details()` to query further settings for the device serials as found in the sites query.
|
||||
|
@ -79,7 +80,7 @@ The AnkerSolixApi class provides 2 main methods:
|
|||
could be added once example data is available.
|
||||
|
||||
Check out `test_api.py` and other python executable tools that may help to leverage and explore the Api for your Anker power system.
|
||||
The subfolder [`examples`](https://github.com/thomluther/anker-solix-api/tree/main/examples) contains actual example exports with json files using anonymized responses of the `export_system.py` module giving you an idea of how various Api responses look like. (Note that the Solarbank was switched off when the data were pulled, so some fields may be empty)
|
||||
The subfolder [`examples`](https://github.com/thomluther/anker-solix-api/tree/main/examples) contains actual example exports with json files using anonymized responses of the `export_system.py` module giving you an idea of how various Api responses look like. (Note that the Solarbank was switched off when the data were pulled, so some fields may be empty)
|
||||
Those json files can also be used to develop/debug the Api for system constellations not available to the developper.
|
||||
|
||||
# AnkerSolixApi Tools
|
||||
|
@ -121,7 +122,6 @@ charge however can be queried only as total for an interval (e.g. day). Therefor
|
|||
data is also selected for export, an additional Api query per day is required.
|
||||
The received daily values will be exported into a csv file.
|
||||
|
||||
|
||||
# Contributing
|
||||
|
||||
![github contributors](https://img.shields.io/github/contributors/thomluther/anker-solix-api?color=orange)
|
||||
|
@ -133,20 +133,18 @@ Github is used to host code, to track issues and feature requests, as well as ac
|
|||
Pull requests are the best way to propose changes to the codebase.
|
||||
|
||||
1. [Check for open features/bugs](https://github.com/thomluther/anker-solix-api/issues)
|
||||
or [initiate a discussion on one](https://github.com/thomluther/anker-solix-api/issues/new).
|
||||
or [initiate a discussion on one](https://github.com/thomluther/anker-solix-api/issues/new).
|
||||
1. [Fork the repository](https://github.com/thomluther/anker-solix-api/fork).
|
||||
1. Fork the repo and create your branch from `main`.
|
||||
1. If you've changed something, update the documentation.
|
||||
1. Test your contribution.
|
||||
1. Issue that pull request!
|
||||
|
||||
|
||||
# Acknowledgements / Credits
|
||||
|
||||
- [python-eufy-security](https://github.com/FuzzyMistborn/python-eufy-security)
|
||||
- [solix2mqtt](https://github.com/tomquist/solix2mqtt)
|
||||
|
||||
|
||||
# Showing Your Appreciation
|
||||
|
||||
[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/thomasluthe)
|
||||
|
|
31
api/api.py
31
api/api.py
|
@ -7,15 +7,15 @@ pip install aiohttp
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from base64 import b64encode
|
||||
import contextlib
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from base64 import b64encode
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from aiohttp.client_exceptions import ClientError
|
||||
|
@ -805,9 +805,10 @@ class AnkerSolixApi:
|
|||
siteInfo = mysite.get("site_info", {})
|
||||
siteInfo.update(site)
|
||||
mysite.update({"site_info": siteInfo})
|
||||
admin = (
|
||||
siteInfo.get("ms_type", 0) in [0, 1]
|
||||
) # add boolean key to indicate whether user is site admin (ms_type 1 or not known) and can query device details
|
||||
admin = siteInfo.get("ms_type", 0) in [
|
||||
0,
|
||||
1,
|
||||
] # add boolean key to indicate whether user is site admin (ms_type 1 or not known) and can query device details
|
||||
mysite.update({"site_admin": admin})
|
||||
# Update scene info for site
|
||||
self._logger.debug("Getting scene info for site")
|
||||
|
@ -1174,7 +1175,7 @@ class AnkerSolixApi:
|
|||
if isinstance(string_data, str):
|
||||
resp["data"].update({"home_load_data": json.loads(string_data)})
|
||||
data = resp.get("data", {})
|
||||
if (schedule := data.get("home_load_data", {})):
|
||||
if schedule := data.get("home_load_data", {}):
|
||||
self._update_dev({"device_sn": deviceSn, "schedule": schedule})
|
||||
return data
|
||||
|
||||
|
@ -1326,12 +1327,16 @@ class AnkerSolixApi:
|
|||
"site_id": siteId,
|
||||
"device_sn": deviceSn,
|
||||
"type": rangeType if rangeType in ["day", "week", "year"] else "day",
|
||||
"start_time": startDay.strftime("%Y-%m-%d")
|
||||
if startDay
|
||||
else datetime.today().strftime("%Y-%m-%d"),
|
||||
"device_type": devType
|
||||
if devType in ["solar_production", "solarbank"]
|
||||
else "solar_production",
|
||||
"start_time": (
|
||||
startDay.strftime("%Y-%m-%d")
|
||||
if startDay
|
||||
else datetime.today().strftime("%Y-%m-%d")
|
||||
),
|
||||
"device_type": (
|
||||
devType
|
||||
if devType in ["solar_production", "solarbank"]
|
||||
else "solar_production"
|
||||
),
|
||||
"end_time": endDay.strftime("%Y-%m-%d") if endDay else "",
|
||||
}
|
||||
resp = await self.request("post", _API_ENDPOINTS["energy_analysis"], json=data)
|
||||
|
|
|
@ -10,13 +10,14 @@ The received daily values will be exported into a csv file.
|
|||
|
||||
import asyncio
|
||||
import csv
|
||||
from datetime import datetime
|
||||
from getpass import getpass
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from getpass import getpass
|
||||
|
||||
from aiohttp import ClientSession
|
||||
|
||||
from api import api
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
|
|
@ -89,4 +89,4 @@
|
|||
"is_zero_output_tips": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
"site_id": "3df1aea0-4b7c-e0f8-7cc5-5ba5a4df5f7a",
|
||||
"site_name": "BKW",
|
||||
"site_img": "",
|
||||
"device_type_list": [
|
||||
3
|
||||
],
|
||||
"device_type_list": [3],
|
||||
"ms_type": 1,
|
||||
"power_site_type": 2,
|
||||
"is_allow_delete": true
|
||||
|
@ -81,4 +79,4 @@
|
|||
"site_id": "3df1aea0-4b7c-e0f8-7cc5-5ba5a4df5f7a",
|
||||
"powerpanel_list": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
]
|
||||
},
|
||||
"trace_id": "cd0b5b19d1ee5958cc4ecfdd66a90910"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,7 @@
|
|||
"link_time": 1695392302068,
|
||||
"wifi_online": false,
|
||||
"wifi_name": "",
|
||||
"relate_type": [
|
||||
"ble",
|
||||
"wifi"
|
||||
],
|
||||
"relate_type": ["ble", "wifi"],
|
||||
"charge": false,
|
||||
"bws_surplus": 0,
|
||||
"device_sw_version": "v1.4.4",
|
||||
|
@ -27,4 +24,4 @@
|
|||
]
|
||||
},
|
||||
"trace_id": "46caca47d8629d532caac685b2167ffb"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
"guide_txt": ""
|
||||
},
|
||||
"trace_id": "c7f8cb6b0dad2af2effa6ab6ad1fb424"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,4 +16,4 @@
|
|||
}
|
||||
},
|
||||
"trace_id": "fc6eb9cc0bd3ebb9900a1ba6d3bcfc7e"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
"data": []
|
||||
},
|
||||
"trace_id": "835d911e86a5a7bfea2d6e1f02cfdbbf"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,4 +9,4 @@
|
|||
"parallel_display": false
|
||||
},
|
||||
"trace_id": "daaad794adf6ec9ebcebd49ae3cbbff9"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
"param_data": "{\"ranges\":[{\"id\":0,\"start_time\":\"00:00\",\"end_time\":\"08:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":80},{\"id\":0,\"start_time\":\"08:00\",\"end_time\":\"17:00\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":100,\"number\":1}],\"charge_priority\":80},{\"id\":0,\"start_time\":\"17:00\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":0}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":0,\"default_charge_priority\":0,\"is_zero_output_tips\":1}"
|
||||
},
|
||||
"trace_id": "bdf5c51cd0fd73b07a5a49c7f8efda5b"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
"site_id": "3df1aea0-4b7c-e0f8-7cc5-5ba5a4df5f7a",
|
||||
"site_name": "BKW",
|
||||
"site_img": "",
|
||||
"device_type_list": [
|
||||
3
|
||||
],
|
||||
"device_type_list": [3],
|
||||
"ms_type": 0,
|
||||
"power_site_type": 0,
|
||||
"is_allow_delete": false
|
||||
|
@ -40,4 +38,4 @@
|
|||
"powerpanel_list": []
|
||||
},
|
||||
"trace_id": "2e647ef3c3bc8bdfe5e2f1f21d0cd410"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,4 +20,4 @@
|
|||
]
|
||||
},
|
||||
"trace_id": "7ccca0c8df1fc646ad6a0bc1daea0dd2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,4 +8,4 @@
|
|||
"site_price_unit": "\u20ac"
|
||||
},
|
||||
"trace_id": "f43f68ee34777fd9fb83dc6ac067aed3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,4 +72,4 @@
|
|||
"powerpanel_list": []
|
||||
},
|
||||
"trace_id": "82aa6e7e4db47cbbe7b2ed355b751beb"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,4 +36,4 @@
|
|||
"powerpanel_list": []
|
||||
},
|
||||
"trace_id": "cd5d205dbe3e4ace5accfcbbcbc7bf5e"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
"site_id": "3df1aea0-4b7c-e0f8-7cc5-5ba5a4df5f7a",
|
||||
"site_name": "BKW",
|
||||
"site_img": "",
|
||||
"device_type_list": [
|
||||
3
|
||||
],
|
||||
"device_type_list": [3],
|
||||
"ms_type": 1,
|
||||
"power_site_type": 2,
|
||||
"is_allow_delete": true
|
||||
|
@ -17,4 +15,4 @@
|
|||
]
|
||||
},
|
||||
"trace_id": "f1ac7d6cee7a2432ea3e6d2dcaa3b6ad"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,4 +9,4 @@
|
|||
"solar_model_name": "MI60 Microinverter"
|
||||
},
|
||||
"trace_id": "faa1851e4db703c37e2f344ac596a2f1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,4 +26,4 @@
|
|||
]
|
||||
},
|
||||
"trace_id": "05cba7ba093e3e2abfaa4800f35fa7e0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,4 +10,4 @@
|
|||
]
|
||||
},
|
||||
"trace_id": "81d6b63ab0b93d9d6b99cecacbbd0ebc"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ Optionally the API class can use the json files for debugging and testing on var
|
|||
"""
|
||||
|
||||
import asyncio
|
||||
from getpass import getpass
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
@ -16,9 +15,11 @@ import random
|
|||
import string
|
||||
import sys
|
||||
import time
|
||||
from getpass import getpass
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from aiohttp.client_exceptions import ClientError
|
||||
|
||||
from api import api, errors
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
@ -315,7 +316,7 @@ async def main() -> bool: # noqa: C901
|
|||
await myapi.request(
|
||||
"post",
|
||||
api._API_ENDPOINTS["solar_info"],
|
||||
json={"solarbank_sn" : sn},
|
||||
json={"solarbank_sn": sn},
|
||||
),
|
||||
)
|
||||
except (ClientError, errors.AnkerSolixError):
|
||||
|
@ -331,7 +332,7 @@ async def main() -> bool: # noqa: C901
|
|||
await myapi.request(
|
||||
"post",
|
||||
api._API_ENDPOINTS["compatible_process"],
|
||||
json={"solarbank_sn" : sn},
|
||||
json={"solarbank_sn": sn},
|
||||
),
|
||||
)
|
||||
except (ClientError, errors.AnkerSolixError):
|
||||
|
|
|
@ -6,16 +6,17 @@ Attention: During executiion of this module, the used account cannot be used in
|
|||
""" # noqa: D205
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime, timedelta
|
||||
from getpass import getpass
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from getpass import getpass
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from aiohttp.client_exceptions import ClientError
|
||||
|
||||
from api import api, errors
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
"""Example exec module to test the Anker API for various methods or direct endpoint requests with various parameters."""
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
from aiohttp import ClientSession
|
||||
|
||||
from api import api, credentials
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
@ -26,7 +27,11 @@ async def main() -> None:
|
|||
# Update your account credentials in api.credentials.py or directly in this file for testing
|
||||
# Both files are added to .gitignore to avoid local changes being comitted to git
|
||||
myapi = api.AnkerSolixApi(
|
||||
credentials.USERNAME, credentials.PASSWORD, credentials.COUNTRYID, websession, _LOGGER
|
||||
credentials.USERNAME,
|
||||
credentials.PASSWORD,
|
||||
credentials.COUNTRYID,
|
||||
websession,
|
||||
_LOGGER,
|
||||
)
|
||||
|
||||
# show login response
|
||||
|
|
Loading…
Reference in New Issue