ironflock 0.1.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.
- ironflock-0.1.0/LICENSE +21 -0
- ironflock-0.1.0/MANIFEST.in +6 -0
- ironflock-0.1.0/PKG-INFO +80 -0
- ironflock-0.1.0/README.md +67 -0
- ironflock-0.1.0/ironflock/AutobahnConnection.py +115 -0
- ironflock-0.1.0/ironflock/__init__.py +10 -0
- ironflock-0.1.0/ironflock/ironflock.py +166 -0
- ironflock-0.1.0/ironflock.egg-info/PKG-INFO +80 -0
- ironflock-0.1.0/ironflock.egg-info/SOURCES.txt +14 -0
- ironflock-0.1.0/ironflock.egg-info/dependency_links.txt +1 -0
- ironflock-0.1.0/ironflock.egg-info/requires.txt +1 -0
- ironflock-0.1.0/ironflock.egg-info/top_level.txt +1 -0
- ironflock-0.1.0/pyproject.toml +6 -0
- ironflock-0.1.0/requirements.txt +1 -0
- ironflock-0.1.0/setup.cfg +4 -0
- ironflock-0.1.0/setup.py +25 -0
ironflock-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Record Evolution
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ironflock-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ironflock
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Publishing data to a IronFlock Fleet Storage
|
|
5
|
+
Home-page: https://github.com/RecordEvolution/ironflock-python
|
|
6
|
+
Author: Record Evolution GmbH
|
|
7
|
+
Author-email: marko.petzold@record-evolution.de
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Python: >=3.6
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: autobahn[asyncio,compression,serialization]==22.3.2
|
|
13
|
+
|
|
14
|
+
# ironflock
|
|
15
|
+
|
|
16
|
+
## About
|
|
17
|
+
|
|
18
|
+
With this library you can publishing data to IronFlock fleet storage. When this library is used on a certain device the library automatically uses the private messaging realm (Unified Name Space) of the device's fleet and the data is collected in the respective fleet database.
|
|
19
|
+
|
|
20
|
+
So if you use the library in your app, the data collection will always be private to the app user's fleet.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import asyncio
|
|
26
|
+
from ironflock import IronFlock
|
|
27
|
+
|
|
28
|
+
# create a ironflock instance, which auto connects to the IronFlock Platform
|
|
29
|
+
# the ironflock instance handles authentication and reconnects when the connection is lost
|
|
30
|
+
rw = IronFlock()
|
|
31
|
+
|
|
32
|
+
async def main():
|
|
33
|
+
while True:
|
|
34
|
+
# publish an event (if connection is not established the publish is skipped)
|
|
35
|
+
publication = await rw.publish("test.publish.com", {"temperature": 20})
|
|
36
|
+
print(publication)
|
|
37
|
+
await asyncio.sleep(3)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
# run the main coroutine
|
|
42
|
+
asyncio.get_event_loop().create_task(main())
|
|
43
|
+
# run the ironflock component
|
|
44
|
+
rw.run()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Options
|
|
48
|
+
|
|
49
|
+
The `IronFlock` `__init__` function can be configured with the following options:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
{
|
|
53
|
+
serial_number: string;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**serial_number**: Used to set the serial_number of the device if the `DEVICE_SERIAL_NUMBER` environment variable does not exist. It can also be used if the user wishes to authenticate as another device.
|
|
58
|
+
|
|
59
|
+
## Advanced Usage
|
|
60
|
+
|
|
61
|
+
If you need more control, e.g. acting on lifecycle events (`onJoin`, `onLeave`) take a look at
|
|
62
|
+
the [examples](./examples/) folder.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
Install the necessary components if you don't have them already:
|
|
68
|
+
|
|
69
|
+
```shell
|
|
70
|
+
pip install --upgrade setuptools wheel twine
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Build and publish a new pypi package:
|
|
74
|
+
|
|
75
|
+
```shell
|
|
76
|
+
python setup.py sdist bdist_wheel
|
|
77
|
+
twine upload dist/*
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Check the package at https://pypi.org/project/ironflock/.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# ironflock
|
|
2
|
+
|
|
3
|
+
## About
|
|
4
|
+
|
|
5
|
+
With this library you can publishing data to IronFlock fleet storage. When this library is used on a certain device the library automatically uses the private messaging realm (Unified Name Space) of the device's fleet and the data is collected in the respective fleet database.
|
|
6
|
+
|
|
7
|
+
So if you use the library in your app, the data collection will always be private to the app user's fleet.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import asyncio
|
|
13
|
+
from ironflock import IronFlock
|
|
14
|
+
|
|
15
|
+
# create a ironflock instance, which auto connects to the IronFlock Platform
|
|
16
|
+
# the ironflock instance handles authentication and reconnects when the connection is lost
|
|
17
|
+
rw = IronFlock()
|
|
18
|
+
|
|
19
|
+
async def main():
|
|
20
|
+
while True:
|
|
21
|
+
# publish an event (if connection is not established the publish is skipped)
|
|
22
|
+
publication = await rw.publish("test.publish.com", {"temperature": 20})
|
|
23
|
+
print(publication)
|
|
24
|
+
await asyncio.sleep(3)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
# run the main coroutine
|
|
29
|
+
asyncio.get_event_loop().create_task(main())
|
|
30
|
+
# run the ironflock component
|
|
31
|
+
rw.run()
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Options
|
|
35
|
+
|
|
36
|
+
The `IronFlock` `__init__` function can be configured with the following options:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
{
|
|
40
|
+
serial_number: string;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**serial_number**: Used to set the serial_number of the device if the `DEVICE_SERIAL_NUMBER` environment variable does not exist. It can also be used if the user wishes to authenticate as another device.
|
|
45
|
+
|
|
46
|
+
## Advanced Usage
|
|
47
|
+
|
|
48
|
+
If you need more control, e.g. acting on lifecycle events (`onJoin`, `onLeave`) take a look at
|
|
49
|
+
the [examples](./examples/) folder.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
Install the necessary components if you don't have them already:
|
|
55
|
+
|
|
56
|
+
```shell
|
|
57
|
+
pip install --upgrade setuptools wheel twine
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Build and publish a new pypi package:
|
|
61
|
+
|
|
62
|
+
```shell
|
|
63
|
+
python setup.py sdist bdist_wheel
|
|
64
|
+
twine upload dist/*
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Check the package at https://pypi.org/project/ironflock/.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Tuple
|
|
3
|
+
from autobahn.asyncio.component import Component
|
|
4
|
+
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner
|
|
5
|
+
from autobahn.wamp import auth
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
SWARM_KEY = os.environ["SWARM_KEY"]
|
|
9
|
+
except:
|
|
10
|
+
raise Exception("Environment variable SWARM_KEY not set!")
|
|
11
|
+
|
|
12
|
+
CB_REALM = "userapps"
|
|
13
|
+
# CB_REALM = f"swarm{SWARM_KEY}"
|
|
14
|
+
|
|
15
|
+
DATAPODS_WS_URI = "wss://cbw.datapods.io/ws-ua-usr"
|
|
16
|
+
STUDIO_WS_URI_OLD = "wss://cbw.record-evolution.com/ws-ua-usr"
|
|
17
|
+
STUDIO_WS_URI = "wss://cbw.ironflock.com/ws-ua-usr"
|
|
18
|
+
LOCALHOST_WS_URI = "ws://localhost:8080/ws-ua-usr"
|
|
19
|
+
|
|
20
|
+
socketURIMap = {
|
|
21
|
+
"https://studio.datapods.io": DATAPODS_WS_URI,
|
|
22
|
+
"https://studio.record-evolution.com": STUDIO_WS_URI_OLD,
|
|
23
|
+
"https://studio.ironflock.com": STUDIO_WS_URI,
|
|
24
|
+
"http://localhost:8085": LOCALHOST_WS_URI,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def getWebSocketURI():
|
|
29
|
+
reswarm_url = os.environ.get("RESWARM_URL")
|
|
30
|
+
if not reswarm_url:
|
|
31
|
+
return STUDIO_WS_URI
|
|
32
|
+
return socketURIMap.get(reswarm_url)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def getSerialNumber(serial_number: str = None) -> str:
|
|
36
|
+
if serial_number is None:
|
|
37
|
+
s_num = os.environ.get("DEVICE_SERIAL_NUMBER")
|
|
38
|
+
if s_num is None:
|
|
39
|
+
raise Exception("ENV Variable 'DEVICE_SERIAL_NUMBER' is not set!")
|
|
40
|
+
else:
|
|
41
|
+
s_num = serial_number
|
|
42
|
+
return s_num
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AppSession(ApplicationSession):
|
|
46
|
+
serial_number: str = None
|
|
47
|
+
|
|
48
|
+
def onConnect(self):
|
|
49
|
+
print('onConnect called')
|
|
50
|
+
if self.serial_number is None:
|
|
51
|
+
raise Exception("serial_number missing on AppSession")
|
|
52
|
+
|
|
53
|
+
self.join(CB_REALM, ["wampcra"], self.serial_number)
|
|
54
|
+
|
|
55
|
+
def onChallenge(self, challenge):
|
|
56
|
+
print('challenge requested for {}'.format(challenge.method))
|
|
57
|
+
if challenge.method == "wampcra":
|
|
58
|
+
if self.serial_number is None:
|
|
59
|
+
raise Exception("serial_number missing on AppSession")
|
|
60
|
+
|
|
61
|
+
signature = auth.compute_wcs(
|
|
62
|
+
self.serial_number, challenge.extra["challenge"]
|
|
63
|
+
)
|
|
64
|
+
return signature
|
|
65
|
+
|
|
66
|
+
raise Exception("Invalid authmethod {}".format(challenge.method))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def create_application_session(
|
|
70
|
+
serial_number: str = None,
|
|
71
|
+
) -> Tuple[ApplicationSession, ApplicationRunner]:
|
|
72
|
+
"""Creates an Autobahn ApplicationSession and ApplicationRunner, which connects to the RE Platform
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
serial_number (str, optional): serial_number of device.
|
|
76
|
+
Defaults to None, in which case the environment variable DEVICE_SERIAL_NUMBER is used.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Tuple[ApplicationSession, ApplicationRunner]
|
|
80
|
+
"""
|
|
81
|
+
AppSession.serial_number = getSerialNumber(serial_number)
|
|
82
|
+
|
|
83
|
+
runner = ApplicationRunner(
|
|
84
|
+
url=getWebSocketURI(),
|
|
85
|
+
realm=CB_REALM,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
print('Application runner created')
|
|
89
|
+
|
|
90
|
+
return AppSession, runner
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def create_application_component(serial_number: str = None) -> Component:
|
|
94
|
+
"""Creates an Autobahn Component, which connects to the RE Platform
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
serial_number (str, optional): serial_number of device.
|
|
98
|
+
Defaults to None, in which case the environment variable DEVICE_SERIAL_NUMBER is used.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Component
|
|
102
|
+
"""
|
|
103
|
+
appSession, _ = create_application_session(serial_number)
|
|
104
|
+
|
|
105
|
+
comp = Component(
|
|
106
|
+
transports=[{
|
|
107
|
+
"url": getWebSocketURI(),
|
|
108
|
+
"serializers": ['msgpack'],
|
|
109
|
+
}],
|
|
110
|
+
realm=CB_REALM,
|
|
111
|
+
session_factory=appSession,
|
|
112
|
+
)
|
|
113
|
+
print('WAMP Component created')
|
|
114
|
+
|
|
115
|
+
return comp
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from ironflock.AutobahnConnection import (
|
|
2
|
+
create_application_component,
|
|
3
|
+
create_application_session,
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
from ironflock.ironflock import IronFlock
|
|
7
|
+
|
|
8
|
+
__all__ = ["IronFlock", "create_application_component", "create_application_session"]
|
|
9
|
+
|
|
10
|
+
__version__ = "0.0.19"
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from autobahn.asyncio.component import Component, run
|
|
4
|
+
from autobahn.wamp.interfaces import ISession
|
|
5
|
+
from autobahn.wamp.types import PublishOptions
|
|
6
|
+
from autobahn.wamp.request import Publication
|
|
7
|
+
|
|
8
|
+
from ironflock.AutobahnConnection import getSerialNumber, create_application_component
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class IronFlock:
|
|
12
|
+
"""Convenience class for easy to use message publishing to the RE platform.
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
|
|
16
|
+
rw = IronFlock()
|
|
17
|
+
|
|
18
|
+
async def main():
|
|
19
|
+
while True:
|
|
20
|
+
publication = await rw.publish("test.publish.pw", 1, "two", 3, foo="bar")
|
|
21
|
+
print(publication)
|
|
22
|
+
await asyncio.sleep(3)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
asyncio.get_event_loop().create_task(main())
|
|
27
|
+
rw.run()
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, serial_number: str = None, mainFunc=None) -> None:
|
|
31
|
+
"""Creates IronFlock Instance
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
serial_number (str, optional): serial_number of device.
|
|
35
|
+
Defaults to None, in which case the environment variable DEVICE_SERIAL_NUMBER is used.
|
|
36
|
+
"""
|
|
37
|
+
self._serial_number = getSerialNumber(serial_number)
|
|
38
|
+
self._device_name = os.environ.get("DEVICE_NAME")
|
|
39
|
+
self._component = create_application_component(serial_number)
|
|
40
|
+
self._session: ISession = None
|
|
41
|
+
self.mainFunc = mainFunc
|
|
42
|
+
|
|
43
|
+
@self._component.on_join
|
|
44
|
+
async def onJoin(session, details):
|
|
45
|
+
print("component joined")
|
|
46
|
+
self._session = session
|
|
47
|
+
if self.mainFunc:
|
|
48
|
+
await self.mainFunc(session)
|
|
49
|
+
|
|
50
|
+
@self._component.on_disconnect
|
|
51
|
+
def onDisconnect(*args, **kwargs):
|
|
52
|
+
print("component disconnected")
|
|
53
|
+
self._session = None
|
|
54
|
+
|
|
55
|
+
@self._component.on_leave
|
|
56
|
+
def onLeave(*args, **kwargs):
|
|
57
|
+
print("component left")
|
|
58
|
+
self._session = None
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def component(self) -> Component:
|
|
62
|
+
"""The Autobahn Component
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Component
|
|
66
|
+
"""
|
|
67
|
+
return self._component
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def session(self) -> Optional[ISession]:
|
|
71
|
+
"""The Autobahn Session
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Optional[ISession]
|
|
75
|
+
"""
|
|
76
|
+
return self._session
|
|
77
|
+
|
|
78
|
+
async def publish(self, topic: str, *args, **kwargs) -> Optional[Publication]:
|
|
79
|
+
"""Publishes to the RE Platform Message Router
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
topic (str): The URI of the topic to publish to, e.g. "com.myapp.mytopic1"
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Optional[Publication]: Object representing a publication
|
|
86
|
+
(feedback from publishing an event when doing an acknowledged publish)
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
extra = {
|
|
90
|
+
"DEVICE_SERIAL_NUMBER": self._serial_number,
|
|
91
|
+
"DEVICE_NAME": self._device_name,
|
|
92
|
+
"options": PublishOptions(acknowledge=True),
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if self._session is not None:
|
|
96
|
+
pub = await self._session.publish(topic, *args, **kwargs, **extra)
|
|
97
|
+
return pub
|
|
98
|
+
else:
|
|
99
|
+
print("cannot publish, not connected")
|
|
100
|
+
|
|
101
|
+
async def set_device_location(self, long: float, lat: float):
|
|
102
|
+
"""Update the location of the device registered in the platform
|
|
103
|
+
This will update the device's location in the master data of the platform.
|
|
104
|
+
The maps in the device or group overviews will reflect the new device location in realtime.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
payload = {
|
|
108
|
+
"long": long,
|
|
109
|
+
"lat": lat
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
extra = {
|
|
113
|
+
"DEVICE_SERIAL_NUMBER": self._serial_number,
|
|
114
|
+
"DEVICE_NAME": self._device_name
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if hasattr(self, "_session") and hasattr(self._session, "call"):
|
|
118
|
+
res = await self._session.call('ironflock.location_service.update', payload, **extra)
|
|
119
|
+
return res
|
|
120
|
+
|
|
121
|
+
async def publish_to_table(
|
|
122
|
+
self, tablename: str, *args, **kwargs
|
|
123
|
+
) -> Optional[Publication]:
|
|
124
|
+
"""Publishes Data to a Table in the RE Platform
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
tablename (str): The table name of the table to publish to, e.g. "sensordata"
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Optional[Publication]: Object representing a publication
|
|
131
|
+
(feedback from publishing an event when doing an acknowledged publish)
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
if not tablename:
|
|
135
|
+
raise Exception("Tablename must not be None or empty string!")
|
|
136
|
+
|
|
137
|
+
swarm_key = os.environ.get("SWARM_KEY")
|
|
138
|
+
app_key = os.environ.get("APP_KEY")
|
|
139
|
+
env_value = os.environ.get("ENV")
|
|
140
|
+
|
|
141
|
+
if swarm_key is None:
|
|
142
|
+
raise Exception("Environment variable SWARM_KEY not set!")
|
|
143
|
+
|
|
144
|
+
if app_key is None:
|
|
145
|
+
raise Exception("Environment variable APP_KEY not set!")
|
|
146
|
+
|
|
147
|
+
if env_value is None:
|
|
148
|
+
raise Exception("Environment variable ENV not set!")
|
|
149
|
+
|
|
150
|
+
if not env_value in ["DEV", "PROD"]:
|
|
151
|
+
raise Exception("Environment variable ENV must be 'PROD' or 'DEV'!")
|
|
152
|
+
|
|
153
|
+
if env_value == "PROD":
|
|
154
|
+
topic = f"{swarm_key}.{app_key}.{tablename}"
|
|
155
|
+
else:
|
|
156
|
+
topic = f"dev.{swarm_key}.{app_key}.{tablename}"
|
|
157
|
+
|
|
158
|
+
pub = await self.publish(topic, *args, **kwargs)
|
|
159
|
+
return pub
|
|
160
|
+
|
|
161
|
+
def run(self, wait=True):
|
|
162
|
+
"""Runs the Component in the asyncio event loop."""
|
|
163
|
+
if wait:
|
|
164
|
+
run([self._component])
|
|
165
|
+
else:
|
|
166
|
+
return self._component.start()
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ironflock
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Publishing data to a IronFlock Fleet Storage
|
|
5
|
+
Home-page: https://github.com/RecordEvolution/ironflock-python
|
|
6
|
+
Author: Record Evolution GmbH
|
|
7
|
+
Author-email: marko.petzold@record-evolution.de
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Python: >=3.6
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: autobahn[asyncio,compression,serialization]==22.3.2
|
|
13
|
+
|
|
14
|
+
# ironflock
|
|
15
|
+
|
|
16
|
+
## About
|
|
17
|
+
|
|
18
|
+
With this library you can publishing data to IronFlock fleet storage. When this library is used on a certain device the library automatically uses the private messaging realm (Unified Name Space) of the device's fleet and the data is collected in the respective fleet database.
|
|
19
|
+
|
|
20
|
+
So if you use the library in your app, the data collection will always be private to the app user's fleet.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import asyncio
|
|
26
|
+
from ironflock import IronFlock
|
|
27
|
+
|
|
28
|
+
# create a ironflock instance, which auto connects to the IronFlock Platform
|
|
29
|
+
# the ironflock instance handles authentication and reconnects when the connection is lost
|
|
30
|
+
rw = IronFlock()
|
|
31
|
+
|
|
32
|
+
async def main():
|
|
33
|
+
while True:
|
|
34
|
+
# publish an event (if connection is not established the publish is skipped)
|
|
35
|
+
publication = await rw.publish("test.publish.com", {"temperature": 20})
|
|
36
|
+
print(publication)
|
|
37
|
+
await asyncio.sleep(3)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
# run the main coroutine
|
|
42
|
+
asyncio.get_event_loop().create_task(main())
|
|
43
|
+
# run the ironflock component
|
|
44
|
+
rw.run()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Options
|
|
48
|
+
|
|
49
|
+
The `IronFlock` `__init__` function can be configured with the following options:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
{
|
|
53
|
+
serial_number: string;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**serial_number**: Used to set the serial_number of the device if the `DEVICE_SERIAL_NUMBER` environment variable does not exist. It can also be used if the user wishes to authenticate as another device.
|
|
58
|
+
|
|
59
|
+
## Advanced Usage
|
|
60
|
+
|
|
61
|
+
If you need more control, e.g. acting on lifecycle events (`onJoin`, `onLeave`) take a look at
|
|
62
|
+
the [examples](./examples/) folder.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
Install the necessary components if you don't have them already:
|
|
68
|
+
|
|
69
|
+
```shell
|
|
70
|
+
pip install --upgrade setuptools wheel twine
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Build and publish a new pypi package:
|
|
74
|
+
|
|
75
|
+
```shell
|
|
76
|
+
python setup.py sdist bdist_wheel
|
|
77
|
+
twine upload dist/*
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Check the package at https://pypi.org/project/ironflock/.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
requirements.txt
|
|
6
|
+
setup.py
|
|
7
|
+
ironflock/AutobahnConnection.py
|
|
8
|
+
ironflock/__init__.py
|
|
9
|
+
ironflock/ironflock.py
|
|
10
|
+
ironflock.egg-info/PKG-INFO
|
|
11
|
+
ironflock.egg-info/SOURCES.txt
|
|
12
|
+
ironflock.egg-info/dependency_links.txt
|
|
13
|
+
ironflock.egg-info/requires.txt
|
|
14
|
+
ironflock.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
autobahn[asyncio,compression,serialization]==22.3.2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ironflock
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
autobahn[asyncio, serialization, compression]==22.3.2
|
ironflock-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
requirements = []
|
|
4
|
+
with open("requirements.txt", "r") as fh:
|
|
5
|
+
for line in fh:
|
|
6
|
+
requirements.append(line.strip())
|
|
7
|
+
|
|
8
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
9
|
+
long_description = fh.read()
|
|
10
|
+
|
|
11
|
+
setup(
|
|
12
|
+
name="ironflock",
|
|
13
|
+
version="0.1.0",
|
|
14
|
+
description="Publishing data to a IronFlock Fleet Storage",
|
|
15
|
+
long_description=long_description,
|
|
16
|
+
long_description_content_type="text/markdown",
|
|
17
|
+
url="https://github.com/RecordEvolution/ironflock-python",
|
|
18
|
+
author="Record Evolution GmbH",
|
|
19
|
+
author_email="marko.petzold@record-evolution.de",
|
|
20
|
+
packages=find_packages(),
|
|
21
|
+
license="MIT",
|
|
22
|
+
python_requires=">=3.6",
|
|
23
|
+
install_requires=requirements,
|
|
24
|
+
classifiers=[],
|
|
25
|
+
)
|