tinytoolslib 0.2.5__tar.gz → 0.3.2__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.
- tinytoolslib-0.3.2/PKG-INFO +37 -0
- tinytoolslib-0.3.2/README.md +21 -0
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/pyproject.toml +1 -1
- tinytoolslib-0.3.2/tinytoolslib/__init__.py +4 -0
- tinytoolslib-0.3.2/tinytoolslib/__version__.py +1 -0
- tinytoolslib-0.3.2/tinytoolslib/constants.py +40 -0
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib/discovery.py +62 -91
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib/flash.py +166 -65
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib/models.py +97 -78
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib/requests.py +53 -32
- tinytoolslib-0.3.2/tinytoolslib.egg-info/PKG-INFO +37 -0
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib.egg-info/top_level.txt +2 -0
- tinytoolslib-0.2.5/PKG-INFO +0 -76
- tinytoolslib-0.2.5/README.md +0 -60
- tinytoolslib-0.2.5/tinytoolslib/__init__.py +0 -1
- tinytoolslib-0.2.5/tinytoolslib/__version__.py +0 -1
- tinytoolslib-0.2.5/tinytoolslib/constants.py +0 -14
- tinytoolslib-0.2.5/tinytoolslib.egg-info/PKG-INFO +0 -76
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/setup.cfg +0 -0
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib/exceptions.py +0 -0
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib/parsers.py +0 -0
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib.egg-info/SOURCES.txt +0 -0
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib.egg-info/dependency_links.txt +0 -0
- {tinytoolslib-0.2.5 → tinytoolslib-0.3.2}/tinytoolslib.egg-info/requires.txt +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: tinytoolslib
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: Set of tools for use with Tinycontrol devices like LK2.X, LK3.X, LK4.X or tcPDU.
|
|
5
|
+
Author-email: Bartek Barszczewski <tinycontrol.software@gmail.com>
|
|
6
|
+
Keywords: tinycontrol,lk,tcpdu
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
+
Requires-Python: >=3.7
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: aiohttp<4,>=3.9.3
|
|
13
|
+
Requires-Dist: netifaces<1,>=0.11.0
|
|
14
|
+
Requires-Dist: requests<3,>=2.31.0
|
|
15
|
+
Requires-Dist: tftpy<1,>=0.8.2
|
|
16
|
+
|
|
17
|
+
# tinyToolsLib
|
|
18
|
+
|
|
19
|
+
Set of tools for use with tinycontrol devices like LK2.X, LK3.X, LK4.X or tcPDU.
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
Easy to use functions for common actions with tinycontrol devices:
|
|
24
|
+
|
|
25
|
+
- Flashing firmware via TFTP (LK2.X, LK3.X).
|
|
26
|
+
- Flashing firmware via HTTP (LK4, tcPDU).
|
|
27
|
+
- Getting data from devices.
|
|
28
|
+
- Sending commands to devices (for common tasks like controlling OUTs, PWMs, etc.).
|
|
29
|
+
- Checking device version.
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
Usage is described in documentation.
|
|
34
|
+
|
|
35
|
+
## Documentation
|
|
36
|
+
|
|
37
|
+
Documentation is available at <https://tinycontrol-software.gitlab.io/tinytoolslib/>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# tinyToolsLib
|
|
2
|
+
|
|
3
|
+
Set of tools for use with tinycontrol devices like LK2.X, LK3.X, LK4.X or tcPDU.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
Easy to use functions for common actions with tinycontrol devices:
|
|
8
|
+
|
|
9
|
+
- Flashing firmware via TFTP (LK2.X, LK3.X).
|
|
10
|
+
- Flashing firmware via HTTP (LK4, tcPDU).
|
|
11
|
+
- Getting data from devices.
|
|
12
|
+
- Sending commands to devices (for common tasks like controlling OUTs, PWMs, etc.).
|
|
13
|
+
- Checking device version.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Usage is described in documentation.
|
|
18
|
+
|
|
19
|
+
## Documentation
|
|
20
|
+
|
|
21
|
+
Documentation is available at <https://tinycontrol-software.gitlab.io/tinytoolslib/>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.3.2'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Constants related to tinycontrol devices."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
LK_UDP_PORT = 30403
|
|
7
|
+
"""Port for UDP commands"""
|
|
8
|
+
|
|
9
|
+
LK_UDP_DISCOVERY_MSG = b"Discovery: Who is out there?"
|
|
10
|
+
"""Message for Discovery query"""
|
|
11
|
+
|
|
12
|
+
LK_UDP_BOOTLOADER_MSG = b"\x12\xf4\x81"
|
|
13
|
+
"""Message for starting bootloader/restart device"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
FW_URL_TEMPLATE = "https://tinycontrol.pl/firmware/{}/latest/"
|
|
17
|
+
"""URL format for getting information about firmware from tinycontrol.pl"""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FWUpdateMethod(str, Enum):
|
|
21
|
+
"""Method used for updating FW.
|
|
22
|
+
|
|
23
|
+
HTTP - for LK4, tcPDU (generally ESP32 based ones)
|
|
24
|
+
TFTP - for LK3.5, LK3, LK2.5, LK2
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
TFTP = "TFTP"
|
|
28
|
+
HTTP = "HTTP"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DeviceFamily(str, Enum):
|
|
32
|
+
"""Device families.
|
|
33
|
+
|
|
34
|
+
PS and DCDC are pretty much the same as LK (UI differs)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
LK = "LK"
|
|
38
|
+
PS = "PS" # Power socket
|
|
39
|
+
DCDC = "DCDC" # Converter DC/DC
|
|
40
|
+
TCPDU = "tcPDU"
|
|
@@ -1,99 +1,20 @@
|
|
|
1
|
+
"""Discovery function for finding tinycontrol devices in the network.
|
|
2
|
+
|
|
3
|
+
Works with LK4, tcPPDU, LK3.5 SW 1.26+, LK2.5, LK2.0.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
import concurrent.futures
|
|
2
7
|
import logging
|
|
3
8
|
import socket
|
|
4
9
|
import socketserver
|
|
5
|
-
import threading
|
|
6
10
|
import time
|
|
7
|
-
|
|
11
|
+
from typing import Any, Dict, List, Set, Union
|
|
8
12
|
import netifaces
|
|
9
13
|
|
|
10
14
|
from tinytoolslib.constants import LK_UDP_DISCOVERY_MSG, LK_UDP_PORT
|
|
11
15
|
from tinytoolslib.models import detect_version, get_device_info
|
|
12
16
|
|
|
13
17
|
|
|
14
|
-
def get_ips():
|
|
15
|
-
"""Return list of IPs to check."""
|
|
16
|
-
try:
|
|
17
|
-
gateways = netifaces.gateways()
|
|
18
|
-
interfaces = []
|
|
19
|
-
for key, value in gateways.items():
|
|
20
|
-
if key != "default":
|
|
21
|
-
for item in value:
|
|
22
|
-
interfaces.append(item[1])
|
|
23
|
-
addresses = set()
|
|
24
|
-
for interface in interfaces:
|
|
25
|
-
addresses_tmp = netifaces.ifaddresses(interface).get(2)
|
|
26
|
-
if addresses_tmp:
|
|
27
|
-
for addr in addresses_tmp:
|
|
28
|
-
addresses.add(addr["addr"])
|
|
29
|
-
except ValueError:
|
|
30
|
-
addresses = socket.gethostbyname_ex(socket.gethostname())[2]
|
|
31
|
-
return addresses
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def run_discovery_single(address, timelimit=3):
|
|
35
|
-
"""Run discovery for given address (tuple) in timelimit."""
|
|
36
|
-
devices = []
|
|
37
|
-
with DiscoveryServer(address, DiscoveryHandler) as server:
|
|
38
|
-
server_thread = threading.Thread(target=server.serve_forever)
|
|
39
|
-
server_thread.start()
|
|
40
|
-
time.sleep(timelimit)
|
|
41
|
-
server.shutdown()
|
|
42
|
-
devices = server.devices.copy()
|
|
43
|
-
del server_thread
|
|
44
|
-
return devices
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def serve_forever(server):
|
|
48
|
-
"""Wrapper for serve_forever method of server."""
|
|
49
|
-
server.serve_forever()
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def run_discovery_all(timelimit=3, port=LK_UDP_PORT, version=2, addresses=None):
|
|
53
|
-
"""Run discovery on all available addresses.
|
|
54
|
-
|
|
55
|
-
`version` - 1 and 2 are parallel, where time execution of 2
|
|
56
|
-
is closer to timelimit; 3 is sequential run;
|
|
57
|
-
"""
|
|
58
|
-
if addresses is None:
|
|
59
|
-
addresses = [ip for ip in get_ips() if not ip.startswith("169.254")]
|
|
60
|
-
devices = []
|
|
61
|
-
if version == 1:
|
|
62
|
-
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
|
|
63
|
-
servers = [
|
|
64
|
-
DiscoveryServer((address, port), DiscoveryHandler)
|
|
65
|
-
for address in addresses
|
|
66
|
-
]
|
|
67
|
-
executor.map(serve_forever, servers)
|
|
68
|
-
time.sleep(timelimit)
|
|
69
|
-
for server in servers:
|
|
70
|
-
server.shutdown()
|
|
71
|
-
devices.extend(server.devices)
|
|
72
|
-
elif version == 2:
|
|
73
|
-
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
|
|
74
|
-
servers = [
|
|
75
|
-
DiscoveryServerAuto(
|
|
76
|
-
(address, port), DiscoveryHandler, timelimit=timelimit
|
|
77
|
-
)
|
|
78
|
-
for address in addresses
|
|
79
|
-
]
|
|
80
|
-
futures = {
|
|
81
|
-
executor.submit(server.serve_forever): server for server in servers
|
|
82
|
-
}
|
|
83
|
-
for future in concurrent.futures.as_completed(futures):
|
|
84
|
-
try:
|
|
85
|
-
data = future.result()
|
|
86
|
-
except Exception as exc:
|
|
87
|
-
logging.warning("discovery error: %s", str(exc))
|
|
88
|
-
else:
|
|
89
|
-
devices.extend(data)
|
|
90
|
-
else:
|
|
91
|
-
for address in addresses:
|
|
92
|
-
temp = run_discovery_single((address, port))
|
|
93
|
-
devices.extend(temp)
|
|
94
|
-
return devices
|
|
95
|
-
|
|
96
|
-
|
|
97
18
|
class DiscoveryHandler(socketserver.BaseRequestHandler):
|
|
98
19
|
"""Handler for LK discovery server."""
|
|
99
20
|
|
|
@@ -147,21 +68,71 @@ class DiscoveryServer(socketserver.UDPServer):
|
|
|
147
68
|
|
|
148
69
|
|
|
149
70
|
class DiscoveryServerAuto(DiscoveryServer):
|
|
150
|
-
"""DiscoveryServer that
|
|
71
|
+
"""DiscoveryServer that automatically shuts down."""
|
|
151
72
|
|
|
152
73
|
def __init__(self, *args, **kwargs):
|
|
153
|
-
self.started_at = time.time()
|
|
154
|
-
|
|
74
|
+
self.started_at: float = time.time()
|
|
75
|
+
"""float: Timestamp of when discovery server started"""
|
|
76
|
+
self.time_limit: float = kwargs.pop("time_limit", 3)
|
|
77
|
+
"""float: Limit of time for how long should discovery server run"""
|
|
155
78
|
super().__init__(*args, **kwargs)
|
|
156
79
|
|
|
157
80
|
def service_actions(self):
|
|
81
|
+
"""Checks if should stop the server due to time_limit."""
|
|
158
82
|
super().service_actions()
|
|
159
83
|
now = time.time()
|
|
160
|
-
if now - self.started_at >= self.
|
|
161
|
-
if not self
|
|
162
|
-
self
|
|
84
|
+
if now - self.started_at >= self.time_limit:
|
|
85
|
+
if not getattr(self, "_BaseServer__shutdown_request"):
|
|
86
|
+
setattr(self, "_BaseServer__shutdown_request", True)
|
|
163
87
|
|
|
164
88
|
def serve_forever(self, *args, **kwargs):
|
|
165
89
|
"""Return devices list after auto shutdown."""
|
|
166
90
|
super().serve_forever(*args, **kwargs)
|
|
167
91
|
return self.devices
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_ips() -> Set[str]:
|
|
95
|
+
"""Return list of IPs to check."""
|
|
96
|
+
try:
|
|
97
|
+
gateways = netifaces.gateways()
|
|
98
|
+
interfaces = []
|
|
99
|
+
for key, value in gateways.items():
|
|
100
|
+
if key != "default":
|
|
101
|
+
for item in value:
|
|
102
|
+
interfaces.append(item[1])
|
|
103
|
+
addresses = set()
|
|
104
|
+
for interface in interfaces:
|
|
105
|
+
addresses_tmp = netifaces.ifaddresses(interface).get(2)
|
|
106
|
+
if addresses_tmp:
|
|
107
|
+
for addr in addresses_tmp:
|
|
108
|
+
addresses.add(addr["addr"])
|
|
109
|
+
except ValueError:
|
|
110
|
+
addresses = socket.gethostbyname_ex(socket.gethostname())[2]
|
|
111
|
+
return addresses
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def run_discovery(
|
|
115
|
+
time_limit: int = 3,
|
|
116
|
+
port: int = LK_UDP_PORT,
|
|
117
|
+
addresses: Union[List[str], None] = None,
|
|
118
|
+
) -> List[Dict[str, Any]]:
|
|
119
|
+
"""Run discovery on all available addresses or given one."""
|
|
120
|
+
if addresses is None:
|
|
121
|
+
addresses = [ip for ip in get_ips() if not ip.startswith("169.254")]
|
|
122
|
+
devices = []
|
|
123
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
|
|
124
|
+
servers = [
|
|
125
|
+
DiscoveryServerAuto(
|
|
126
|
+
(address, port), DiscoveryHandler, time_limit=time_limit
|
|
127
|
+
)
|
|
128
|
+
for address in addresses
|
|
129
|
+
]
|
|
130
|
+
futures = {executor.submit(server.serve_forever): server for server in servers}
|
|
131
|
+
for future in concurrent.futures.as_completed(futures):
|
|
132
|
+
try:
|
|
133
|
+
data = future.result()
|
|
134
|
+
except Exception as exc:
|
|
135
|
+
logging.warning("discovery error: %s", str(exc))
|
|
136
|
+
else:
|
|
137
|
+
devices.extend(data)
|
|
138
|
+
return devices
|