pysma 0.2.0__zip
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.
- Python/Lib/site-packages/pysma/__init__.py +128 -0
- Python/Lib/site-packages/pysma/__pycache__/__init__.cpython-36.pyc +0 -0
- Python/Lib/site-packages/pysma-0.2.0-py3.6.egg-info/PKG-INFO +11 -0
- Python/Lib/site-packages/pysma-0.2.0-py3.6.egg-info/SOURCES.txt +9 -0
- Python/Lib/site-packages/pysma-0.2.0-py3.6.egg-info/dependency_links.txt +1 -0
- Python/Lib/site-packages/pysma-0.2.0-py3.6.egg-info/requires.txt +2 -0
- Python/Lib/site-packages/pysma-0.2.0-py3.6.egg-info/top_level.txt +1 -0
- Python/Lib/site-packages/pysma-0.2.0-py3.6.egg-info/zip-safe +1 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""SMA WebConnect library for Python.
|
|
2
|
+
|
|
3
|
+
See: http://www.sma.de/en/products/monitoring-control/webconnect.html
|
|
4
|
+
|
|
5
|
+
Source: http://www.github.com/kellerza/pysma
|
|
6
|
+
"""
|
|
7
|
+
import asyncio
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
import async_timeout
|
|
12
|
+
|
|
13
|
+
_LOGGER = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
GROUP_USER = 'usr'
|
|
16
|
+
GROUP_INSTALLER = 'istl'
|
|
17
|
+
|
|
18
|
+
KEY_CURRENT_POWER_W = '6100_40263F00'
|
|
19
|
+
KEY_CURRENT_CONSUMPTION_W = '6100_00543100'
|
|
20
|
+
KEY_TOTAL_YIELD_KWH = '6400_00260100'
|
|
21
|
+
KEY_TOTAL_CONSUMPTION_KWH = '6400_00543A00'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
URL_LOGIN = "{}/dyn/login.json"
|
|
25
|
+
URL_LOGOUT = "{}/dyn/logout.json"
|
|
26
|
+
URL_VALUES = "{}/dyn/getValues.json"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SMA:
|
|
30
|
+
"""Class to connect to the SMA webconnect module and read parameters."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, session, url, password, group=GROUP_USER):
|
|
33
|
+
"""Init SMA connection."""
|
|
34
|
+
self._new_session_data = {
|
|
35
|
+
'right': group, 'pass': password}
|
|
36
|
+
self._url = url.rstrip('/')
|
|
37
|
+
if not url.startswith('http'):
|
|
38
|
+
self._url = "http://" + self._url
|
|
39
|
+
self._aio_session = session
|
|
40
|
+
self._sma_sid = None
|
|
41
|
+
self._401_error_count = 0
|
|
42
|
+
|
|
43
|
+
@asyncio.coroutine
|
|
44
|
+
def _fetch_json(self, url, payload, params=None):
|
|
45
|
+
"""Fetch json data for requests."""
|
|
46
|
+
headers = {'content-type': 'application/json'}
|
|
47
|
+
with async_timeout.timeout(3):
|
|
48
|
+
res = yield from self._aio_session.post(
|
|
49
|
+
url, data=json.dumps(payload), headers=headers, params=params)
|
|
50
|
+
return (yield from res.json())
|
|
51
|
+
|
|
52
|
+
@asyncio.coroutine
|
|
53
|
+
def new_session(self):
|
|
54
|
+
"""Establish a new session."""
|
|
55
|
+
try:
|
|
56
|
+
res = yield from self._fetch_json(
|
|
57
|
+
URL_LOGIN.format(self._url), self._new_session_data)
|
|
58
|
+
self._sma_sid = res['result']['sid']
|
|
59
|
+
return True
|
|
60
|
+
except asyncio.TimeoutError:
|
|
61
|
+
_LOGGER.error("Could not connect to SMA at %s", self._url)
|
|
62
|
+
except KeyError:
|
|
63
|
+
self._sma_sid = None
|
|
64
|
+
if str(res.get('err', '')) == '503':
|
|
65
|
+
_LOGGER.error("Max amount of sesions reached")
|
|
66
|
+
else:
|
|
67
|
+
_LOGGER.error("Session ID expected ['result']['sid'], got %s",
|
|
68
|
+
res)
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
@asyncio.coroutine
|
|
72
|
+
def close_session(self):
|
|
73
|
+
"""Close the session login."""
|
|
74
|
+
if self._sma_sid is None:
|
|
75
|
+
return
|
|
76
|
+
yield from self._fetch_json(
|
|
77
|
+
URL_LOGOUT.format(self._url), {}, params={'sid': self._sma_sid})
|
|
78
|
+
self._sma_sid = None
|
|
79
|
+
|
|
80
|
+
@asyncio.coroutine
|
|
81
|
+
def read(self, keys):
|
|
82
|
+
"""Read a set of keys."""
|
|
83
|
+
payload = {'destDev': [], 'keys': keys}
|
|
84
|
+
if self._sma_sid is None:
|
|
85
|
+
yield from self.new_session()
|
|
86
|
+
if self._sma_sid is None:
|
|
87
|
+
return None
|
|
88
|
+
try:
|
|
89
|
+
res = yield from self._fetch_json(
|
|
90
|
+
URL_VALUES.format(self._url), payload=payload,
|
|
91
|
+
params={'sid': self._sma_sid})
|
|
92
|
+
except asyncio.TimeoutError:
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
# On the first 401 error we close the session which will re-login
|
|
96
|
+
if res.get('err') == 401 and self._401_error_count == 0:
|
|
97
|
+
_LOGGER.warning("401 error detected, closing session to force " +
|
|
98
|
+
"another login attempt")
|
|
99
|
+
self.close_session()
|
|
100
|
+
self._401_error_count += 1
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
_, res = res['result'].popitem() # Only use first value
|
|
105
|
+
result = []
|
|
106
|
+
for key in keys:
|
|
107
|
+
result.append(res[key])
|
|
108
|
+
except (KeyError, TypeError) as err:
|
|
109
|
+
_LOGGER.error("Unexpected return: %s - %s", res, err)
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
for idx, val in enumerate(result):
|
|
113
|
+
try:
|
|
114
|
+
# First list item indicates result length,
|
|
115
|
+
# Results are the second item in list.
|
|
116
|
+
result[idx] = val.popitem()[1]
|
|
117
|
+
# Extract all ['val'] values
|
|
118
|
+
result[idx] = [value['val'] for value in result[idx]]
|
|
119
|
+
# If only 1 item in list, remove list
|
|
120
|
+
if len(result[idx]) == 1:
|
|
121
|
+
result[idx] = result[idx][0]
|
|
122
|
+
except (KeyError, TypeError) as err:
|
|
123
|
+
_LOGGER.error(err)
|
|
124
|
+
|
|
125
|
+
# reset 401 error count
|
|
126
|
+
self._401_error_count = 0
|
|
127
|
+
|
|
128
|
+
return result
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 1.1
|
|
2
|
+
Name: pysma
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Library to interface an SMA Solar WebConnect module
|
|
5
|
+
Home-page: https://github.com/kellerza/pysma
|
|
6
|
+
Author: Johann Kellerman
|
|
7
|
+
Author-email: kellerza@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Download-URL: https://github.com/kellerza/pysma/tarball/0.2
|
|
10
|
+
Description: UNKNOWN
|
|
11
|
+
Platform: UNKNOWN
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pysma
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|