Migrate MCP and utilities to CircuitPython, including color GIF and volume fixes
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
"""CircuitPython BLE UART utility.
|
||||
|
||||
Wraps the adafruit_ble library to advertise Nordic UART Service and scan for nearby devices.
|
||||
"""
|
||||
|
||||
import time
|
||||
from adafruit_ble import BLERadio
|
||||
from adafruit_ble.services.nordic import UARTService
|
||||
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
|
||||
|
||||
class BLEUART:
|
||||
def __init__(self, ble=None, name="ESP32-S3-RLCD"):
|
||||
self.ble = BLERadio()
|
||||
self.ble.name = name
|
||||
self.uart = UARTService()
|
||||
self.advertisement = ProvideServicesAdvertisement(self.uart)
|
||||
self.rx_callback = None
|
||||
self._is_advertising = False
|
||||
self._start_advertise()
|
||||
|
||||
def _start_advertise(self):
|
||||
if not self.ble.connected and not self._is_advertising:
|
||||
try:
|
||||
self.ble.start_advertising(self.advertisement)
|
||||
self._is_advertising = True
|
||||
print(f"BLE advertising started as '{self.ble.name}'")
|
||||
except Exception as e:
|
||||
print(f"Failed to start BLE advertising: {e}")
|
||||
|
||||
def on_rx(self, callback):
|
||||
self.rx_callback = callback
|
||||
return callback
|
||||
|
||||
def update(self):
|
||||
"""Polls the UART stream for incoming data and triggers callbacks."""
|
||||
if self.ble.connected:
|
||||
self._is_advertising = False
|
||||
try:
|
||||
if self.uart.in_waiting:
|
||||
data = self.uart.read(self.uart.in_waiting)
|
||||
if self.rx_callback and data:
|
||||
try:
|
||||
decoded = data.decode("utf-8").strip()
|
||||
self.rx_callback(decoded)
|
||||
except:
|
||||
self.rx_callback(data)
|
||||
except Exception as e:
|
||||
print(f"Error reading BLE RX: {e}")
|
||||
else:
|
||||
if not self._is_advertising:
|
||||
self._start_advertise()
|
||||
|
||||
def write(self, data):
|
||||
if not self.ble.connected:
|
||||
return False
|
||||
if isinstance(data, str):
|
||||
data = data.encode("utf-8")
|
||||
try:
|
||||
self.uart.write(data)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error sending BLE data: {e}")
|
||||
return False
|
||||
|
||||
def is_connected(self):
|
||||
return self.ble.connected
|
||||
|
||||
def scan(self, duration_ms=3000):
|
||||
"""Scans for nearby BLE devices."""
|
||||
duration_s = duration_ms / 1000.0
|
||||
results = {}
|
||||
was_advertising = self._is_advertising
|
||||
if was_advertising:
|
||||
try:
|
||||
self.ble.stop_advertising()
|
||||
except:
|
||||
pass
|
||||
self._is_advertising = False
|
||||
|
||||
try:
|
||||
print("Starting BLE scan...")
|
||||
for adv in self.ble.start_scan(timeout=duration_s):
|
||||
# Clean up address representation (mac address)
|
||||
mac = str(adv.address).replace("Address(", "").replace(")", "").strip()
|
||||
name = adv.complete_name or ""
|
||||
results[mac] = {"rssi": adv.rssi, "name": name}
|
||||
self.ble.stop_scan()
|
||||
except Exception as e:
|
||||
print(f"BLE scan error: {e}")
|
||||
|
||||
if was_advertising:
|
||||
self._start_advertise()
|
||||
return results
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self.ble.stop_advertising()
|
||||
except:
|
||||
pass
|
||||
self._is_advertising = False
|
||||
print("BLE closed.")
|
||||
Reference in New Issue
Block a user