pysmarlaapi 0.5.0__py3-none-any.whl → 0.6.0__py3-none-any.whl
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.
Potentially problematic release.
This version of pysmarlaapi might be problematic. Click here for more details.
- pysmarlaapi/__init__.py +4 -4
- pysmarlaapi/classes/__init__.py +2 -2
- pysmarlaapi/classes/auth_token.py +36 -36
- pysmarlaapi/classes/connection.py +40 -40
- pysmarlaapi/connection_hub/__init__.py +148 -148
- pysmarlaapi/federwiege/__init__.py +64 -64
- pysmarlaapi/federwiege/classes/__init__.py +2 -2
- pysmarlaapi/federwiege/classes/property.py +46 -46
- pysmarlaapi/federwiege/classes/service.py +28 -28
- pysmarlaapi/federwiege/services/__init__.py +3 -3
- pysmarlaapi/federwiege/services/analyser_service.py +65 -65
- pysmarlaapi/federwiege/services/babywiege_service.py +74 -74
- pysmarlaapi/federwiege/services/info_service.py +46 -46
- {pysmarlaapi-0.5.0.dist-info → pysmarlaapi-0.6.0.dist-info}/METADATA +2 -2
- pysmarlaapi-0.6.0.dist-info/RECORD +17 -0
- {pysmarlaapi-0.5.0.dist-info → pysmarlaapi-0.6.0.dist-info}/licenses/LICENSE +201 -201
- pysmarlaapi-0.5.0.dist-info/RECORD +0 -17
- {pysmarlaapi-0.5.0.dist-info → pysmarlaapi-0.6.0.dist-info}/WHEEL +0 -0
pysmarlaapi/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
__version__ = "0.
|
|
2
|
-
|
|
3
|
-
from .classes import Connection
|
|
4
|
-
from .federwiege import Federwiege
|
|
1
|
+
__version__ = "0.6.0"
|
|
2
|
+
|
|
3
|
+
from .classes import Connection
|
|
4
|
+
from .federwiege import Federwiege
|
pysmarlaapi/classes/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
from .auth_token import AuthToken
|
|
2
|
-
from .connection import Connection
|
|
1
|
+
from .auth_token import AuthToken
|
|
2
|
+
from .connection import Connection
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
from typing import Self
|
|
4
|
-
|
|
5
|
-
import jsonpickle
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@dataclass
|
|
9
|
-
class AuthToken:
|
|
10
|
-
refreshToken: str
|
|
11
|
-
token: str
|
|
12
|
-
dateCreated: str
|
|
13
|
-
appIdentifier: str
|
|
14
|
-
serialNumber: str
|
|
15
|
-
appVersion: str
|
|
16
|
-
appCulture: str
|
|
17
|
-
|
|
18
|
-
@classmethod
|
|
19
|
-
def from_json(cls, value) -> Self:
|
|
20
|
-
value["py/object"] = "pysmarlaapi.classes.auth_token.AuthToken"
|
|
21
|
-
return jsonpickle.decode(str(value))
|
|
22
|
-
|
|
23
|
-
@classmethod
|
|
24
|
-
def from_string(cls, value) -> Self:
|
|
25
|
-
return AuthToken.from_json(jsonpickle.decode(value))
|
|
26
|
-
|
|
27
|
-
@classmethod
|
|
28
|
-
def from_base64(cls, value) -> Self:
|
|
29
|
-
token = base64.b64decode(value.encode()).decode()
|
|
30
|
-
return AuthToken.from_string(token)
|
|
31
|
-
|
|
32
|
-
def get_string(self) -> str:
|
|
33
|
-
return jsonpickle.encode(self, unpicklable=False)
|
|
34
|
-
|
|
35
|
-
def get_base64(self) -> str:
|
|
36
|
-
return base64.b64encode(self.get_string().encode()).decode()
|
|
1
|
+
import base64
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Self
|
|
4
|
+
|
|
5
|
+
import jsonpickle
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class AuthToken:
|
|
10
|
+
refreshToken: str
|
|
11
|
+
token: str
|
|
12
|
+
dateCreated: str
|
|
13
|
+
appIdentifier: str
|
|
14
|
+
serialNumber: str
|
|
15
|
+
appVersion: str
|
|
16
|
+
appCulture: str
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def from_json(cls, value) -> Self:
|
|
20
|
+
value["py/object"] = "pysmarlaapi.classes.auth_token.AuthToken"
|
|
21
|
+
return jsonpickle.decode(str(value))
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def from_string(cls, value) -> Self:
|
|
25
|
+
return AuthToken.from_json(jsonpickle.decode(value))
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def from_base64(cls, value) -> Self:
|
|
29
|
+
token = base64.b64decode(value.encode()).decode()
|
|
30
|
+
return AuthToken.from_string(token)
|
|
31
|
+
|
|
32
|
+
def get_string(self) -> str:
|
|
33
|
+
return jsonpickle.encode(self, unpicklable=False)
|
|
34
|
+
|
|
35
|
+
def get_base64(self) -> str:
|
|
36
|
+
return base64.b64encode(self.get_string().encode()).decode()
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import aiohttp
|
|
2
|
-
import jsonpickle
|
|
3
|
-
|
|
4
|
-
from . import AuthToken
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Connection:
|
|
8
|
-
|
|
9
|
-
def __init__(self, url: str, token: AuthToken = None, token_str=None, token_json=None, token_b64=None):
|
|
10
|
-
self.url = url
|
|
11
|
-
if token is not None:
|
|
12
|
-
self.token = token
|
|
13
|
-
elif token_json is not None:
|
|
14
|
-
self.token = AuthToken.from_json(token_json)
|
|
15
|
-
elif token_str is not None:
|
|
16
|
-
self.token = AuthToken.from_string(token_str)
|
|
17
|
-
elif token_b64 is not None:
|
|
18
|
-
self.token = AuthToken.from_base64(token_b64)
|
|
19
|
-
else:
|
|
20
|
-
self.token = None
|
|
21
|
-
|
|
22
|
-
async def get_token(self) -> AuthToken:
|
|
23
|
-
try:
|
|
24
|
-
async with aiohttp.ClientSession(self.url) as session:
|
|
25
|
-
async with session.post(
|
|
26
|
-
"/api/AppParing/getToken",
|
|
27
|
-
headers={"accept": "*/*", "Content-Type": "application/json"},
|
|
28
|
-
data=jsonpickle.encode(self.token, unpicklable=False),
|
|
29
|
-
) as response:
|
|
30
|
-
if response.status != 200:
|
|
31
|
-
return None
|
|
32
|
-
json_body = await response.json()
|
|
33
|
-
except ValueError:
|
|
34
|
-
return None
|
|
35
|
-
try:
|
|
36
|
-
new_token = AuthToken.from_json(json_body)
|
|
37
|
-
except ValueError:
|
|
38
|
-
return None
|
|
39
|
-
self.token = new_token
|
|
40
|
-
return self.token
|
|
1
|
+
import aiohttp
|
|
2
|
+
import jsonpickle
|
|
3
|
+
|
|
4
|
+
from . import AuthToken
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Connection:
|
|
8
|
+
|
|
9
|
+
def __init__(self, url: str, token: AuthToken = None, token_str=None, token_json=None, token_b64=None):
|
|
10
|
+
self.url = url
|
|
11
|
+
if token is not None:
|
|
12
|
+
self.token = token
|
|
13
|
+
elif token_json is not None:
|
|
14
|
+
self.token = AuthToken.from_json(token_json)
|
|
15
|
+
elif token_str is not None:
|
|
16
|
+
self.token = AuthToken.from_string(token_str)
|
|
17
|
+
elif token_b64 is not None:
|
|
18
|
+
self.token = AuthToken.from_base64(token_b64)
|
|
19
|
+
else:
|
|
20
|
+
self.token = None
|
|
21
|
+
|
|
22
|
+
async def get_token(self) -> AuthToken:
|
|
23
|
+
try:
|
|
24
|
+
async with aiohttp.ClientSession(self.url) as session:
|
|
25
|
+
async with session.post(
|
|
26
|
+
"/api/AppParing/getToken",
|
|
27
|
+
headers={"accept": "*/*", "Content-Type": "application/json"},
|
|
28
|
+
data=jsonpickle.encode(self.token, unpicklable=False),
|
|
29
|
+
) as response:
|
|
30
|
+
if response.status != 200:
|
|
31
|
+
return None
|
|
32
|
+
json_body = await response.json()
|
|
33
|
+
except ValueError:
|
|
34
|
+
return None
|
|
35
|
+
try:
|
|
36
|
+
new_token = AuthToken.from_json(json_body)
|
|
37
|
+
except ValueError:
|
|
38
|
+
return None
|
|
39
|
+
self.token = new_token
|
|
40
|
+
return self.token
|
|
@@ -1,148 +1,148 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import logging
|
|
3
|
-
import random
|
|
4
|
-
import uuid
|
|
5
|
-
|
|
6
|
-
from pysignalr.client import SignalRClient
|
|
7
|
-
from pysignalr.transport.abstract import ConnectionState
|
|
8
|
-
|
|
9
|
-
from ..classes import Connection
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
async def event_wait(event, timeout):
|
|
13
|
-
try:
|
|
14
|
-
await asyncio.wait_for(event.wait(), timeout)
|
|
15
|
-
except asyncio.TimeoutError:
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class ConnectionHub:
|
|
20
|
-
"""SignalRCore Hub
|
|
21
|
-
Provides interface via websocket for the controller using the SignalRCore protocol.
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
@property
|
|
25
|
-
def running(self):
|
|
26
|
-
return self._running
|
|
27
|
-
|
|
28
|
-
@property
|
|
29
|
-
def connected(self):
|
|
30
|
-
return self.client._transport._state == ConnectionState.connected if self.client else False
|
|
31
|
-
|
|
32
|
-
def __init__(
|
|
33
|
-
self,
|
|
34
|
-
event_loop: asyncio.AbstractEventLoop,
|
|
35
|
-
connection: Connection,
|
|
36
|
-
interval: int = 60,
|
|
37
|
-
backoff: int = 300,
|
|
38
|
-
):
|
|
39
|
-
self.connection: Connection = connection
|
|
40
|
-
self._loop = event_loop
|
|
41
|
-
self._interval = interval
|
|
42
|
-
self._backoff = backoff
|
|
43
|
-
|
|
44
|
-
self.logger = logging.getLogger(f"{__package__}[{self.connection.token.serialNumber}]")
|
|
45
|
-
|
|
46
|
-
self.listeners = set()
|
|
47
|
-
|
|
48
|
-
self._running = False
|
|
49
|
-
self._wake = asyncio.Event()
|
|
50
|
-
|
|
51
|
-
self.client = None
|
|
52
|
-
self.setup()
|
|
53
|
-
|
|
54
|
-
async def notifycontrollerconnection(self, args):
|
|
55
|
-
value = args[0]
|
|
56
|
-
if value == "ControllerConnected":
|
|
57
|
-
await self.notify_listeners(True)
|
|
58
|
-
else:
|
|
59
|
-
await self.notify_listeners(False)
|
|
60
|
-
|
|
61
|
-
def setup(self):
|
|
62
|
-
self.client = SignalRClient(self.connection.url + "/MobileAppHub", retry_count=1)
|
|
63
|
-
self.client.on_open(self.on_open_function)
|
|
64
|
-
self.client.on_close(self.on_close_function)
|
|
65
|
-
self.client.on_error(self.on_error)
|
|
66
|
-
self.client.on("SetNotifyAppConnectionCallback", self.notifycontrollerconnection)
|
|
67
|
-
|
|
68
|
-
def add_listener(self, listener):
|
|
69
|
-
if self.running:
|
|
70
|
-
return
|
|
71
|
-
self.listeners.add(listener)
|
|
72
|
-
|
|
73
|
-
def remove_listener(self, listener):
|
|
74
|
-
if self.running:
|
|
75
|
-
return
|
|
76
|
-
self.listeners.remove(listener)
|
|
77
|
-
|
|
78
|
-
async def notify_listeners(self, value):
|
|
79
|
-
for listener in self.listeners:
|
|
80
|
-
await listener(value)
|
|
81
|
-
|
|
82
|
-
async def on_open_function(self):
|
|
83
|
-
self.logger.info("Connection to server established")
|
|
84
|
-
|
|
85
|
-
async def on_close_function(self):
|
|
86
|
-
self.logger.info("Connection to server closed")
|
|
87
|
-
|
|
88
|
-
async def on_error(self, message):
|
|
89
|
-
self.logger.error("Connection error occurred: " + str(message))
|
|
90
|
-
|
|
91
|
-
def start(self):
|
|
92
|
-
if self.running:
|
|
93
|
-
return
|
|
94
|
-
self._running = True
|
|
95
|
-
asyncio.run_coroutine_threadsafe(self.connection_watcher(), self._loop)
|
|
96
|
-
|
|
97
|
-
def stop(self):
|
|
98
|
-
if not self.running:
|
|
99
|
-
return
|
|
100
|
-
self._running = False
|
|
101
|
-
self.close_connection()
|
|
102
|
-
self.wake_up()
|
|
103
|
-
|
|
104
|
-
async def connection_watcher(self):
|
|
105
|
-
while self.running:
|
|
106
|
-
await self.refresh_token()
|
|
107
|
-
try:
|
|
108
|
-
await self.client.run()
|
|
109
|
-
except Exception as e:
|
|
110
|
-
self.logger.warning(f"Error during connection: {type(e).__name__}: {str(e)}")
|
|
111
|
-
|
|
112
|
-
# Random backoff to avoid simultaneous connection attempts
|
|
113
|
-
backoff = random.randint(0, self._backoff)
|
|
114
|
-
await event_wait(self._wake, self._interval + backoff)
|
|
115
|
-
self._wake.clear()
|
|
116
|
-
|
|
117
|
-
def wake_up(self):
|
|
118
|
-
self._wake.set()
|
|
119
|
-
|
|
120
|
-
def close_connection(self):
|
|
121
|
-
if not self.connected:
|
|
122
|
-
return
|
|
123
|
-
asyncio.run_coroutine_threadsafe(self.client._transport._ws.close(), self._loop)
|
|
124
|
-
|
|
125
|
-
async def refresh_token(self):
|
|
126
|
-
await self.connection.get_token()
|
|
127
|
-
auth_token = self.connection.token.token
|
|
128
|
-
self.client._transport._headers["Authorization"] = f"Bearer {auth_token}"
|
|
129
|
-
self.logger.info("Auth token refreshed")
|
|
130
|
-
|
|
131
|
-
def send_serialized_data(self, event, value=None):
|
|
132
|
-
serialized_result = {
|
|
133
|
-
"callIdentifier": {
|
|
134
|
-
"requestNonce": str(uuid.uuid4()),
|
|
135
|
-
},
|
|
136
|
-
}
|
|
137
|
-
if value is not None:
|
|
138
|
-
serialized_result["value"] = value
|
|
139
|
-
|
|
140
|
-
self.logger.debug(f"Sending data, Event: {event}, Payload: {str(serialized_result)}")
|
|
141
|
-
|
|
142
|
-
asyncio.run_coroutine_threadsafe(self.send_data(event, [serialized_result]), self._loop)
|
|
143
|
-
|
|
144
|
-
async def send_data(self, event, data):
|
|
145
|
-
try:
|
|
146
|
-
await self.client.send(event, data)
|
|
147
|
-
except Exception:
|
|
148
|
-
pass
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import random
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
from pysignalr.client import SignalRClient
|
|
7
|
+
from pysignalr.transport.abstract import ConnectionState
|
|
8
|
+
|
|
9
|
+
from ..classes import Connection
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def event_wait(event, timeout):
|
|
13
|
+
try:
|
|
14
|
+
await asyncio.wait_for(event.wait(), timeout)
|
|
15
|
+
except asyncio.TimeoutError:
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ConnectionHub:
|
|
20
|
+
"""SignalRCore Hub
|
|
21
|
+
Provides interface via websocket for the controller using the SignalRCore protocol.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def running(self):
|
|
26
|
+
return self._running
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def connected(self):
|
|
30
|
+
return self.client._transport._state == ConnectionState.connected if self.client else False
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
event_loop: asyncio.AbstractEventLoop,
|
|
35
|
+
connection: Connection,
|
|
36
|
+
interval: int = 60,
|
|
37
|
+
backoff: int = 300,
|
|
38
|
+
):
|
|
39
|
+
self.connection: Connection = connection
|
|
40
|
+
self._loop = event_loop
|
|
41
|
+
self._interval = interval
|
|
42
|
+
self._backoff = backoff
|
|
43
|
+
|
|
44
|
+
self.logger = logging.getLogger(f"{__package__}[{self.connection.token.serialNumber}]")
|
|
45
|
+
|
|
46
|
+
self.listeners = set()
|
|
47
|
+
|
|
48
|
+
self._running = False
|
|
49
|
+
self._wake = asyncio.Event()
|
|
50
|
+
|
|
51
|
+
self.client = None
|
|
52
|
+
self.setup()
|
|
53
|
+
|
|
54
|
+
async def notifycontrollerconnection(self, args):
|
|
55
|
+
value = args[0]
|
|
56
|
+
if value == "ControllerConnected":
|
|
57
|
+
await self.notify_listeners(True)
|
|
58
|
+
else:
|
|
59
|
+
await self.notify_listeners(False)
|
|
60
|
+
|
|
61
|
+
def setup(self):
|
|
62
|
+
self.client = SignalRClient(self.connection.url + "/MobileAppHub", retry_count=1)
|
|
63
|
+
self.client.on_open(self.on_open_function)
|
|
64
|
+
self.client.on_close(self.on_close_function)
|
|
65
|
+
self.client.on_error(self.on_error)
|
|
66
|
+
self.client.on("SetNotifyAppConnectionCallback", self.notifycontrollerconnection)
|
|
67
|
+
|
|
68
|
+
def add_listener(self, listener):
|
|
69
|
+
if self.running:
|
|
70
|
+
return
|
|
71
|
+
self.listeners.add(listener)
|
|
72
|
+
|
|
73
|
+
def remove_listener(self, listener):
|
|
74
|
+
if self.running:
|
|
75
|
+
return
|
|
76
|
+
self.listeners.remove(listener)
|
|
77
|
+
|
|
78
|
+
async def notify_listeners(self, value):
|
|
79
|
+
for listener in self.listeners:
|
|
80
|
+
await listener(value)
|
|
81
|
+
|
|
82
|
+
async def on_open_function(self):
|
|
83
|
+
self.logger.info("Connection to server established")
|
|
84
|
+
|
|
85
|
+
async def on_close_function(self):
|
|
86
|
+
self.logger.info("Connection to server closed")
|
|
87
|
+
|
|
88
|
+
async def on_error(self, message):
|
|
89
|
+
self.logger.error("Connection error occurred: " + str(message))
|
|
90
|
+
|
|
91
|
+
def start(self):
|
|
92
|
+
if self.running:
|
|
93
|
+
return
|
|
94
|
+
self._running = True
|
|
95
|
+
asyncio.run_coroutine_threadsafe(self.connection_watcher(), self._loop)
|
|
96
|
+
|
|
97
|
+
def stop(self):
|
|
98
|
+
if not self.running:
|
|
99
|
+
return
|
|
100
|
+
self._running = False
|
|
101
|
+
self.close_connection()
|
|
102
|
+
self.wake_up()
|
|
103
|
+
|
|
104
|
+
async def connection_watcher(self):
|
|
105
|
+
while self.running:
|
|
106
|
+
await self.refresh_token()
|
|
107
|
+
try:
|
|
108
|
+
await self.client.run()
|
|
109
|
+
except Exception as e:
|
|
110
|
+
self.logger.warning(f"Error during connection: {type(e).__name__}: {str(e)}")
|
|
111
|
+
|
|
112
|
+
# Random backoff to avoid simultaneous connection attempts
|
|
113
|
+
backoff = random.randint(0, self._backoff)
|
|
114
|
+
await event_wait(self._wake, self._interval + backoff)
|
|
115
|
+
self._wake.clear()
|
|
116
|
+
|
|
117
|
+
def wake_up(self):
|
|
118
|
+
self._wake.set()
|
|
119
|
+
|
|
120
|
+
def close_connection(self):
|
|
121
|
+
if not self.connected:
|
|
122
|
+
return
|
|
123
|
+
asyncio.run_coroutine_threadsafe(self.client._transport._ws.close(), self._loop)
|
|
124
|
+
|
|
125
|
+
async def refresh_token(self):
|
|
126
|
+
await self.connection.get_token()
|
|
127
|
+
auth_token = self.connection.token.token
|
|
128
|
+
self.client._transport._headers["Authorization"] = f"Bearer {auth_token}"
|
|
129
|
+
self.logger.info("Auth token refreshed")
|
|
130
|
+
|
|
131
|
+
def send_serialized_data(self, event, value=None):
|
|
132
|
+
serialized_result = {
|
|
133
|
+
"callIdentifier": {
|
|
134
|
+
"requestNonce": str(uuid.uuid4()),
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
if value is not None:
|
|
138
|
+
serialized_result["value"] = value
|
|
139
|
+
|
|
140
|
+
self.logger.debug(f"Sending data, Event: {event}, Payload: {str(serialized_result)}")
|
|
141
|
+
|
|
142
|
+
asyncio.run_coroutine_threadsafe(self.send_data(event, [serialized_result]), self._loop)
|
|
143
|
+
|
|
144
|
+
async def send_data(self, event, data):
|
|
145
|
+
try:
|
|
146
|
+
await self.client.send(event, data)
|
|
147
|
+
except Exception:
|
|
148
|
+
pass
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import threading
|
|
3
|
-
|
|
4
|
-
from ..classes import Connection
|
|
5
|
-
from ..connection_hub import ConnectionHub
|
|
6
|
-
from .classes import Service
|
|
7
|
-
from .services import AnalyserService, BabywiegeService, InfoService
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Federwiege:
|
|
11
|
-
|
|
12
|
-
@property
|
|
13
|
-
def running(self):
|
|
14
|
-
return self.hub.running
|
|
15
|
-
|
|
16
|
-
@property
|
|
17
|
-
def connected(self):
|
|
18
|
-
return self.hub.connected
|
|
19
|
-
|
|
20
|
-
async def on_controller_connection_change(self, value):
|
|
21
|
-
self.available = value
|
|
22
|
-
if value:
|
|
23
|
-
self.sync()
|
|
24
|
-
|
|
25
|
-
def __init__(self, event_loop: asyncio.AbstractEventLoop, connection: Connection):
|
|
26
|
-
self.serial_number = connection.token.serialNumber
|
|
27
|
-
self.hub = ConnectionHub(event_loop, connection)
|
|
28
|
-
self.services: dict[str, Service] = {
|
|
29
|
-
"babywiege": BabywiegeService(self.hub),
|
|
30
|
-
"analyser": AnalyserService(self.hub),
|
|
31
|
-
"info": InfoService(self.hub),
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
self.registered = False
|
|
35
|
-
self._lock = threading.Lock()
|
|
36
|
-
|
|
37
|
-
self.available = False
|
|
38
|
-
|
|
39
|
-
def get_service(self, service):
|
|
40
|
-
if service not in self.services:
|
|
41
|
-
return None
|
|
42
|
-
return self.services[service]
|
|
43
|
-
|
|
44
|
-
def connect(self):
|
|
45
|
-
with self._lock:
|
|
46
|
-
if not self.registered:
|
|
47
|
-
return
|
|
48
|
-
self.hub.start()
|
|
49
|
-
|
|
50
|
-
def disconnect(self):
|
|
51
|
-
self.hub.stop()
|
|
52
|
-
|
|
53
|
-
def sync(self):
|
|
54
|
-
for service in self.services.values():
|
|
55
|
-
service.sync()
|
|
56
|
-
|
|
57
|
-
def register(self):
|
|
58
|
-
with self._lock:
|
|
59
|
-
if self.registered:
|
|
60
|
-
return
|
|
61
|
-
self.registered = True
|
|
62
|
-
self.hub.add_listener(self.on_controller_connection_change)
|
|
63
|
-
for service in self.services.values():
|
|
64
|
-
service.register()
|
|
1
|
+
import asyncio
|
|
2
|
+
import threading
|
|
3
|
+
|
|
4
|
+
from ..classes import Connection
|
|
5
|
+
from ..connection_hub import ConnectionHub
|
|
6
|
+
from .classes import Service
|
|
7
|
+
from .services import AnalyserService, BabywiegeService, InfoService
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Federwiege:
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def running(self):
|
|
14
|
+
return self.hub.running
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def connected(self):
|
|
18
|
+
return self.hub.connected
|
|
19
|
+
|
|
20
|
+
async def on_controller_connection_change(self, value):
|
|
21
|
+
self.available = value
|
|
22
|
+
if value:
|
|
23
|
+
self.sync()
|
|
24
|
+
|
|
25
|
+
def __init__(self, event_loop: asyncio.AbstractEventLoop, connection: Connection):
|
|
26
|
+
self.serial_number = connection.token.serialNumber
|
|
27
|
+
self.hub = ConnectionHub(event_loop, connection)
|
|
28
|
+
self.services: dict[str, Service] = {
|
|
29
|
+
"babywiege": BabywiegeService(self.hub),
|
|
30
|
+
"analyser": AnalyserService(self.hub),
|
|
31
|
+
"info": InfoService(self.hub),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
self.registered = False
|
|
35
|
+
self._lock = threading.Lock()
|
|
36
|
+
|
|
37
|
+
self.available = False
|
|
38
|
+
|
|
39
|
+
def get_service(self, service: str):
|
|
40
|
+
if service not in self.services:
|
|
41
|
+
return None
|
|
42
|
+
return self.services[service]
|
|
43
|
+
|
|
44
|
+
def connect(self):
|
|
45
|
+
with self._lock:
|
|
46
|
+
if not self.registered:
|
|
47
|
+
return
|
|
48
|
+
self.hub.start()
|
|
49
|
+
|
|
50
|
+
def disconnect(self):
|
|
51
|
+
self.hub.stop()
|
|
52
|
+
|
|
53
|
+
def sync(self):
|
|
54
|
+
for service in self.services.values():
|
|
55
|
+
service.sync()
|
|
56
|
+
|
|
57
|
+
def register(self):
|
|
58
|
+
with self._lock:
|
|
59
|
+
if self.registered:
|
|
60
|
+
return
|
|
61
|
+
self.registered = True
|
|
62
|
+
self.hub.add_listener(self.on_controller_connection_change)
|
|
63
|
+
for service in self.services.values():
|
|
64
|
+
service.register()
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
from .property import Property
|
|
2
|
-
from .service import Service
|
|
1
|
+
from .property import Property
|
|
2
|
+
from .service import Service
|