xaal.lib 0.7.2__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.
xaal/lib/network.py ADDED
@@ -0,0 +1,100 @@
1
+ #
2
+ # Copyright 2014, Jérôme Colin, Jérôme Kerdreux, Philippe Tanguy,
3
+ # Telecom Bretagne.
4
+ #
5
+ # This file is part of xAAL.
6
+ #
7
+ # xAAL is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # xAAL is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with xAAL. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ import socket
22
+ import struct
23
+ import select
24
+ import logging
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ import time
29
+ from enum import Enum
30
+
31
+ class NetworkState(Enum):
32
+ disconnected = 0
33
+ connected = 1
34
+
35
+
36
+ class NetworkConnector(object):
37
+ UDP_MAX_SIZE = 65507
38
+
39
+ def __init__(self, addr, port, hops,bind_addr='0.0.0.0'):
40
+ self.addr = addr
41
+ self.port = port
42
+ self.hops = hops
43
+ self.bind_addr = bind_addr
44
+ self.state = NetworkState.disconnected
45
+
46
+ def connect(self):
47
+ try:
48
+ self.__connect()
49
+ except Exception as e:
50
+ self.network_error(e)
51
+
52
+ def __connect(self):
53
+ logger.info("Connecting to %s:%s" % (self.addr, self.port))
54
+
55
+ self.__sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)
56
+ self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
57
+ # #formac os ???
58
+ #self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
59
+ self.__sock.bind((self.bind_addr, self.port))
60
+ mreq = struct.pack("=4s4s",socket.inet_aton(self.addr),socket.inet_aton(self.bind_addr))
61
+ self.__sock.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,mreq)
62
+ self.__sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL,self.hops)
63
+ self.state = NetworkState.connected
64
+
65
+ def disconnect(self):
66
+ logger.info("Disconnecting from the bus")
67
+ self.state = NetworkState.disconnected
68
+ self.__sock.close()
69
+
70
+ def is_connected(self):
71
+ return self.state == NetworkState.connected
72
+
73
+ def receive(self):
74
+ packt = self.__sock.recv(self.UDP_MAX_SIZE)
75
+ return packt
76
+
77
+ def __get_data(self):
78
+ r = select.select([self.__sock, ], [], [], 0.02)
79
+ if r[0]:
80
+ return self.receive()
81
+ return None
82
+
83
+ def get_data(self):
84
+ if not self.is_connected(): self.connect()
85
+ try:
86
+ return self.__get_data()
87
+ except Exception as e:
88
+ self.network_error(e)
89
+
90
+ def send(self,data):
91
+ if not self.is_connected(): self.connect()
92
+ try:
93
+ self.__sock.sendto(data, (self.addr, self.port))
94
+ except Exception as e:
95
+ self.network_error(e)
96
+
97
+ def network_error(self, msg):
98
+ self.disconnect()
99
+ logger.info("Network error, reconnect..%s" % msg)
100
+ time.sleep(5)
xaal/lib/test.py ADDED
@@ -0,0 +1,140 @@
1
+
2
+
3
+ import xaal.lib
4
+ from xaal.lib import tools
5
+
6
+
7
+ import logging
8
+
9
+
10
+ ADDR="b8bec7ca-f955-11e6-9031-82ed25e6aaaa"
11
+ ADDR=tools.get_random_uuid()
12
+
13
+ def dump_hex(name,data):
14
+ print("%s : " % name,end='=')
15
+ for k in data:
16
+ if type(k) == int:
17
+ print("%x"%k,end=' ')
18
+ else:
19
+ print("%x"%ord(k),end=' ')
20
+ print()
21
+
22
+ def test_pysodium():
23
+ from xaal.lib import messages
24
+ import pysodium
25
+
26
+ payload = "FooBar".encode("utf-8")
27
+ ad = '[]'
28
+
29
+ data = messages.build_timestamp()
30
+ nonce = messages.build_nonce(data)
31
+ key = tools.pass2key("My Friend Goo")
32
+
33
+ dump_hex("Payload",payload)
34
+ dump_hex("Key",key)
35
+
36
+ ciph = pysodium.crypto_aead_chacha20poly1305_encrypt(payload, ad, nonce, key)
37
+ dump_hex("Ciph",ciph)
38
+
39
+ pjson = pysodium.crypto_aead_chacha20poly1305_decrypt(ciph, ad, nonce, key)
40
+ print(pjson)
41
+
42
+
43
+ def test_device():
44
+ from xaal.lib.devices import Device
45
+ addr = ADDR
46
+ dev = Device("foo.basic",addr)
47
+ dev.vendor_id = "ACME"
48
+ dev.url="http://acmefactory.blogspot.fr/"
49
+ dev.hw_id = "0x201"
50
+ print(dev.getDescription())
51
+ return dev
52
+
53
+ def test_msg():
54
+ from xaal.lib.messages import Message
55
+ msg = Message()
56
+ addr = ADDR
57
+ msg.targets = [addr,]
58
+ msg.dump()
59
+
60
+ def test_encode():
61
+ from xaal.lib.messages import MessageFactory
62
+ key = tools.pass2key("FooBar")
63
+ factory = MessageFactory(key)
64
+ m2 = factory.build_msg()
65
+ print(factory.decode_msg(m2))
66
+
67
+ def test_log():
68
+ logger = logging.getLogger(__name__)
69
+ logger.info("This is an INFO msg")
70
+ logger.debug("This is an DEBUG msg")
71
+
72
+
73
+ def test_engine():
74
+ from xaal.lib.core import Engine
75
+ engine = Engine()
76
+ engine.run()
77
+
78
+ def test_alive():
79
+ addr = ADDR
80
+ dev = xaal.lib.Device("test.basic",addr)
81
+ eng = xaal.lib.Engine()
82
+ eng.add_devices([dev,])
83
+ eng.run()
84
+
85
+ def test_crypto_decoding_error():
86
+ addr = ADDR
87
+ dev = xaal.lib.Device("test.basic",addr)
88
+ eng = xaal.lib.Engine()
89
+ eng.add_devices([dev,])
90
+ eng.msg_factory.cipher_key = tools.pass2key("FakeKey")
91
+ eng.start()
92
+ eng.loop()
93
+
94
+
95
+ def test_attr():
96
+ dev = xaal.lib.Device("test.basic",ADDR)
97
+ dev.url = "http://linux.org"
98
+ dev.vendor_id = "ACME"
99
+ dev.product_id = "Full Fake Device"
100
+ dev.info = "FooBar"
101
+ dev.hw_id = "ffd0001"
102
+ #dev.alive_period = 100
103
+
104
+ attr0 = dev.new_attribute("attr0",10)
105
+ attr1 = dev.new_attribute("attr1",False)
106
+
107
+ eng = xaal.lib.Engine()
108
+ eng.add_devices([dev,])
109
+
110
+ def update():
111
+ attr0.value = attr0.value + 1
112
+
113
+ eng.add_timer(update,60)
114
+
115
+ #eng.loop()
116
+ eng.run()
117
+
118
+
119
+
120
+ def run():
121
+
122
+ logger = tools.get_logger(__name__,logging.DEBUG,"%s.log" % __name__)
123
+ #test_pysodium()
124
+ #test_device()
125
+ #test_msg()
126
+ #test_encode()
127
+ #test_log()
128
+ #test_alive()
129
+ #test_crypto_decoding_error()
130
+ test_attr()
131
+
132
+
133
+
134
+ if __name__ == '__main__':
135
+ try:
136
+ run()
137
+ except KeyboardInterrupt:
138
+ print("Bye bye...")
139
+
140
+
xaal/lib/tools.py ADDED
@@ -0,0 +1,130 @@
1
+ #
2
+ # Copyright 2014, Jérôme Colin, Jérôme Kerdreux, Philippe Tanguy,
3
+ # Telecom Bretagne.
4
+ #
5
+ # This file is part of xAAL.
6
+ #
7
+ # xAAL is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # xAAL is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with xAAL. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ import os
22
+ import re
23
+
24
+ import pysodium
25
+
26
+ import sys
27
+ import functools
28
+ from configobj import ConfigObj
29
+
30
+ from . import config
31
+ from .bindings import UUID
32
+
33
+ XAAL_DEVTYPE_PATTERN = '^[a-zA-Z][a-zA-Z0-9_-]*\.[a-zA-Z][a-zA-Z0-9_-]*$'
34
+
35
+ def get_cfg_filename(name, cfg_dir=config.conf_dir):
36
+ if name.startswith('xaal.'):
37
+ name = name[5:]
38
+ filename = '%s.ini' % name
39
+ if not os.path.isdir(cfg_dir):
40
+ print("Your configuration directory doesn't exist: [%s]" % cfg_dir)
41
+ return os.path.join(cfg_dir, filename)
42
+
43
+ def load_cfg_file(filename):
44
+ """ load .ini file and return it as dict"""
45
+ if os.path.isfile(filename):
46
+ return ConfigObj(filename,indent_type=' ',encoding="utf8")
47
+ return None
48
+
49
+ def load_cfg(app_name):
50
+ filename = get_cfg_filename(app_name)
51
+ return load_cfg_file(filename)
52
+
53
+ def load_cfg_or_die(app_name):
54
+ cfg = load_cfg(app_name)
55
+ if not cfg:
56
+ print("Unable to load config file %s" % get_cfg_filename(app_name))
57
+ sys.exit(-1)
58
+ return cfg
59
+
60
+ def new_cfg(app_name):
61
+ filename = get_cfg_filename(app_name)
62
+ cfg = ConfigObj(filename,indent_type=' ')
63
+ cfg['config'] = {}
64
+ cfg['config']['addr']=get_random_uuid().str
65
+ return cfg
66
+
67
+ def get_random_uuid():
68
+ return UUID.random()
69
+
70
+ def get_random_base_uuid(digit=2):
71
+ return UUID.random_base(digit)
72
+
73
+ def get_uuid(val):
74
+ if isinstance(val,UUID):
75
+ return val
76
+ if isinstance(val,str):
77
+ return str_to_uuid(val)
78
+ return None
79
+
80
+ def str_to_uuid(val):
81
+ """ return an xAAL address for a given string"""
82
+ try:
83
+ return UUID(val)
84
+ except ValueError:
85
+ return None
86
+
87
+ def bytes_to_uuid(val):
88
+ try:
89
+ return UUID(bytes=val)
90
+ except ValueError:
91
+ return None
92
+
93
+ def is_valid_uuid(val):
94
+ return isinstance(val,UUID)
95
+
96
+ def is_valid_address(val):
97
+ return is_valid_uuid(val)
98
+
99
+ @functools.lru_cache(maxsize=128)
100
+ def is_valid_dev_type(val):
101
+ if not isinstance(val,str):
102
+ return False
103
+ if re.match(XAAL_DEVTYPE_PATTERN,val):
104
+ return True
105
+ return False
106
+
107
+ def pass2key(passphrase):
108
+ """Generate key from passphrase using libsodium
109
+ crypto_pwhash_scryptsalsa208sha256 func
110
+ salt: buffer of zeros
111
+ opslimit: crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE
112
+ memlimit: crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE
113
+ """
114
+ buf = passphrase.encode('utf-8')
115
+ KEY_BYTES = pysodium.crypto_pwhash_scryptsalsa208sha256_SALTBYTES #32
116
+ # this should be:
117
+ # salt = bytes(KEY_BYTES)
118
+ # but due to bytes() stupid stuff in py2 we need this awfull stuff
119
+ salt = ('\00' * KEY_BYTES).encode('utf-8')
120
+ opslimit = pysodium.crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE
121
+ memlimit = pysodium.crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE
122
+ key = pysodium.crypto_pwhash_scryptsalsa208sha256(KEY_BYTES, buf, salt, opslimit, memlimit)
123
+ return key
124
+
125
+ @functools.lru_cache(maxsize=128)
126
+ def reduce_addr(addr):
127
+ """return a string based addred without all digits"""
128
+ tmp = addr.str
129
+ return tmp[:5] + '..' + tmp[-5:]
130
+
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.1
2
+ Name: xaal.lib
3
+ Version: 0.7.2
4
+ Summary: xaal.lib is the official Python stack of xAAL protocol dedicated to home automation systems
5
+ Author-email: Jerome Kerdreux <Jerome.Kerdreux@imt-atlantique.fr>
6
+ License: GPL License
7
+ Keywords: xaal,home-automation
8
+ Classifier: Programming Language :: Python
9
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
10
+ Description-Content-Type: text/x-rst
11
+ Requires-Dist: cbor2 ==5.4.2
12
+ Requires-Dist: pysodium
13
+ Requires-Dist: configobj
14
+ Requires-Dist: coloredlogs
15
+ Requires-Dist: decorator
16
+ Requires-Dist: tabulate
17
+ Requires-Dist: aioconsole
18
+
19
+
20
+ xaal.lib
21
+ ========
22
+ **xaal.lib** is the official Python stack to develop home-automation devices and gateways
23
+ with the xAAL protocol. For a full description of the protocol check out
24
+ http://recherche.imt-atlantique.fr/xaal/
25
+
26
+
27
+ Dependencies
28
+ ~~~~~~~~~~~~
29
+ xaal.lib depends on :
30
+ * cbor2
31
+ * pysodium
32
+ * configobj
33
+ * coloredlogs
34
+ * decorator
35
+ * tabulate
36
+ * aioconsole
37
+
38
+
39
+ Install
40
+ ~~~~~~~
41
+ Please refer to the official `full documentation to install the lib in a virtualenv
42
+ <https://redmine.telecom-bretagne.eu/svn/xaal/code/Python/branches/0.7/README.html>`_
43
+
44
+
45
+ Usage
46
+ ~~~~~
47
+ The main goal of xaal.lib is to provide an API to easily develop devices & gateways.
48
+ **xaal.lib.Engine send / receive / parse to|from xAAL Bus**.
49
+
50
+
51
+ To receive / parse / display incoming xAAL messages, you can simply try something like
52
+ this:
53
+
54
+ .. code-block:: python
55
+
56
+ from xaal.lib import Engine
57
+
58
+ def display(msg):
59
+ print(msg)
60
+
61
+ eng = Engine()
62
+ eng.subscribe(display)
63
+ eng.run()
64
+
65
+ The Engine will call the display function every time it receive a xAAL message.
66
+
67
+ Let's take a look at a simple lamp device :
68
+
69
+ .. code-block:: python
70
+
71
+ from xaal.lib import Device,Engine,tools
72
+
73
+ # create and configure the lamp device, with a random address
74
+ dev = Device("lamp.basic", tools.get_random_uuid())
75
+ dev.product_id = 'Dummy Lamp'
76
+ dev.url = 'http://www.acme.org'
77
+ dev.info = 'My fake lamp'
78
+
79
+ # add an xAAL attribute 'light'
80
+ light = dev.new_attribute('light')
81
+
82
+ # declare two device methods ON & OFF
83
+ def on():
84
+ light.value = True
85
+
86
+ def off():
87
+ light.value = False
88
+
89
+ dev.add_method('turn_on',on)
90
+ dev.add_method('turn_off',off)
91
+
92
+ # last step, create an engine and register the lamp
93
+ eng = Engine()
94
+ eng.add_device(dev)
95
+ eng.run()
96
+
97
+
98
+ FAQ
99
+ ~~~
100
+ The core engine run forever so how can I use it in webserver, GUI or to develop device
101
+ with IO. The whole API is absolutely not thread safe, so **don't use threads** unless you
102
+ exactly know what's going on. Anyways, you have several options to fix this issue:
103
+
104
+ * You can use you own loop and periodically call *eng.loop()*
105
+ for example, you can do something like this:
106
+
107
+ .. code:: python
108
+
109
+ while 1:
110
+ do_some_stuff()
111
+ eng.loop()
112
+
113
+ * You can use a engine timer, to perform some stuff.
114
+
115
+ .. code:: python
116
+
117
+ def read_io():
118
+ pass
119
+
120
+ # call the read_io function every 10 sec
121
+ eng.add_timer(read_io,10)
122
+ eng.run()
123
+
124
+ * Use the **AsyncEngine**. Python version > 3.8 provides async programming with **asyncio** package.
125
+ *AsyncEngine* use the same API as *Engine*, but it is a **asynchronous** engine. You can use
126
+ *coroutines* in device methods, timers functions and callbacks. It provides additionals features
127
+ like the *on_start* and *on_stop* callbacks.
128
+
129
+ * Use an alternate coroutine lib, you can use **gevent** or **greenlet** for example. Look at
130
+ apps/rest for a simple greenlet example.
131
+
@@ -0,0 +1,22 @@
1
+ xaal/__init__.py,sha256=jv2YF__bseklT3OWEzlqJ5qE24c4aWd5F4r0TTjOrWQ,65
2
+ xaal/lib/__init__.py,sha256=MMXBicq9vNn6yCzBPcqZfTXk329NEL-qTM95jXUMymE,471
3
+ xaal/lib/__main__.py,sha256=xsVqqoIh3UeJIXxeexSfmGSUP4YxUcibdZExjEzk4lE,30
4
+ xaal/lib/aioengine.py,sha256=3MTG9aGKekVvsWhYaehZqZem6YmPng4UqGfDoRTaC2E,13100
5
+ xaal/lib/aiohelpers.py,sha256=2a310wSXzbg9SGYzrTfcHbaZ8PWEe9rLteDmS2i62kU,1007
6
+ xaal/lib/aionetwork.py,sha256=pH-5kf8o4FHsbvs-oFf5guAgYaEu0aosyTuI3k8xt2M,2484
7
+ xaal/lib/bindings.py,sha256=EkDJJ_iBQbC7UzsjHfoXAjpGSwC613hrIm5ubrkcw4k,1994
8
+ xaal/lib/cbor.py,sha256=hWE-mfwhzYQVZ1-JWyx2vy0Sl96Pv6KV7qaN_nf_DxE,1666
9
+ xaal/lib/config.py,sha256=jNAEXCswWsKrVab3hycupQn4aYt4c61eq628ow_I2ZI,1736
10
+ xaal/lib/core.py,sha256=VfaisNREUse-zMrilJuKf6NLVO9HugL1U_I4M7BFzKQ,10806
11
+ xaal/lib/devices.py,sha256=ZDNVNVmJ26W2atuNkzB7xtYZQAT3dWTrQCvMCDMSVWA,9574
12
+ xaal/lib/engine.py,sha256=p2of6IPQB0It0RNu5fkJHHp615K_2rgzHfuWOpvJ6Is,7539
13
+ xaal/lib/exceptions.py,sha256=ZKDKGlm_F48K_0NlaV1fa0Z-a4ZnOxT7NU8c8MKSJAc,504
14
+ xaal/lib/helpers.py,sha256=mXxVxv7fTV9O9xO1BROhVYBTmdviMl6qx3Il8q1ox8w,2679
15
+ xaal/lib/messages.py,sha256=cLwplLp_0qmlgZi6ByohvLEcmuxpWK7liE5dpqyV9AM,11552
16
+ xaal/lib/network.py,sha256=3HWuQ0afQ-X6_-En2rFeqYJ0Scy5IEHfd0qTldxxCFo,3130
17
+ xaal/lib/test.py,sha256=laVbgG4HtQquxDzixAG-Cka-HO4kpb7YUsLL267mGPU,3006
18
+ xaal/lib/tools.py,sha256=SnXmOkeTd4eTN8yWn-GyCkV5mYiG-MX4hkF39KnogLE,3841
19
+ xaal.lib-0.7.2.dist-info/METADATA,sha256=nOxqYAIqm40VUe4t2-22728LE5yL_PfxRlXjbQaI_X0,3545
20
+ xaal.lib-0.7.2.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
21
+ xaal.lib-0.7.2.dist-info/top_level.txt,sha256=UZ2WDkN02ztkh1OrsjrW8Kmj4n3WqC0BQxaEYOYfWa0,5
22
+ xaal.lib-0.7.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (70.3.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ xaal