sok-ble 0.1.2__py3-none-any.whl → 0.1.4__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.
- sok_ble/sok_bluetooth_device.py +77 -38
- {sok_ble-0.1.2.dist-info → sok_ble-0.1.4.dist-info}/METADATA +2 -1
- {sok_ble-0.1.2.dist-info → sok_ble-0.1.4.dist-info}/RECORD +5 -5
- {sok_ble-0.1.2.dist-info → sok_ble-0.1.4.dist-info}/WHEEL +0 -0
- {sok_ble-0.1.2.dist-info → sok_ble-0.1.4.dist-info}/top_level.txt +0 -0
sok_ble/sok_bluetooth_device.py
CHANGED
|
@@ -9,10 +9,14 @@ import struct
|
|
|
9
9
|
import logging
|
|
10
10
|
import statistics
|
|
11
11
|
|
|
12
|
+
import async_timeout
|
|
13
|
+
from bleak import BleakError
|
|
14
|
+
|
|
12
15
|
from bleak.backends.device import BLEDevice
|
|
13
16
|
|
|
14
17
|
from sok_ble.const import UUID_RX, UUID_TX, _sok_command
|
|
15
18
|
from sok_ble.sok_parser import SokParser
|
|
19
|
+
from sok_ble.exceptions import BLEConnectionError
|
|
16
20
|
|
|
17
21
|
logger = logging.getLogger(__name__)
|
|
18
22
|
|
|
@@ -48,51 +52,86 @@ class SokBluetoothDevice:
|
|
|
48
52
|
async def _connect(self) -> AsyncIterator[BleakClientWithServiceCache]:
|
|
49
53
|
"""Connect to the device and yield a BLE client."""
|
|
50
54
|
logger.debug("Connecting to %s", self._ble_device.address)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
last_err: Exception | None = None
|
|
56
|
+
for attempt in range(3):
|
|
57
|
+
try:
|
|
58
|
+
if establish_connection:
|
|
59
|
+
client = await establish_connection(
|
|
60
|
+
BleakClientWithServiceCache,
|
|
61
|
+
self._ble_device,
|
|
62
|
+
self._ble_device.name or self._ble_device.address,
|
|
63
|
+
adapter=self._adapter,
|
|
64
|
+
)
|
|
65
|
+
else:
|
|
66
|
+
client = BleakClientWithServiceCache(
|
|
67
|
+
self._ble_device, adapter=self._adapter
|
|
68
|
+
)
|
|
69
|
+
await client.connect()
|
|
70
|
+
|
|
71
|
+
# Force service discovery
|
|
72
|
+
async with async_timeout.timeout(5):
|
|
73
|
+
_ = client.services
|
|
74
|
+
await asyncio.sleep(0.15)
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
yield client
|
|
78
|
+
finally:
|
|
79
|
+
await client.disconnect()
|
|
80
|
+
logger.debug(
|
|
81
|
+
"Disconnected from %s", self._ble_device.address
|
|
82
|
+
)
|
|
83
|
+
return
|
|
84
|
+
except (BleakError, asyncio.TimeoutError) as err:
|
|
85
|
+
last_err = err
|
|
86
|
+
logger.debug(
|
|
87
|
+
"BLE connect attempt %s failed for %s: %s",
|
|
88
|
+
attempt + 1,
|
|
89
|
+
self._ble_device.address,
|
|
90
|
+
err,
|
|
91
|
+
)
|
|
92
|
+
await asyncio.sleep(0.5)
|
|
93
|
+
|
|
94
|
+
raise BLEConnectionError(
|
|
95
|
+
f"Unable to establish GATT connection to {self._ble_device.address}"
|
|
96
|
+
) from last_err
|
|
69
97
|
|
|
70
98
|
async def _send_command(
|
|
71
99
|
self, client: BleakClientWithServiceCache, cmd: int, expected: int
|
|
72
100
|
) -> bytes:
|
|
73
101
|
"""Send a command and return the response bytes with the given header."""
|
|
74
102
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
queue: asyncio.Queue[bytes] = asyncio.Queue()
|
|
83
|
-
|
|
84
|
-
def handler(_: int, data: bytearray) -> None:
|
|
85
|
-
queue.put_nowait(bytes(data))
|
|
86
|
-
|
|
87
|
-
await client.start_notify(UUID_RX, handler)
|
|
88
|
-
try:
|
|
89
|
-
await client.write_gatt_char(UUID_TX, _sok_command(cmd))
|
|
90
|
-
while True:
|
|
91
|
-
data = await asyncio.wait_for(queue.get(), 5.0)
|
|
92
|
-
if struct.unpack_from(">H", data)[0] == expected:
|
|
103
|
+
for attempt in range(2):
|
|
104
|
+
try:
|
|
105
|
+
start_notify = getattr(client, "start_notify", None)
|
|
106
|
+
if start_notify is None:
|
|
107
|
+
await client.write_gatt_char(UUID_TX, _sok_command(cmd))
|
|
108
|
+
data = bytes(await client.read_gatt_char(UUID_RX))
|
|
93
109
|
return data
|
|
94
|
-
|
|
95
|
-
|
|
110
|
+
|
|
111
|
+
queue: asyncio.Queue[bytes] = asyncio.Queue()
|
|
112
|
+
|
|
113
|
+
def handler(_: int, data: bytearray) -> None:
|
|
114
|
+
queue.put_nowait(bytes(data))
|
|
115
|
+
|
|
116
|
+
await client.start_notify(UUID_RX, handler)
|
|
117
|
+
try:
|
|
118
|
+
await client.write_gatt_char(UUID_TX, _sok_command(cmd))
|
|
119
|
+
while True:
|
|
120
|
+
data = await asyncio.wait_for(queue.get(), 5.0)
|
|
121
|
+
if struct.unpack_from(">H", data)[0] == expected:
|
|
122
|
+
return data
|
|
123
|
+
finally:
|
|
124
|
+
await client.stop_notify(UUID_RX)
|
|
125
|
+
except BleakError as err:
|
|
126
|
+
if attempt == 0:
|
|
127
|
+
logger.debug(
|
|
128
|
+
"BLE command attempt failed for %s: %s",
|
|
129
|
+
self._ble_device.address,
|
|
130
|
+
err,
|
|
131
|
+
)
|
|
132
|
+
await asyncio.sleep(0.2)
|
|
133
|
+
continue
|
|
134
|
+
raise
|
|
96
135
|
|
|
97
136
|
async def async_update(self) -> None:
|
|
98
137
|
"""Poll the device for all telemetry and update attributes."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sok-ble
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: SOK BLE battery interface library
|
|
5
5
|
Author-email: Mitchell Carlson <mitchell.carlson.pro@gmail.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -12,6 +12,7 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Requires-Python: >=3.11
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: async-timeout>=4.0.3
|
|
15
16
|
Requires-Dist: bleak>=0.22.3
|
|
16
17
|
Requires-Dist: bleak-retry-connector>=3.9.0
|
|
17
18
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
sok_ble/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
sok_ble/const.py,sha256=mHtJTbWz_dG3v1lhZrLDzMf-QAG9v5QWlHU9ZKsyYdg,998
|
|
3
3
|
sok_ble/exceptions.py,sha256=7H1yUqqnrKyi3LwxRCMF7RkuGp_rgdy9j35nrMOgz44,247
|
|
4
|
-
sok_ble/sok_bluetooth_device.py,sha256=
|
|
4
|
+
sok_ble/sok_bluetooth_device.py,sha256=DlTqxtw5ZZtN-Y8gN3Gm8xGeiRVLQ_IpIxtXtHEBuWo,7878
|
|
5
5
|
sok_ble/sok_parser.py,sha256=KXYxsR4868vWFs2AAI7o7XfzjNZiDgfpsmz3dFgjLco,4323
|
|
6
|
-
sok_ble-0.1.
|
|
7
|
-
sok_ble-0.1.
|
|
8
|
-
sok_ble-0.1.
|
|
9
|
-
sok_ble-0.1.
|
|
6
|
+
sok_ble-0.1.4.dist-info/METADATA,sha256=F19P8UkWc3PfrtpjT1zaRIYqGGsxsOHqorv8wt25mgA,1469
|
|
7
|
+
sok_ble-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
8
|
+
sok_ble-0.1.4.dist-info/top_level.txt,sha256=WTVtlZ2sADYAxKEBkDJPUn4hFAH9NfIZ9Q2HP2RKpbw,8
|
|
9
|
+
sok_ble-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|