actionstreamer 0.4.4__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.
Files changed (29) hide show
  1. actionstreamer-0.4.4/PKG-INFO +20 -0
  2. actionstreamer-0.4.4/README.md +3 -0
  3. actionstreamer-0.4.4/actionstreamer/CommonFunctions/CommonFunctions.py +254 -0
  4. actionstreamer-0.4.4/actionstreamer/CommonFunctions/Wifi/Wifi.py +93 -0
  5. actionstreamer-0.4.4/actionstreamer/CommonFunctions/Wifi/__init__.py +4 -0
  6. actionstreamer-0.4.4/actionstreamer/CommonFunctions/__init__.py +4 -0
  7. actionstreamer-0.4.4/actionstreamer/Config/Config.py +127 -0
  8. actionstreamer-0.4.4/actionstreamer/Config/__init__.py +4 -0
  9. actionstreamer-0.4.4/actionstreamer/Device/Device.py +143 -0
  10. actionstreamer-0.4.4/actionstreamer/Device/__init__.py +4 -0
  11. actionstreamer-0.4.4/actionstreamer/Model/Model.py +127 -0
  12. actionstreamer-0.4.4/actionstreamer/Model/__init__.py +4 -0
  13. actionstreamer-0.4.4/actionstreamer/WebService/API/API.py +55 -0
  14. actionstreamer-0.4.4/actionstreamer/WebService/API/__init__.py +4 -0
  15. actionstreamer-0.4.4/actionstreamer/WebService/Event/Event.py +187 -0
  16. actionstreamer-0.4.4/actionstreamer/WebService/Event/__init__.py +4 -0
  17. actionstreamer-0.4.4/actionstreamer/WebService/File/File.py +90 -0
  18. actionstreamer-0.4.4/actionstreamer/WebService/File/__init__.py +4 -0
  19. actionstreamer-0.4.4/actionstreamer/WebService/Health/Health.py +73 -0
  20. actionstreamer-0.4.4/actionstreamer/WebService/Health/__init__.py +4 -0
  21. actionstreamer-0.4.4/actionstreamer/WebService/LogMessage/LogMessage.py +37 -0
  22. actionstreamer-0.4.4/actionstreamer/WebService/LogMessage/__init__.py +4 -0
  23. actionstreamer-0.4.4/actionstreamer/WebService/Patch/Patch.py +14 -0
  24. actionstreamer-0.4.4/actionstreamer/WebService/Patch/__init__.py +4 -0
  25. actionstreamer-0.4.4/actionstreamer/WebService/VideoClip/VideoClip.py +82 -0
  26. actionstreamer-0.4.4/actionstreamer/WebService/VideoClip/__init__.py +4 -0
  27. actionstreamer-0.4.4/actionstreamer/WebService/__init__.py +10 -0
  28. actionstreamer-0.4.4/actionstreamer/__init__.py +7 -0
  29. actionstreamer-0.4.4/pyproject.toml +17 -0
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.1
2
+ Name: actionstreamer
3
+ Version: 0.4.4
4
+ Summary: A library for the ActionStreamer API.
5
+ Author: ActionStreamer
6
+ Author-email: joe@actionstreamer.com
7
+ Requires-Python: >=3.10,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Requires-Dist: pytz (>=2024.1,<2025.0)
13
+ Requires-Dist: requests (>=2.32.3,<3.0.0)
14
+ Requires-Dist: wmi (>=1.5.1,<2.0.0) ; sys_platform == "win32"
15
+ Description-Content-Type: text/markdown
16
+
17
+ # ActionStreamer
18
+
19
+ A library for the ActionStreamer API.
20
+
@@ -0,0 +1,3 @@
1
+ # ActionStreamer
2
+
3
+ A library for the ActionStreamer API.
@@ -0,0 +1,254 @@
1
+ import sys
2
+ import hashlib
3
+ import hmac
4
+ import uuid
5
+ import time
6
+ from datetime import datetime
7
+ import requests
8
+ import os
9
+ import re
10
+
11
+ import pytz
12
+ import requests
13
+
14
+ from ActionStreamer.Config import WebServiceConfig
15
+
16
+ class StandardResult:
17
+
18
+ def __init__(self, code: int, description: str):
19
+ self.Code = code
20
+ self.Description = description
21
+
22
+
23
+ class switch(object):
24
+
25
+ def __init__(self, value):
26
+ self.value = value
27
+ self.fall = False
28
+
29
+ def __iter__(self):
30
+ """Return the match method once, then stop"""
31
+ yield self.match
32
+ raise StopIteration
33
+
34
+ def match(self, *args) -> bool:
35
+ """Indicate whether or not to enter a case suite"""
36
+ if self.fall or not args:
37
+ return True
38
+ elif self.value in args:
39
+ self.fall = True
40
+ return True
41
+ else:
42
+ return False
43
+
44
+
45
+ def get_exception_info() -> tuple[str, int] | tuple[None, None]:
46
+ exception_type, exception_object, exception_traceback = sys.exc_info()
47
+ if exception_traceback is not None:
48
+ filename = exception_traceback.tb_frame.f_code.co_filename
49
+ line_number = exception_traceback.tb_lineno
50
+ return filename, line_number
51
+ return None, None
52
+
53
+
54
+ def get_line_number() -> int | None:
55
+ exception_type, exception_object, exception_traceback = sys.exc_info()
56
+ if exception_traceback is not None:
57
+ return exception_traceback.tb_lineno
58
+ return None
59
+
60
+
61
+ def log_to_console(message: str, agent_name='') -> None:
62
+ # Get the current UTC time
63
+ utc_now = datetime.now(pytz.utc)
64
+
65
+ # Format the UTC time
66
+ utc_time_formatted = utc_now.strftime("%Y-%m-%d %H:%M:%S UTC")
67
+
68
+ # Prepend the formatted UTC time to the string
69
+ if (agent_name):
70
+ result_string = f"[{utc_time_formatted}]: [{agent_name}]: {message}"
71
+ else:
72
+ result_string = f"[{utc_time_formatted}]: {message}"
73
+
74
+ # Print the result to standard output
75
+ print(result_string)
76
+
77
+
78
+ def send_signed_request(ws_config: WebServiceConfig, method: str, url: str, path: str, headers: dict = None, parameters: str = None, body: str = None) -> tuple[int, str]:
79
+
80
+ try:
81
+ if headers is None:
82
+ headers = {"Content-Type": "application/json"}
83
+ elif isinstance(headers, str):
84
+ headers = dict(header.strip().split(':', 1) for header in headers.split('\n'))
85
+
86
+ nonce = str(uuid.uuid4())
87
+ timestamp = str(int(time.time()))
88
+
89
+ headers['X-Nonce'] = nonce
90
+ headers['X-Timestamp'] = timestamp
91
+ headers['Authorization'] = 'HMAC-SHA256 ' + ws_config.access_key
92
+ headers['X-AccessKey'] = ws_config.access_key
93
+
94
+ # Generate HMAC signature
95
+ signature, string_to_sign = get_hmac_signature(ws_config.secret_key, method, path, headers, parameters, body)
96
+
97
+ # Include signature in headers
98
+ headers['X-Signature'] = signature
99
+
100
+ verify = not ws_config.ignore_ssl
101
+
102
+ if method.upper() == 'POST':
103
+ response = requests.post(url, headers=headers, data=body, verify=verify, timeout=ws_config.timeout)
104
+ elif method.upper() == 'GET':
105
+ response = requests.get(url, headers=headers, params=parameters, verify=verify, timeout=ws_config.timeout)
106
+ if method.upper() == 'PUT':
107
+ response = requests.put(url, headers=headers, data=body, verify=verify, timeout=ws_config.timeout)
108
+ elif method.upper() == 'PATCH':
109
+ response = requests.patch(url, headers=headers, data=body, params=parameters, verify=verify, timeout=ws_config.timeout)
110
+ elif method.upper() == 'DELETE':
111
+ response = requests.delete(url, headers=headers, params=parameters, verify=verify, timeout=ws_config.timeout)
112
+
113
+ status_code = response.status_code
114
+ response_string = response.content.decode('utf-8')
115
+
116
+ except Exception as ex:
117
+ filename, line_number = get_exception_info()
118
+ if filename is not None and line_number is not None:
119
+ print(f"Exception occurred at line {line_number} in {filename}")
120
+ print(ex)
121
+ status_code = -1
122
+ response_string = "Error in send_signed_request"
123
+
124
+ return status_code, response_string
125
+
126
+
127
+ def get_hmac_signature(secret_key: str, method: str, path: str, headers, parameters: dict, body: str = None)-> tuple[str, str] | None:
128
+
129
+ try:
130
+ if 'Content-Type' in headers:
131
+ del headers['Content-Type']
132
+
133
+ headerString = dictionary_to_string(headers)
134
+ parameterString = dictionary_to_string(parameters)
135
+
136
+ # Path should be in the format /v1/event
137
+ if not path.startswith('/'):
138
+ path = '/' + path
139
+
140
+ if path.endswith('/') and len(path) > 1:
141
+ path = path[:-1]
142
+
143
+ string_to_sign = '\n'.join([method, path, headerString, parameterString, body if body else ''])
144
+
145
+ string_to_sign = string_to_sign.strip()
146
+ #log_to_console("stringToSign: " + string_to_sign)
147
+
148
+ # Generate the HMAC SHA256 signature
149
+ hmac_signature = hmac.new(secret_key.encode('utf-8'), string_to_sign.encode('utf-8'), hashlib.sha256)
150
+
151
+ # Convert the HMAC signature to hexadecimal
152
+ return hmac_signature.hexdigest(), string_to_sign
153
+
154
+ except Exception as ex:
155
+ filename, line_number = get_exception_info()
156
+ if filename is not None and line_number is not None:
157
+ print(f"Exception occurred at line {line_number} in {filename}")
158
+ print(ex)
159
+
160
+
161
+ def dictionary_to_string(dictionary: dict) -> str:
162
+
163
+ result = ''
164
+
165
+ try:
166
+ sorted_keys = sorted(dictionary.keys())
167
+
168
+ for key in sorted_keys:
169
+ result += f"{key}: {dictionary[key]}\n"
170
+
171
+ except Exception as ex:
172
+ filename, line_number = get_exception_info()
173
+ #if filename is not None and line_number is not None:
174
+ #print(f"Exception occurred at line {line_number} in {filename}")
175
+ #print(ex)
176
+
177
+ return result
178
+
179
+
180
+ def upload_file_to_s3(file_path: str, signed_url: str) -> int:
181
+
182
+ retry = True
183
+ result = 0
184
+
185
+ while retry:
186
+
187
+ try:
188
+ with open(file_path, 'rb') as file:
189
+ response = requests.put(signed_url, data=file)
190
+
191
+ if response.status_code == 200:
192
+ retry = False
193
+ result = 0
194
+ else:
195
+ print(f"Error uploading file to S3. Status code: {response.status_code}")
196
+ result = -1
197
+
198
+ except Exception as ex:
199
+ print("Exception occurred while uploading file to S3:", str(ex))
200
+ result = -2
201
+
202
+ return result
203
+
204
+
205
+ def get_sha256_hash_for_file(file_path: str) -> str:
206
+ # Initialize the hash object (SHA-256 is used in this example)
207
+ hash_object = hashlib.sha256()
208
+
209
+ # Open the file in binary mode to read its contents
210
+ with open(file_path, "rb") as file:
211
+ # Read the file in chunks to avoid loading the entire file into memory
212
+ for chunk in iter(lambda: file.read(4096), b""):
213
+ hash_object.update(chunk)
214
+
215
+ # Get the hexadecimal representation of the hash
216
+ file_hash = hash_object.hexdigest()
217
+
218
+ return file_hash
219
+
220
+
221
+ def create_folders(path: str) -> None:
222
+ # Split the path into individual folders
223
+ folders = path.split(os.sep)
224
+
225
+ # Initialize the base folder to the root of the file system
226
+ base_folder = ""
227
+
228
+ # Loop through each folder in the path
229
+ for folder in folders:
230
+ # Append the current folder to the base folder
231
+ base_folder = os.path.join(base_folder, folder)
232
+
233
+ # Check if the current folder exists
234
+ if not os.path.exists(base_folder):
235
+ # If not, create the folder
236
+ os.makedirs(base_folder)
237
+
238
+
239
+ def get_cpu_frequency() -> float:
240
+ with open("/proc/cpuinfo") as f:
241
+ cpuinfo = f.read()
242
+ # Find the first occurrence of "cpu MHz"
243
+ match = re.search(r"cpu MHz\s+:\s+(\d+\.\d+)", cpuinfo)
244
+ if match:
245
+ return float(match.group(1))
246
+ else:
247
+ raise RuntimeError("Unable to find CPU frequency in /proc/cpuinfo")
248
+
249
+
250
+ def get_clock_cycles_per_millisecond() -> float:
251
+ frequency_mhz = get_cpu_frequency()
252
+ frequency_hz = frequency_mhz * 1_000_000
253
+ cycles_per_millisecond = frequency_hz / 1_000
254
+ return cycles_per_millisecond
@@ -0,0 +1,93 @@
1
+ import json
2
+ import subprocess
3
+
4
+
5
+ def add_wifi_connection(ssid: str, password: str, connection_name: str, priority=1) -> None:
6
+
7
+ try:
8
+ subprocess.run(['sudo', 'nmcli', 'connection', 'add', 'type', 'wifi', 'ifname', 'wlan0', 'con-name', connection_name, 'ssid', ssid, 'connection.autoconnect-priority', str(priority)], check=True)
9
+ subprocess.run(['sudo', 'nmcli', 'connection', 'modify', connection_name, 'wifi-sec.key-mgmt', 'wpa-psk'], check=True)
10
+ subprocess.run(['sudo', 'nmcli', 'connection', 'modify', connection_name, 'wifi-sec.psk', password], check=True)
11
+
12
+ # Activate the connection
13
+ subprocess.run(['sudo', 'nmcli', 'connection', 'up', connection_name], check=True)
14
+ #print(f"Added and activated new connection: {connection_name}")
15
+
16
+ except subprocess.CalledProcessError as ex:
17
+ print(f"Failed to add connection: {connection_name}. Error: {ex}")
18
+
19
+
20
+ def remove_wifi_connection(ssid: str) -> None:
21
+
22
+ try:
23
+ subprocess.run(['sudo', 'nmcli', 'connection', 'delete', ssid], check=True)
24
+ print(f"Removed existing connection: {ssid}")
25
+ except subprocess.CalledProcessError as ex:
26
+ print(f"Failed to remove connection: {ssid}. It might not exist.")
27
+
28
+
29
+ def set_wifi_priority(ssid: str, priority: int) -> None:
30
+
31
+ # Example usage:
32
+ # set_wifi_priority("YourSSID", 100)
33
+
34
+ try:
35
+ # Get the UUID of the connection
36
+ result = subprocess.run(
37
+ ['nmcli', '-g', 'uuid', 'connection', 'show', ssid],
38
+ capture_output=True, text=True, check=True
39
+ )
40
+ uuid = result.stdout.strip()
41
+
42
+ if not uuid:
43
+ raise ValueError(f"Connection {ssid} not found.")
44
+
45
+ # Set the autoconnect priority
46
+ subprocess.run(
47
+ ['nmcli', 'connection', 'modify', uuid, 'connection.autoconnect-priority', str(priority)],
48
+ check=True
49
+ )
50
+
51
+ # Restart Network Manager to apply the changes
52
+ subprocess.run(['sudo', 'systemctl', 'restart', 'NetworkManager'], check=True)
53
+
54
+ print(f"Priority for {ssid} set to {priority}.")
55
+
56
+ except subprocess.CalledProcessError as ex:
57
+ print(f"An error occurred while running nmcli: {ex}")
58
+
59
+ except ValueError as ex:
60
+ print(ex)
61
+
62
+
63
+ def back_up_connections(backup_file_path: str) -> None:
64
+ # Backup all connection data to a JSON file
65
+ try:
66
+ result = subprocess.run(['sudo', 'nmcli', '--json', 'connection', 'export'], capture_output=True, text=True, check=True)
67
+ connections_data = json.loads(result.stdout)
68
+
69
+ with open(backup_file_path, 'w') as f:
70
+ json.dump(connections_data, f, indent=4)
71
+
72
+ print(f"Connections backed up to {backup_file_path}.")
73
+
74
+ except subprocess.CalledProcessError as ex:
75
+ print(f"Failed to backup connections. Error: {ex}")
76
+
77
+
78
+ def restore_connections(backup_file_path: str) -> None:
79
+ # Restore all connections from a JSON backup file
80
+ try:
81
+ with open(backup_file_path, 'r') as f:
82
+ connections_data = json.load(f)
83
+
84
+ subprocess.run(['sudo', 'nmcli', 'connection', 'delete', 'id', 'all'], check=True)
85
+
86
+ for connection in connections_data:
87
+ subprocess.run(['sudo', 'nmcli', 'connection', 'import', 'json', json.dumps(connection)], check=True)
88
+
89
+ print(f"Connections restored from {backup_file_path}.")
90
+
91
+ except (subprocess.CalledProcessError, json.JSONDecodeError) as ex:
92
+ print(f"Failed to restore connections. Error: {ex}")
93
+
@@ -0,0 +1,4 @@
1
+ from .Wifi import add_wifi_connection, remove_wifi_connection, set_wifi_priority, back_up_connections, restore_connections
2
+
3
+
4
+ __all__ = ['add_wifi_connection', 'remove_wifi_connection', 'set_wifi_priority', 'back_up_connections', 'restore_connections']
@@ -0,0 +1,4 @@
1
+ from .CommonFunctions import StandardResult, switch, get_exception_info, get_line_number, log_to_console, send_signed_request, get_hmac_signature, dictionary_to_string, upload_file_to_s3, get_sha256_hash_for_file, create_folders
2
+ from . import Wifi
3
+
4
+ __all__ = ['StandardResult', 'switch', 'get_exception_info', 'get_line_number', 'log_to_console', 'send_signed_request', 'get_hmac_signature', 'dictionary_to_string', 'upload_file_to_s3', 'get_sha256_hash_for_file', 'Wifi', 'create_folders']
@@ -0,0 +1,127 @@
1
+ import os
2
+ import platform
3
+
4
+ class WebServiceConfig:
5
+
6
+ """
7
+ Configuration for connecting to the web service.
8
+
9
+ Attributes:
10
+ access_key (str): The access key for authentication.
11
+ secret_key (str): The secret key for authentication.
12
+ base_url (str): The base URL of the web service.
13
+ timeout (int): The timeout for requests in seconds.
14
+ ignore_ssl (bool): Whether to ignore SSL verification.
15
+ """
16
+ def __init__(self, access_key: str, secret_key: str, base_url: str, timeout: int = 30, ignore_ssl: bool = False):
17
+ """
18
+ Initialize the WebServiceConfig.
19
+
20
+ :param access_key: The access key for authentication.
21
+ :param secret_key: The secret key for authentication.
22
+ :param base_url: The base URL of the web service.
23
+ :param timeout: The timeout for requests in seconds (default is 30).
24
+ :param ignore_ssl: Whether to ignore SSL verification (default is False).
25
+ """
26
+ self.access_key = access_key
27
+ self.secret_key = secret_key
28
+ self.base_url = base_url
29
+ self.timeout = timeout
30
+ self.ignore_ssl = ignore_ssl
31
+
32
+ class LogConfig:
33
+
34
+ def __init__(self, ws_config: WebServiceConfig, device_name: str, agent_type: str, agent_version: str, agent_index: int, process_id: int):
35
+ self.ws_config = ws_config
36
+ self.device_name = device_name
37
+ self.agent_type = agent_type
38
+ self.agent_version = agent_version
39
+ self.agent_index = agent_index
40
+ self.process_id = process_id
41
+
42
+
43
+ def is_windows() -> bool:
44
+ return platform.system() == 'Windows'
45
+
46
+
47
+ def get_config_folder_path(app_name: str, base_folder_path: str = '') -> str:
48
+
49
+ if is_windows():
50
+ username = os.getlogin()
51
+ config_dir = os.path.join('C:\\Users', username, 'AppData', 'Roaming', app_name, "config")
52
+ # If a virtual environment is used, the path will be in something like:
53
+ # C:\Users\Username\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\Roaming
54
+
55
+ else:
56
+ if base_folder_path:
57
+ config_dir = os.path.join(base_folder_path, ".config", app_name)
58
+ else:
59
+ config_dir = os.path.expanduser(os.path.join("~", ".config", app_name))
60
+
61
+ # Create the directory if it doesn't exist
62
+ if not os.path.exists(config_dir):
63
+ os.makedirs(config_dir)
64
+
65
+ return config_dir
66
+
67
+
68
+ def get_appdata_folder_path(app_name: str, base_folder_path: str = '') -> str:
69
+
70
+ if is_windows():
71
+ username = os.getlogin()
72
+ appdata_folder_path = os.path.join('C:\\Users', username, 'AppData', 'Roaming', app_name)
73
+ # If a virtual environment is used, the path will be in something like:
74
+ # C:\Users\Username\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\Roaming
75
+ else:
76
+ if base_folder_path:
77
+ appdata_folder_path = os.path.join(base_folder_path, ".appdata", app_name)
78
+ else:
79
+ appdata_folder_path = os.path.expanduser(os.path.join("~", ".appdata", app_name))
80
+
81
+ # Create the directory if it doesn't exist
82
+ if not os.path.exists(appdata_folder_path):
83
+ os.makedirs(appdata_folder_path)
84
+
85
+ return appdata_folder_path
86
+
87
+
88
+ def get_config_value(config_folder_path: str, name: str, default_value: str = '') -> str | None:
89
+
90
+ if not os.path.exists(config_folder_path):
91
+ os.makedirs(config_folder_path)
92
+
93
+ file_path = os.path.join(config_folder_path, name + '.txt')
94
+
95
+ if not os.path.exists(file_path):
96
+ with open(file_path, 'w') as file:
97
+ file.write(default_value)
98
+
99
+ try:
100
+ with open(file_path, 'r') as file:
101
+ contents = file.read()
102
+ return contents
103
+ except FileNotFoundError:
104
+ print(f"File '{name}' not found in the specified folder '{config_folder_path}'")
105
+ return None
106
+ except Exception as ex:
107
+ print(f"Error occurred while reading '{name}': {ex}")
108
+ return None
109
+
110
+
111
+ def set_config_value(config_folder_path: str, name: str, value: str) -> None:
112
+
113
+ if not os.path.exists(config_folder_path):
114
+ os.makedirs(config_folder_path)
115
+
116
+ # Create the directory if it doesn't exist
117
+ if not os.path.exists(config_folder_path):
118
+ os.makedirs(config_folder_path)
119
+
120
+ file_path = os.path.join(config_folder_path, name + '.txt')
121
+
122
+ try:
123
+ with open(file_path, 'w') as file:
124
+ file.write(value)
125
+ print(f"Successfully set the value in '{name}'")
126
+ except Exception as ex:
127
+ print(f"Error occurred while setting value in '{name}': {ex}")
@@ -0,0 +1,4 @@
1
+ from .Config import WebServiceConfig, LogConfig, is_windows, get_config_folder_path, get_appdata_folder_path, get_config_value, set_config_value
2
+
3
+
4
+ __all__ = ['WebServiceConfig', 'LogConfig', 'is_windows', 'get_config_folder_path', 'get_appdata_folder_path', 'get_config_value', 'set_config_value']
@@ -0,0 +1,143 @@
1
+ import getopt
2
+ import socket
3
+ import sys
4
+ import platform
5
+ import subprocess
6
+
7
+ def process_cpuinfo() -> str:
8
+
9
+ device_name = "0000000000000000"
10
+
11
+ try:
12
+ optlist, args = getopt.getopt(sys.argv[1:], 'm:')
13
+
14
+ except getopt.GetoptError as err:
15
+ # Print help information and exit:
16
+ print(str(err)) # This will print something like "option -a not recognized"
17
+ return device_name
18
+
19
+ for option, argument in optlist:
20
+ if option == "-m":
21
+ device_name = argument
22
+
23
+ return device_name
24
+
25
+
26
+ def get_serial_number() -> str:
27
+
28
+ serial_number = ""
29
+ manufacturer = ""
30
+ manufacturer, return_code = get_manufacturer()
31
+
32
+ if platform.system() == "Windows":
33
+ serial_number = get_cpu_serial_number_windows()
34
+
35
+ elif platform.system() == "Linux":
36
+ serial_number = get_cpu_serial_number_linux()
37
+
38
+ else:
39
+ serial_number = ""
40
+
41
+ return manufacturer + "_" + serial_number
42
+
43
+
44
+ def get_ip_address() -> str:
45
+
46
+ try:
47
+ # Get the local hostname
48
+ hostname = socket.gethostname()
49
+ # Get the IP address associated with the hostname
50
+ ip_address = socket.gethostbyname(hostname)
51
+ except socket.error:
52
+ # If an error occurs, return a default IP address
53
+ ip_address = "0.0.0.0"
54
+
55
+ return ip_address
56
+
57
+
58
+ def get_cpu_serial_number_windows() -> str:
59
+
60
+ try:
61
+ import wmi
62
+ wmi_object = wmi.WMI()
63
+ for processor in wmi_object.Win32_Processor():
64
+ return processor.ProcessorId.strip()
65
+
66
+ except Exception as ex:
67
+ return str(ex)
68
+
69
+
70
+ def get_cpu_serial_number_linux() -> str:
71
+
72
+ try:
73
+ with open('/proc/cpuinfo', 'r') as f:
74
+ for line in f:
75
+ if line.strip().startswith("Serial"):
76
+ return line.strip().split(":")[1].strip()
77
+
78
+ except Exception as ex:
79
+ return str(ex)
80
+
81
+
82
+ def get_manufacturer() -> tuple[str, int]:
83
+
84
+ if platform.system() == "Windows":
85
+ return get_manufacturer_windows()
86
+ else:
87
+ return get_manufacturer_linux()
88
+
89
+
90
+ def get_manufacturer_windows() -> tuple[str, int]:
91
+ try:
92
+ import wmi
93
+ w = wmi.WMI()
94
+ for processor in w.Win32_Processor():
95
+ return parse_manufacturer(processor.Manufacturer.strip()), 0
96
+ except Exception as e:
97
+ print(f"Exception in get_manufacturer_windows: {e}")
98
+ return "", 1
99
+
100
+ return "", 1
101
+
102
+
103
+ def get_manufacturer_linux() -> tuple[str, int]:
104
+ try:
105
+ with open("/proc/cpuinfo", "r") as f:
106
+ for line in f:
107
+ if line.startswith("Model"):
108
+ model = line.split(":")[1].strip()
109
+ if "Raspberry Pi" in model:
110
+ return parse_raspberry_pi_model(model), 0
111
+ # Fall back to using dmidecode if not a Raspberry Pi
112
+ result = subprocess.run(['dmidecode', '-t', 'processor'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
113
+ for line in result.stdout.splitlines():
114
+ if line.strip().startswith("Manufacturer"):
115
+ return parse_manufacturer(line.split(":")[1].strip()), 0
116
+ except Exception as e:
117
+ print(f"Exception in get_manufacturer_linux: {e}")
118
+ return "", 1
119
+
120
+ return "", 1
121
+
122
+
123
+ def parse_raspberry_pi_model(model: str) -> str:
124
+
125
+ if "Raspberry Pi" in model:
126
+ parts = model.split()
127
+ if len(parts) >= 3 and parts[2].isdigit():
128
+ return f"RPi{parts[2]}"
129
+ return model
130
+
131
+
132
+ def parse_manufacturer(manufacturer: str) -> str:
133
+
134
+ if "Intel" in manufacturer:
135
+ return "Intel"
136
+ elif "AMD" in manufacturer:
137
+ return "AMD"
138
+ elif "Broadcom" in manufacturer:
139
+ return "Broadcom"
140
+ elif "ARM" in manufacturer:
141
+ return "ARM"
142
+ else:
143
+ return manufacturer
@@ -0,0 +1,4 @@
1
+ from .Device import get_serial_number, get_ip_address, get_manufacturer
2
+
3
+
4
+ __all__ = ['get_serial_number', 'get_ip_address', 'get_manufacturer']