feat: Add identity-based device naming for BLE discovery (Protocol v2.1)
Implement automatic device name generation from Transport.identity hash
to enable reliable peer discovery when bluezero service_uuid exposure
is unreliable.
Changes:
- Auto-generate device_name as RNS-{32-hex-identity} if not configured
- Parse peer identity from device name pattern (RNS-[0-9a-f]{32})
- Update GATT server device_name before advertising
- Store parsed identities in address_to_identity mapping
Limitations discovered:
- bluezero Peripheral uses system hostname for BLE local_name, not
the device_name parameter we set
- BlueZ D-Bus cache issues cause service_uuid exposure to be unreliable
- Reboot + cache clear (/var/lib/bluetooth/*/cache) temporarily fixes
service_uuid visibility
Current status:
- Bidirectional discovery works via service_uuid after fresh reboot
- Identity parsing infrastructure ready for future manufacturer_data approach
- Fallback to Protocol v1 address-based tracking remains functional
Tested on Raspberry Pi 4 with BlueZ 5.76, bluezero 0.9.1, bleak 1.1.1
Generated with Claude Code (https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
07e1f2e426
commit
cdd642a70f
1 changed files with 41 additions and 4 deletions
|
|
@ -348,7 +348,10 @@ class BLEInterface(Interface):
|
|||
|
||||
# BLE configuration
|
||||
self.service_uuid = c.get("service_uuid", BLEInterface.SERVICE_UUID)
|
||||
self.device_name = c.get("device_name", f"Reticulum-{RNS.Identity.full_hash(self.name.encode())[:4].hex()}")
|
||||
# Device name will be set to identity-based name after Transport.identity is available
|
||||
# Format: RNS-{identity_hash} where identity_hash is first 16 hex chars of Transport.identity
|
||||
# This enables reliable discovery even when bluezero doesn't expose service UUIDs to Bleak
|
||||
self.device_name = c.get("device_name", None) # Will be auto-generated from identity if None
|
||||
self.discovery_interval = float(c.get("discovery_interval", BLEInterface.DISCOVERY_INTERVAL))
|
||||
self.max_peers = int(c.get("max_connections", BLEInterface.MAX_PEERS))
|
||||
self.min_rssi = int(c.get("min_rssi", BLEInterface.MIN_RSSI))
|
||||
|
|
@ -542,12 +545,27 @@ class BLEInterface(Interface):
|
|||
elapsed = time.time() - start_time
|
||||
RNS.log(f"{self} ✓ Transport.identity available after {elapsed:.1f}s", RNS.LOG_INFO)
|
||||
|
||||
# Generate identity-based device name if not configured
|
||||
# Protocol v2.1: Encode full identity.hash (16 bytes) in BLE device name for reliable discovery
|
||||
# This bypasses bluezero service_uuid exposure bug (service_uuids=[] in Bleak scans)
|
||||
# Format: RNS-{32-hex-chars} = RNS-{16-byte-identity-hex} (36 chars, fits in 248-byte BLE name limit)
|
||||
if self.device_name is None:
|
||||
identity_str = identity_hash.hex() # Full 16 bytes as 32 hex chars
|
||||
self.device_name = f"RNS-{identity_str}"
|
||||
RNS.log(f"{self} Auto-generated identity-based device name: {self.device_name}", RNS.LOG_INFO)
|
||||
else:
|
||||
RNS.log(f"{self} Using configured device name: {self.device_name}", RNS.LOG_INFO)
|
||||
|
||||
# Set identity on GATT server
|
||||
self.gatt_server.set_transport_identity(identity_hash)
|
||||
RNS.log(f"{self} Transport.identity set on GATT server: {identity_hash.hex()}", RNS.LOG_INFO)
|
||||
|
||||
# Update GATT server's device_name to use identity-based name
|
||||
self.gatt_server.device_name = self.device_name
|
||||
RNS.log(f"{self} GATT server will advertise as: {self.device_name}", RNS.LOG_INFO)
|
||||
|
||||
# Start GATT server with valid identity
|
||||
RNS.log(f"{self} Starting GATT server with Protocol v2 identity...", RNS.LOG_INFO)
|
||||
RNS.log(f"{self} Starting GATT server with Protocol v2.1 (identity-based naming)...", RNS.LOG_INFO)
|
||||
asyncio.run_coroutine_threadsafe(self._start_server(), self.loop)
|
||||
return
|
||||
except Exception as e:
|
||||
|
|
@ -966,8 +984,9 @@ class BLEInterface(Interface):
|
|||
match_method = "service UUID"
|
||||
|
||||
# Fallback: Match by device name pattern
|
||||
# This handles cases where bluezero/BlueZ don't include service UUID in advertisement
|
||||
# Common reasons: advertisement packet size limit (31 bytes), BlueZ configuration
|
||||
# Protocol v2.1: Extract identity from device name (format: RNS-{16-char-hex-hash})
|
||||
# This bypasses bluezero service_uuid bug where service_uuids=[] in Bleak scans
|
||||
# Also handles Protocol v1 devices with generic RNS- names
|
||||
elif device.name and device.name.startswith("RNS-"):
|
||||
# Ensure it's not our own device (self-filtering)
|
||||
if device.name != self.device_name:
|
||||
|
|
@ -980,6 +999,24 @@ class BLEInterface(Interface):
|
|||
rssi = adv_data.rssi
|
||||
device_name = device.name or f"BLE-{device.address[-8:]}"
|
||||
|
||||
# Protocol v2.1: Try to parse identity from device name (format: RNS-{32-hex-chars})
|
||||
# This bypasses the need to read Identity characteristic over GATT
|
||||
peer_identity_from_name = None
|
||||
if device.name and match_method == "name pattern (fallback)":
|
||||
import re
|
||||
identity_pattern = r'^RNS-([0-9a-f]{32})$' # 32 hex chars = 16 bytes
|
||||
name_match = re.match(identity_pattern, device.name)
|
||||
if name_match:
|
||||
try:
|
||||
# Parse full 16-byte identity.hash from device name
|
||||
identity_hex = name_match.group(1)
|
||||
peer_identity_from_name = bytes.fromhex(identity_hex) # 16 bytes
|
||||
self.address_to_identity[device.address] = peer_identity_from_name
|
||||
self.identity_to_address[identity_hex[:16]] = device.address # Store mapping
|
||||
RNS.log(f"{self} parsed identity from device name {device.name}: {identity_hex[:16]}...", RNS.LOG_INFO)
|
||||
except (ValueError, IndexError) as e:
|
||||
RNS.log(f"{self} failed to parse identity from name {device.name}: {e}", RNS.LOG_DEBUG)
|
||||
|
||||
# Log all matching peers at DEBUG level for visibility
|
||||
RNS.log(f"{self} found matching peer {device_name} ({device.address}) via {match_method}, "
|
||||
f"RSSI: {rssi}dBm (min: {self.min_rssi}dBm)", RNS.LOG_DEBUG)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue