mudra-sdk 0.2.2__tar.gz → 0.2.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.
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/PKG-INFO +1 -1
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/__init__.py +3 -2
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/cloud/api_config.py +1 -1
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/cloud/data.py +3 -3
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/cloud/mudra_server_client.py +3 -5
- mudra_sdk-0.2.4/mudra_sdk/libs/darwin/arm64/MudraSDK.dylib +0 -0
- mudra_sdk-0.2.4/mudra_sdk/libs/darwin/x86_64/MudraSDK.dylib +0 -0
- mudra_sdk-0.2.4/mudra_sdk/libs/windows/x64/MudraSDK.dll +0 -0
- mudra_sdk-0.2.4/mudra_sdk/libs/windows/x86/MudraSDK.dll +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/models/__init__.py +1 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/models/callbacks.py +1 -1
- mudra_sdk-0.2.4/mudra_sdk/models/firmware_details.py +12 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/models/mudra.py +4 -3
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/models/mudra_device.py +55 -19
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/service/ble_service.py +5 -14
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk.egg-info/PKG-INFO +1 -1
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk.egg-info/SOURCES.txt +1 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/setup.py +1 -1
- mudra_sdk-0.2.2/mudra_sdk/libs/darwin/arm64/MudraSDK.dylib +0 -0
- mudra_sdk-0.2.2/mudra_sdk/libs/darwin/x86_64/MudraSDK.dylib +0 -0
- mudra_sdk-0.2.2/mudra_sdk/libs/windows/x64/MudraSDK.dll +0 -0
- mudra_sdk-0.2.2/mudra_sdk/libs/windows/x86/MudraSDK.dll +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/MANIFEST.in +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/README.md +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/cloud/__init__.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/cloud/auth_storage.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/cloud/request_interceptor.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/libs/__init__.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/libs/library_loader.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/models/computation_wrapper.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/models/data_recorder.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/models/enums.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/models/firmware_status.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk/service/__init__.py +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk.egg-info/dependency_links.txt +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk.egg-info/requires.txt +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/mudra_sdk.egg-info/top_level.txt +0 -0
- {mudra_sdk-0.2.2 → mudra_sdk-0.2.4}/setup.cfg +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Mudra SDK - Python client for Mudra API
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
__version__ = "0.2.
|
|
5
|
+
__version__ = "0.2.4"
|
|
6
6
|
__author__ = "Foad Khoury"
|
|
7
7
|
|
|
8
8
|
# Import main classes/functions to make them available at package level
|
|
@@ -13,6 +13,7 @@ from .service import *
|
|
|
13
13
|
# Define what's available when someone does: from mudra_sdk import *
|
|
14
14
|
__all__ = [
|
|
15
15
|
"Mudra",
|
|
16
|
-
"MudraDevice",
|
|
16
|
+
"MudraDevice",
|
|
17
17
|
"FirmwareCallbacks",
|
|
18
|
+
"FirmwareDetails",
|
|
18
19
|
]
|
|
@@ -122,7 +122,7 @@ class Endpoint(Enum):
|
|
|
122
122
|
ABORT_VIDEO_RECORDING = ("data/upload/abortVideoRecording", HttpMethod.POST)
|
|
123
123
|
DOWNLOAD_RECORDING = ("data/download/recordingDb", HttpMethod.POST)
|
|
124
124
|
DOWNLOAD_VIDEO_RECORDING_DIRECT = ("data/download/directVideoRecording", HttpMethod.POST)
|
|
125
|
-
LICENSE_SECURE_TOKEN = ("license/
|
|
125
|
+
LICENSE_SECURE_TOKEN = ("license/getLicense", HttpMethod.POST)
|
|
126
126
|
|
|
127
127
|
def __init__(self, path: str, method: HttpMethod):
|
|
128
128
|
self.path = path
|
|
@@ -458,12 +458,12 @@ class SetSerialNumberRequest:
|
|
|
458
458
|
@dataclass
|
|
459
459
|
class LicenseSecureTokenRequest:
|
|
460
460
|
"""Request for license/secure-token API"""
|
|
461
|
-
|
|
461
|
+
securityNumber: int
|
|
462
462
|
|
|
463
463
|
def to_json(self) -> Dict[str, Any]:
|
|
464
464
|
return {
|
|
465
|
-
'encryptionMethod': '
|
|
466
|
-
'
|
|
465
|
+
'encryptionMethod': 'ADVANCED',
|
|
466
|
+
'securityNumber': self.securityNumber,
|
|
467
467
|
}
|
|
468
468
|
|
|
469
469
|
|
|
@@ -622,12 +622,10 @@ class MudraServerClient(RequestInterceptorDelegate):
|
|
|
622
622
|
}
|
|
623
623
|
)
|
|
624
624
|
|
|
625
|
-
def send_security_number_api_call(self,
|
|
626
|
-
"""Call license secure token API with
|
|
627
|
-
uses first 4 bytes of random_number."""
|
|
625
|
+
def send_security_number_api_call(self, securityNumber: int) -> Optional[bytes]:
|
|
626
|
+
"""Call license secure token API with value. Returns token as bytes or None."""
|
|
628
627
|
try:
|
|
629
|
-
|
|
630
|
-
request = LicenseSecureTokenRequest(random_number=bytes(first_four))
|
|
628
|
+
request = LicenseSecureTokenRequest(securityNumber=securityNumber)
|
|
631
629
|
response = self._make_api_call(
|
|
632
630
|
endpoint=Endpoint.LICENSE_SECURE_TOKEN,
|
|
633
631
|
data=request.to_json(),
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class FirmwareDetails:
|
|
2
|
+
|
|
3
|
+
__slots__ = ()
|
|
4
|
+
|
|
5
|
+
def __new__(cls):
|
|
6
|
+
raise TypeError("%s cannot be instantiated" % cls.__name__)
|
|
7
|
+
|
|
8
|
+
#: Stable firmware version for Mudra Band (DFU, device info, cloud details).
|
|
9
|
+
STABLE_VERSION_MUDRA = "6.0.8.5"
|
|
10
|
+
|
|
11
|
+
#: Release / MDK target firmware version for update checks.
|
|
12
|
+
RELEASE_VERSION_MUDRA = "6.0.8.5"
|
|
@@ -91,7 +91,7 @@ class Mudra(BleServiceDelegate):
|
|
|
91
91
|
|
|
92
92
|
async def set_band_mode(self, device: mudraDeviceModule.MudraDevice, band_mode: BandMode):
|
|
93
93
|
await self._ble_service.set_band_mode(device, band_mode)
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
async def get_security_number(self, device: mudraDeviceModule.MudraDevice):
|
|
96
96
|
await self._ble_service.get_security_number(device)
|
|
97
97
|
|
|
@@ -157,9 +157,9 @@ class Mudra(BleServiceDelegate):
|
|
|
157
157
|
if device_address in self._mudra_devices:
|
|
158
158
|
self._mudra_devices[device_address].on_firmware_version_received(version)
|
|
159
159
|
|
|
160
|
-
def on_security_number_received(self, device_address: str,
|
|
160
|
+
def on_security_number_received(self, device_address: str, value: int):
|
|
161
161
|
if device_address in self._mudra_devices:
|
|
162
|
-
self._mudra_devices[device_address].on_security_number_received(
|
|
162
|
+
self._mudra_devices[device_address].on_security_number_received(value)
|
|
163
163
|
|
|
164
164
|
def on_battery_level_changed(self, device_address: str, level: int):
|
|
165
165
|
if device_address in self._mudra_devices:
|
|
@@ -185,6 +185,7 @@ class Mudra(BleServiceDelegate):
|
|
|
185
185
|
mudra_device = self._mudra_devices[device.address]
|
|
186
186
|
if mudra_device and self._delegate:
|
|
187
187
|
self._delegate.on_mudra_device_disconnected(device)
|
|
188
|
+
mudra_device.handle_disconnection()
|
|
188
189
|
|
|
189
190
|
def on_mudra_device_disconnecting(self, device: BLEDevice):
|
|
190
191
|
mudra_device = self._mudra_devices[device.address]
|
|
@@ -10,6 +10,40 @@ import mudra_sdk.models.mudra as mudraModule
|
|
|
10
10
|
import mudra_sdk.models.computation_wrapper as computationWrapperModule
|
|
11
11
|
from mudra_sdk.service.ble_service import MudraBLEServicesUUID, MudraCharacteristicUUID
|
|
12
12
|
|
|
13
|
+
|
|
14
|
+
class SecurityNumberPoller:
|
|
15
|
+
__slots__ = ("_device", "_task")
|
|
16
|
+
|
|
17
|
+
def __init__(self, device: "MudraDevice"):
|
|
18
|
+
self._device = device
|
|
19
|
+
self._task: Optional[asyncio.Task] = None
|
|
20
|
+
|
|
21
|
+
def start(self) -> None:
|
|
22
|
+
if self._task is not None and not self._task.done():
|
|
23
|
+
return
|
|
24
|
+
loop = asyncio.get_running_loop()
|
|
25
|
+
self._task = loop.create_task(self._poll_until_received())
|
|
26
|
+
|
|
27
|
+
def stop(self) -> None:
|
|
28
|
+
if self._task is None:
|
|
29
|
+
return
|
|
30
|
+
task = self._task
|
|
31
|
+
self._task = None
|
|
32
|
+
if not task.done():
|
|
33
|
+
task.cancel()
|
|
34
|
+
|
|
35
|
+
async def _poll_until_received(self) -> None:
|
|
36
|
+
try:
|
|
37
|
+
while True:
|
|
38
|
+
await self._device.get_security_number()
|
|
39
|
+
await asyncio.sleep(0.1)
|
|
40
|
+
except asyncio.CancelledError:
|
|
41
|
+
raise
|
|
42
|
+
finally:
|
|
43
|
+
if self._task is asyncio.current_task():
|
|
44
|
+
self._task = None
|
|
45
|
+
|
|
46
|
+
|
|
13
47
|
class MudraDevice(BLEDevice):
|
|
14
48
|
def __init__(self, ble_device: BLEDevice):
|
|
15
49
|
super().__init__(ble_device.address, ble_device.name, ble_device.details)
|
|
@@ -49,8 +83,8 @@ class MudraDevice(BLEDevice):
|
|
|
49
83
|
FirmwareDataType.embeddedAirTouch: False,
|
|
50
84
|
}
|
|
51
85
|
### ----------------------- Parameters ----------------------- ###
|
|
52
|
-
self._security_number: Optional[bytes] = None
|
|
53
86
|
self._license_sent: bool = False
|
|
87
|
+
self._security_number_poller = SecurityNumberPoller(self)
|
|
54
88
|
|
|
55
89
|
### ----------------------- Data Recorder ----------------------- ###
|
|
56
90
|
self._data_recorder = DataRecorder()
|
|
@@ -61,7 +95,6 @@ class MudraDevice(BLEDevice):
|
|
|
61
95
|
self._on_navigation_axis_ready: Optional[computationWrapperModule.OnNavigationAxisReceivedCallback] = None
|
|
62
96
|
self._on_navigation_direction_ready: Optional[computationWrapperModule.OnNavigationDirectionReceivedCallback] = None
|
|
63
97
|
self._on_button_changed_ready: Optional[computationWrapperModule.OnAirMouseButtonChangedReceivedCallback] = None
|
|
64
|
-
self._on_security_number_received: Optional[computationWrapperModule.OnSecurityNumberReceivedCallback] = None
|
|
65
98
|
|
|
66
99
|
### ----------------------- Parameters Callbacks ----------------------- ###
|
|
67
100
|
self._on_charging_state_changed: Optional[computationWrapperModule.OnChargingStateChangedCallback] = None
|
|
@@ -85,10 +118,11 @@ class MudraDevice(BLEDevice):
|
|
|
85
118
|
if not status:
|
|
86
119
|
return False
|
|
87
120
|
print(f"Device {self.name} is finished initializing")
|
|
88
|
-
await self.get_security_number()
|
|
89
|
-
await self.get_security_number()
|
|
90
121
|
return await mudraModule.Mudra().is_connected(self)
|
|
91
122
|
|
|
123
|
+
def handle_disconnection(self):
|
|
124
|
+
self._security_number_poller.stop()
|
|
125
|
+
|
|
92
126
|
### ----------------------- Ready Methods ----------------------- ###
|
|
93
127
|
|
|
94
128
|
def on_pressure_data_received(self, pressure_data: float):
|
|
@@ -113,26 +147,31 @@ class MudraDevice(BLEDevice):
|
|
|
113
147
|
self._on_navigation_direction_ready(direction)
|
|
114
148
|
|
|
115
149
|
def on_charging_state_changed(self, is_charging: bool):
|
|
150
|
+
print(f"Charging state changed: {is_charging}")
|
|
116
151
|
self._is_charging = is_charging
|
|
117
152
|
if self._on_charging_state_changed:
|
|
118
153
|
self._on_charging_state_changed(is_charging)
|
|
119
154
|
|
|
120
155
|
def on_serial_number_right_part_received(self, serial_number: int):
|
|
156
|
+
print(f"Serial number right part received: {serial_number}")
|
|
121
157
|
self._serial_number_right_part = serial_number
|
|
122
158
|
|
|
123
159
|
def on_serial_number_left_part_received(self, serial_number: int):
|
|
160
|
+
print(f"Serial number left part received: {serial_number}")
|
|
124
161
|
self._serial_number_left_part = serial_number
|
|
125
162
|
|
|
126
163
|
def on_firmware_version_received(self, version: str):
|
|
164
|
+
print(f"Firmware version received: {version}")
|
|
127
165
|
self._firmware_version = version
|
|
128
166
|
|
|
129
|
-
def on_security_number_received(self,
|
|
130
|
-
|
|
131
|
-
if self._on_security_number_received:
|
|
132
|
-
self._on_security_number_received(data)
|
|
167
|
+
def on_security_number_received(self, value: int):
|
|
168
|
+
print(f"Security number received: {value}")
|
|
133
169
|
|
|
170
|
+
self._security_number_poller.stop()
|
|
134
171
|
if not self._license_sent:
|
|
135
|
-
self.
|
|
172
|
+
self._license_sent = True
|
|
173
|
+
loop = asyncio.get_running_loop()
|
|
174
|
+
loop.create_task(self._send_security_number(value))
|
|
136
175
|
|
|
137
176
|
def on_battery_level_changed(self, level: int):
|
|
138
177
|
self._battery_level = level
|
|
@@ -145,7 +184,6 @@ class MudraDevice(BLEDevice):
|
|
|
145
184
|
return self._is_charging
|
|
146
185
|
|
|
147
186
|
def get_serial_number(self) -> Optional[int]:
|
|
148
|
-
self._license_sent = False
|
|
149
187
|
if self._serial_number_right_part is not None and self._serial_number_left_part is not None:
|
|
150
188
|
return self._serial_number_right_part + self._serial_number_left_part
|
|
151
189
|
return None
|
|
@@ -167,20 +205,19 @@ class MudraDevice(BLEDevice):
|
|
|
167
205
|
if self._characteristic_status[MudraCharacteristicUUID.COMMAND_CHARACTERISTIC]:
|
|
168
206
|
await mudraModule.Mudra().set_band_mode(self, band_mode)
|
|
169
207
|
|
|
170
|
-
async def get_security_number(self
|
|
208
|
+
async def get_security_number(self):
|
|
171
209
|
if self._characteristic_status[MudraCharacteristicUUID.COMMAND_CHARACTERISTIC]:
|
|
172
210
|
await mudraModule.Mudra().get_security_number(self)
|
|
173
211
|
|
|
174
|
-
def _send_security_number(self,
|
|
175
|
-
"""
|
|
176
|
-
self._license_sent = True
|
|
212
|
+
async def _send_security_number(self, value: int):
|
|
213
|
+
"""Sync fallback when no asyncio loop is running."""
|
|
177
214
|
try:
|
|
178
|
-
token = MudraServerClient().send_security_number_api_call(
|
|
215
|
+
token = MudraServerClient().send_security_number_api_call(value)
|
|
179
216
|
if token is not None:
|
|
180
|
-
# Schedule async set_license - BLE callback may be sync but typically runs in async context
|
|
181
217
|
try:
|
|
182
218
|
loop = asyncio.get_running_loop()
|
|
183
219
|
loop.create_task(self.set_license(token))
|
|
220
|
+
self._license_sent = False
|
|
184
221
|
except RuntimeError:
|
|
185
222
|
print("Cannot set license: no running event loop (ensure app uses asyncio)")
|
|
186
223
|
else:
|
|
@@ -203,6 +240,8 @@ class MudraDevice(BLEDevice):
|
|
|
203
240
|
def on_characteristic_discovered(self, characteristic_uuid: MudraCharacteristicUUID):
|
|
204
241
|
print(f"Characteristic discovered: {characteristic_uuid}")
|
|
205
242
|
self._characteristic_status[characteristic_uuid] = True
|
|
243
|
+
if(characteristic_uuid == MudraCharacteristicUUID.COMMAND_CHARACTERISTIC):
|
|
244
|
+
self._security_number_poller.start()
|
|
206
245
|
|
|
207
246
|
def on_firmware_status_updated(self, data: bytes):
|
|
208
247
|
self.firmware_status.update(data)
|
|
@@ -264,9 +303,6 @@ class MudraDevice(BLEDevice):
|
|
|
264
303
|
self._computation_wrapper.set_air_touch_active(active)
|
|
265
304
|
await self._update_state_enabled()
|
|
266
305
|
|
|
267
|
-
async def set_on_security_number_received(self, callback: computationWrapperModule.OnSecurityNumberReceivedCallback) -> None:
|
|
268
|
-
self._on_security_number_received = callback
|
|
269
|
-
|
|
270
306
|
### ----------------------- Is Callbacks set Methods ----------------------- ###
|
|
271
307
|
|
|
272
308
|
def is_on_imu_gyro_callback_set(self) -> bool:
|
|
@@ -2,7 +2,7 @@ import asyncio
|
|
|
2
2
|
from calendar import c
|
|
3
3
|
import cmd
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from typing import Any, Callable, Optional, Dict
|
|
5
|
+
from typing import Any, Callable, Optional, Dict, List, Tuple
|
|
6
6
|
from bleak import BleakScanner, BleakClient
|
|
7
7
|
from bleak.backends.device import BLEDevice
|
|
8
8
|
from bleak.backends.service import BleakGATTServiceCollection
|
|
@@ -10,8 +10,6 @@ from mudra_sdk.models.enums import AirMouseButton, FirmwareCallbacks, FirmwareCo
|
|
|
10
10
|
|
|
11
11
|
from ..models.callbacks import BleServiceDelegate
|
|
12
12
|
|
|
13
|
-
from typing import Optional
|
|
14
|
-
|
|
15
13
|
class BleService:
|
|
16
14
|
_instance = None
|
|
17
15
|
_delegate: Optional[BleServiceDelegate] = None
|
|
@@ -56,8 +54,6 @@ class BleService:
|
|
|
56
54
|
# Attempt connection
|
|
57
55
|
print(f"Calling BleakClient.connect() for {address}")
|
|
58
56
|
await client.connect()
|
|
59
|
-
import asyncio
|
|
60
|
-
await asyncio.sleep(10)
|
|
61
57
|
|
|
62
58
|
# Store the connected client
|
|
63
59
|
self._connected_clients[address] = client
|
|
@@ -266,13 +262,13 @@ class BleService:
|
|
|
266
262
|
case FirmwareCallbacks.BAND_CONNECTION_STATUS:
|
|
267
263
|
pass
|
|
268
264
|
case FirmwareCallbacks.SecurityNumber:
|
|
269
|
-
if self._delegate:
|
|
270
|
-
|
|
265
|
+
if self._delegate and len(data) >= 5:
|
|
266
|
+
value = data[4] << 24 | data[3] << 16 | data[2] << 8 | data[1]
|
|
267
|
+
self._delegate.on_security_number_received(device.address, value)
|
|
271
268
|
case FirmwareCallbacks.NONE:
|
|
272
269
|
print("NONE")
|
|
273
270
|
case _:
|
|
274
271
|
print("Unknown firmware callback")
|
|
275
|
-
|
|
276
272
|
def _logging_notification_handler(self, device: BLEDevice, sender: int, data: bytearray):
|
|
277
273
|
"""Handle LOGGING characteristic notifications."""
|
|
278
274
|
print(f"LOGGING notification from {sender} (device {device.address}): {data.hex()}")
|
|
@@ -449,15 +445,10 @@ class BleService:
|
|
|
449
445
|
await self.send_general_command(device, bytes(cmd))
|
|
450
446
|
|
|
451
447
|
async def set_license(self, device: BLEDevice, data: bytes):
|
|
452
|
-
cmd = bytearray(FirmwareCommand.setLicense.id)
|
|
453
|
-
cmd[2] = data[0]
|
|
454
|
-
cmd[3] = data[1]
|
|
455
|
-
cmd[4] = data[2]
|
|
456
|
-
cmd[5] = data[3]
|
|
448
|
+
cmd = bytearray(list(FirmwareCommand.setLicense.id) + list(data))
|
|
457
449
|
await self.send_general_command(device, bytes(cmd))
|
|
458
450
|
|
|
459
451
|
### ----------------------- Scan Methods ----------------------- ###
|
|
460
|
-
|
|
461
452
|
@property
|
|
462
453
|
def _is_scanning(self) -> bool:
|
|
463
454
|
"""Check if currently scanning for devices."""
|
|
@@ -24,6 +24,7 @@ mudra_sdk/models/callbacks.py
|
|
|
24
24
|
mudra_sdk/models/computation_wrapper.py
|
|
25
25
|
mudra_sdk/models/data_recorder.py
|
|
26
26
|
mudra_sdk/models/enums.py
|
|
27
|
+
mudra_sdk/models/firmware_details.py
|
|
27
28
|
mudra_sdk/models/firmware_status.py
|
|
28
29
|
mudra_sdk/models/mudra.py
|
|
29
30
|
mudra_sdk/models/mudra_device.py
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|