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.
@@ -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.
@@ -0,0 +1,6 @@
1
+ include MANIFEST.in
2
+ include setup.py
3
+ include *.cfg
4
+ include *.ini
5
+ include *.txt
6
+ include requirements.txt
@@ -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
+ autobahn[asyncio,compression,serialization]==22.3.2
@@ -0,0 +1 @@
1
+ ironflock
@@ -0,0 +1,6 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=42",
4
+ "wheel"
5
+ ]
6
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1 @@
1
+ autobahn[asyncio, serialization, compression]==22.3.2
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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
+ )