fix(ble): Remove device name from advertisements to fix packet size limit
Fixes "Failed to register advertisement" error (BlueZ error 0x03) caused by
device name exceeding 31-byte BLE advertisement packet limit.
Changes:
- Make device_name optional (default: None) to save advertisement space
- Remove auto-generation of long identity-based names (RNS-{32-hex-identity})
- Update driver to handle None device names when creating peripheral
- Use full 16-byte identity (32 hex chars) for fragmenter keys to avoid collisions
- Update documentation to reflect device name is optional and discovery is UUID-based
Discovery is based on service UUID matching only. Identity is obtained from
the Identity GATT characteristic after connection, not from device name.
Tested on Raspberry Pi Zero W with BlueZ 5.82 - advertisement now registers
successfully (ActiveInstances: 1).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
971f9e47bb
commit
b503718bf8
5 changed files with 101 additions and 101 deletions
|
|
@ -64,10 +64,10 @@ The BLE Reticulum Protocol enables mesh networking over Bluetooth Low Energy (BL
|
||||||
- Centrals read peripheral identities via GATT characteristic
|
- Centrals read peripheral identities via GATT characteristic
|
||||||
- Address-based fragmenter keys
|
- Address-based fragmenter keys
|
||||||
|
|
||||||
### v2.1 (Identity-Based Naming)
|
### v2.1 (Identity-Based Naming) - Deprecated
|
||||||
- Device names encode identity: `RNS-{32-hex-identity-hash}`
|
- **Deprecated:** Device names previously encoded identity: `RNS-{32-hex-identity-hash}`
|
||||||
- Bypasses bluezero service UUID bug (name-based discovery fallback)
|
- **Issue:** 36-character names exceeded 31-byte BLE advertisement packet limit
|
||||||
- Identity mappings stored during discovery
|
- **Replaced in v2.2+:** Device names now optional (default: omitted)
|
||||||
|
|
||||||
### v2.2 (Current - Identity Handshake)
|
### v2.2 (Current - Identity Handshake)
|
||||||
- **Identity handshake:** Centrals send 16-byte identity to peripherals
|
- **Identity handshake:** Centrals send 16-byte identity to peripherals
|
||||||
|
|
@ -89,31 +89,28 @@ All Reticulum BLE devices advertise this service UUID to enable discovery.
|
||||||
|
|
||||||
### Device Naming Convention
|
### Device Naming Convention
|
||||||
|
|
||||||
**Format:**
|
**Device names are optional** and configurable via the `device_name` parameter in the BLE interface configuration. The default is `None` (no device name in advertisement).
|
||||||
|
|
||||||
|
**Rationale:**
|
||||||
|
- BLE advertisements have a **31-byte packet size limit**
|
||||||
|
- Including the 128-bit service UUID (18 bytes) and flags (3 bytes) leaves only ~10 bytes
|
||||||
|
- Device names compete for limited advertisement space
|
||||||
|
- **Discovery is based on service UUID matching only** (device name is not used for peer discovery)
|
||||||
|
- **Identity is obtained from the Identity GATT characteristic** after connection, not from the device name
|
||||||
|
|
||||||
|
**Recommended:**
|
||||||
|
- **Omit device name** (default: `None`) to maximize advertisement reliability
|
||||||
|
- If a name is needed for debugging, keep it very short (max 8 characters)
|
||||||
|
- Example: `"RNS"`, `"Node1"`, etc.
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```ini
|
||||||
|
[[BLE Interface]]
|
||||||
|
type = BLEInterface
|
||||||
|
enabled = True
|
||||||
|
# device_name = None # Default: no device name (recommended)
|
||||||
|
# device_name = RNS # Optional: short name for debugging
|
||||||
```
|
```
|
||||||
RNS-{32-hex-characters}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
```
|
|
||||||
RNS-680069b61fa51cde5a751ed2396ce46d
|
|
||||||
```
|
|
||||||
|
|
||||||
Where `680069b61fa51cde5a751ed2396ce46d` is derived from the device's Reticulum identity:
|
|
||||||
- Take `RNS.Identity.full_hash(identity)` (cryptographic hash)
|
|
||||||
- Extract first 16 bytes: `[:16]`
|
|
||||||
- Convert to hexadecimal: `.hex()` → 32 hex characters
|
|
||||||
- Result: Device name contains 32-character identity fingerprint
|
|
||||||
|
|
||||||
### Why Embed Identity in Name?
|
|
||||||
|
|
||||||
The bluezero GATT server library (used for peripheral mode) has a known bug where service UUIDs are not properly exposed in BLE advertisements when queried via Bleak scanners. Clients see `service_uuids=[]` even though the service is registered.
|
|
||||||
|
|
||||||
**Workaround:**
|
|
||||||
By embedding the identity in the device name, scanners can:
|
|
||||||
1. Match by service UUID (preferred, when it works)
|
|
||||||
2. Fall back to name pattern matching: `^RNS-[0-9a-f]{32}$`
|
|
||||||
3. Extract identity directly from the name, bypassing GATT characteristic reads
|
|
||||||
|
|
||||||
### Advertisement Interval
|
### Advertisement Interval
|
||||||
|
|
||||||
|
|
@ -316,41 +313,37 @@ BLE devices can **rotate MAC addresses** for privacy reasons. If fragmenters/rea
|
||||||
|
|
||||||
### Solution: Identity-Based Keys
|
### Solution: Identity-Based Keys
|
||||||
|
|
||||||
All peer-specific data structures (fragmenters, reassemblers, interfaces) are keyed by a **16-character hex string derived from the peer's identity hash**.
|
All peer-specific data structures (fragmenters, reassemblers, interfaces) are keyed by a **32-character hex string representing the full 16-byte peer identity**.
|
||||||
|
|
||||||
### Key Computation
|
### Key Computation
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def _get_fragmenter_key(self, peer_identity, peer_address):
|
def _get_fragmenter_key(self, peer_identity, peer_address):
|
||||||
"""
|
"""
|
||||||
Compute fragmenter/reassembler dictionary key using identity hash.
|
Compute fragmenter/reassembler dictionary key using full identity.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
peer_identity: 16-byte identity hash
|
peer_identity: 16-byte identity hash
|
||||||
peer_address: BLE MAC address (unused in v2.2, kept for compatibility)
|
peer_address: BLE MAC address (unused in v2.2, kept for compatibility)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
16-character hex string (e.g., "680069b61fa51cde")
|
32-character hex string representing full 16-byte identity
|
||||||
"""
|
"""
|
||||||
return RNS.Identity.full_hash(peer_identity)[:16].hex()[:16]
|
return peer_identity.hex()
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key Derivation Steps:**
|
**Key Derivation:**
|
||||||
1. `RNS.Identity.full_hash(peer_identity)` - Compute cryptographic hash
|
- Uses the **full 16-byte peer identity** directly as hex string (32 characters)
|
||||||
2. `[:16]` - Take first 16 bytes
|
- Avoids collision risk that would exist with shortened keys
|
||||||
3. `.hex()` - Convert to 32 hex characters
|
- Example: `"680069b61fa51cde5a751ed2396ce46d"` (32 hex chars = 16 bytes)
|
||||||
4. `[:16]` - Take first 16 hex characters (representing 8 bytes)
|
|
||||||
5. Result: 16-character hex string used as dictionary key
|
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```python
|
```python
|
||||||
peer_identity = bytes.fromhex("680069b61fa51cde5a751ed2396ce46d") # 16 bytes from device name
|
peer_identity = bytes.fromhex("680069b61fa51cde5a751ed2396ce46d") # 16 bytes from Identity characteristic
|
||||||
frag_key = _get_fragmenter_key(peer_identity, "B8:27:EB:10:28:CD")
|
frag_key = _get_fragmenter_key(peer_identity, "B8:27:EB:10:28:CD")
|
||||||
# Result: "680069b61fa51cde" (16 hex chars, first half of hash)
|
# Result: "680069b61fa51cde5a751ed2396ce46d" (32 hex chars, full identity)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** The fragmenter key (16 hex chars) is shorter than the device name identity (32 hex chars) for efficiency, but both are derived from the same identity hash.
|
|
||||||
|
|
||||||
### Identity Mapping Tables
|
### Identity Mapping Tables
|
||||||
|
|
||||||
Two dictionaries maintain bidirectional identity ↔ address mappings:
|
Two dictionaries maintain bidirectional identity ↔ address mappings:
|
||||||
|
|
@ -361,30 +354,30 @@ self.address_to_identity = {
|
||||||
"B8:27:EB:10:28:CD": b'\x68\x00\x69\xb6\x1f\xa5\x1c\xde...',
|
"B8:27:EB:10:28:CD": b'\x68\x00\x69\xb6\x1f\xa5\x1c\xde...',
|
||||||
}
|
}
|
||||||
|
|
||||||
# 16-char identity hash → MAC address
|
# Full 32-char identity hash → MAC address
|
||||||
self.identity_to_address = {
|
self.identity_to_address = {
|
||||||
"680069b61fa51cde": "B8:27:EB:10:28:CD",
|
"680069b61fa51cde5a751ed2396ce46d": "B8:27:EB:10:28:CD",
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dictionary Structures
|
### Dictionary Structures
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Fragmenters (keyed by identity hash)
|
# Fragmenters (keyed by full 32-char identity hash)
|
||||||
self.fragmenters = {
|
self.fragmenters = {
|
||||||
"680069b61fa51cde": BLEFragmenter(mtu=517),
|
"680069b61fa51cde5a751ed2396ce46d": BLEFragmenter(mtu=517),
|
||||||
"a1b2c3d4e5f6g7h8": BLEFragmenter(mtu=23),
|
"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6": BLEFragmenter(mtu=23),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Reassemblers (keyed by identity hash)
|
# Reassemblers (keyed by full 32-char identity hash)
|
||||||
self.reassemblers = {
|
self.reassemblers = {
|
||||||
"680069b61fa51cde": BLEReassembler(timeout=30.0),
|
"680069b61fa51cde5a751ed2396ce46d": BLEReassembler(timeout=30.0),
|
||||||
"a1b2c3d4e5f6g7h8": BLEReassembler(timeout=30.0),
|
"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6": BLEReassembler(timeout=30.0),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Peer interfaces (keyed by identity hash)
|
# Peer interfaces (keyed by full 32-char identity hash)
|
||||||
self.spawned_interfaces = {
|
self.spawned_interfaces = {
|
||||||
"680069b61fa51cde": BLEPeerInterface(...),
|
"680069b61fa51cde5a751ed2396ce46d": BLEPeerInterface(...),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -525,12 +518,10 @@ Device A (Lower MAC) Device B (Higher MAC)
|
||||||
| |
|
| |
|
||||||
| 1. Start scanning (0.5-2s) | 1. Start advertising
|
| 1. Start scanning (0.5-2s) | 1. Start advertising
|
||||||
| | - Service UUID
|
| | - Service UUID
|
||||||
| | - Device name: RNS-{identity}
|
| | - Device name (optional)
|
||||||
| |
|
| |
|
||||||
| 2. Discover Device B |
|
| 2. Discover Device B |
|
||||||
| - Match by service UUID or name |
|
| - Match by service UUID |
|
||||||
| - Extract identity from name |
|
|
||||||
| - Store in address_to_identity |
|
|
||||||
| |
|
| |
|
||||||
| 3. MAC sorting check |
|
| 3. MAC sorting check |
|
||||||
| my_mac < peer_mac → I connect |
|
| my_mac < peer_mac → I connect |
|
||||||
|
|
@ -572,14 +563,12 @@ Device A (Lower MAC) Device B (Higher MAC)
|
||||||
|
|
||||||
1. **Scan for BLE devices** (0.5-2.0 seconds depending on power mode)
|
1. **Scan for BLE devices** (0.5-2.0 seconds depending on power mode)
|
||||||
2. **Match peers:**
|
2. **Match peers:**
|
||||||
- Primary: Check `service_uuids` for Reticulum UUID
|
- Check `service_uuids` for Reticulum service UUID
|
||||||
- Fallback: Check device name matches `^RNS-[0-9a-f]{32}$`
|
- Device name is not used for matching (optional/omitted)
|
||||||
3. **Extract identity:**
|
3. **Score peers** by RSSI, history, recency
|
||||||
- Parse 32 hex chars from device name
|
4. **Select best peer** for connection
|
||||||
- Convert to 16-byte identity
|
|
||||||
- Store in `address_to_identity[peer_address] = identity`
|
**Note:** Identity is obtained from the Identity GATT characteristic after connection, not from the device name or during discovery.
|
||||||
4. **Score peers** by RSSI, history, recency
|
|
||||||
5. **Select best peer** for connection
|
|
||||||
|
|
||||||
### Connection Phase (Device A → Device B)
|
### Connection Phase (Device A → Device B)
|
||||||
|
|
||||||
|
|
@ -1382,8 +1371,7 @@ sequenceDiagram
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
BLE->>BLE: Generate identity-based device name
|
Note over BLE: Device name is optional (default: None)<br/>to fit in 31-byte BLE advertisement packet
|
||||||
Note over BLE: Format: RNS-{32-hex-identity-hash}<br/>Example: RNS-680069b61fa51cde5a751ed2396ce46d
|
|
||||||
|
|
||||||
BLE->>Driver: set_identity(identity_16_bytes)
|
BLE->>Driver: set_identity(identity_16_bytes)
|
||||||
Driver-->>BLE: Identity set
|
Driver-->>BLE: Identity set
|
||||||
|
|
@ -1440,7 +1428,7 @@ sequenceDiagram
|
||||||
Note over Scanner: Scan cycle (every 5s)
|
Note over Scanner: Scan cycle (every 5s)
|
||||||
Scanner->>Scanner: Start BLE scan
|
Scanner->>Scanner: Start BLE scan
|
||||||
|
|
||||||
Peer-->>Scanner: Advertisement<br/>Service: 37145b00-...<br/>Name: RNS-680069b61fa51cde...<br/>RSSI: -45 dBm
|
Peer-->>Scanner: Advertisement<br/>Service: 37145b00-...<br/>Name: (optional/omitted)<br/>RSSI: -45 dBm
|
||||||
|
|
||||||
Scanner->>BLE: on_device_discovered(address, rssi, name, service_uuids)
|
Scanner->>BLE: on_device_discovered(address, rssi, name, service_uuids)
|
||||||
|
|
||||||
|
|
@ -1583,7 +1571,7 @@ sequenceDiagram
|
||||||
|
|
||||||
Peripheral->>Peripheral: Extract central's identity
|
Peripheral->>Peripheral: Extract central's identity
|
||||||
Peripheral->>Peripheral: Compute identity hash
|
Peripheral->>Peripheral: Compute identity hash
|
||||||
Note over Peripheral: hash = RNS.Identity.full_hash(identity)[:16].hex()[:16]<br/>Steps: hash → first 16 bytes → hex → first 16 chars<br/>Example: "680069b61fa51cde"
|
Note over Peripheral: hash = identity.hex()<br/>Uses full 16-byte identity as 32 hex chars<br/>Example: "680069b61fa51cde5a751ed2396ce46d"
|
||||||
|
|
||||||
Peripheral->>Peripheral: Store bidirectional mappings
|
Peripheral->>Peripheral: Store bidirectional mappings
|
||||||
Note over Peripheral: address_to_identity[central_addr] = identity_16_bytes<br/>identity_to_address[identity_hash] = central_addr
|
Note over Peripheral: address_to_identity[central_addr] = identity_16_bytes<br/>identity_to_address[identity_hash] = central_addr
|
||||||
|
|
@ -1626,10 +1614,10 @@ sequenceDiagram
|
||||||
**Central Side:**
|
**Central Side:**
|
||||||
```python
|
```python
|
||||||
address_to_identity["B8:27:EB:A8:A7:22"] = b'\x68\x00\x69\xb6...' # From discovery
|
address_to_identity["B8:27:EB:A8:A7:22"] = b'\x68\x00\x69\xb6...' # From discovery
|
||||||
identity_to_address["680069b61fa51cde"] = "B8:27:EB:A8:A7:22"
|
identity_to_address["680069b61fa51cde5a751ed2396ce46d"] = "B8:27:EB:A8:A7:22"
|
||||||
fragmenters["680069b61fa51cde"] = BLEFragmenter(mtu=517)
|
fragmenters["680069b61fa51cde5a751ed2396ce46d"] = BLEFragmenter(mtu=517)
|
||||||
reassemblers["680069b61fa51cde"] = BLEReassembler()
|
reassemblers["680069b61fa51cde5a751ed2396ce46d"] = BLEReassembler()
|
||||||
spawned_interfaces["680069b61fa51cde"] = BLEPeerInterface(...)
|
spawned_interfaces["680069b61fa51cde5a751ed2396ce46d"] = BLEPeerInterface(...)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Peripheral Side:**
|
**Peripheral Side:**
|
||||||
|
|
@ -1667,7 +1655,7 @@ sequenceDiagram
|
||||||
Note over Transport: 233-byte announce packet<br/>Contains: identity, public key, hops, etc.
|
Note over Transport: 233-byte announce packet<br/>Contains: identity, public key, hops, etc.
|
||||||
|
|
||||||
BLE_If->>BLE_If: Look up fragmenter by identity hash
|
BLE_If->>BLE_If: Look up fragmenter by identity hash
|
||||||
Note over BLE_If: Key: "680069b61fa51cde"
|
Note over BLE_If: Key: "680069b61fa51cde5a751ed2396ce46d"
|
||||||
|
|
||||||
BLE_If->>Frag: fragment_packet(data, mtu=23)
|
BLE_If->>Frag: fragment_packet(data, mtu=23)
|
||||||
activate Frag
|
activate Frag
|
||||||
|
|
|
||||||
|
|
@ -159,8 +159,8 @@ Add the BLE interface to your Reticulum configuration (`~/.reticulum/config`):
|
||||||
type = BLEInterface
|
type = BLEInterface
|
||||||
enabled = yes
|
enabled = yes
|
||||||
|
|
||||||
# Optional: customize device name
|
# Optional: set short device name (max 8 chars recommended, default: none)
|
||||||
# device_name = My-Reticulum-Node
|
# device_name = RNS
|
||||||
```
|
```
|
||||||
|
|
||||||
For detailed configuration options, see [`examples/config_example.toml`](examples/config_example.toml).
|
For detailed configuration options, see [`examples/config_example.toml`](examples/config_example.toml).
|
||||||
|
|
@ -195,7 +195,7 @@ The BLE interface supports extensive configuration options. See [`examples/confi
|
||||||
|
|
||||||
### Key Configuration Options
|
### Key Configuration Options
|
||||||
|
|
||||||
- **`device_name`**: Advertised device name (auto-generated if not specified)
|
- **`device_name`**: Optional BLE device name (default: none, keep short if used, max 8 chars recommended)
|
||||||
- **`service_uuid`**: BLE service UUID (must match on all devices)
|
- **`service_uuid`**: BLE service UUID (must match on all devices)
|
||||||
- **`enable_peripheral`**: Accept incoming connections (default: yes)
|
- **`enable_peripheral`**: Accept incoming connections (default: yes)
|
||||||
- **`enable_central`**: Scan and connect to peers (default: yes)
|
- **`enable_central`**: Scan and connect to peers (default: yes)
|
||||||
|
|
|
||||||
|
|
@ -288,10 +288,11 @@ class BLEInterface(Interface):
|
||||||
|
|
||||||
# BLE configuration
|
# BLE configuration
|
||||||
self.service_uuid = c.get("service_uuid", BLEInterface.SERVICE_UUID)
|
self.service_uuid = c.get("service_uuid", BLEInterface.SERVICE_UUID)
|
||||||
# Device name will be set to identity-based name after Transport.identity is available
|
# Device name for BLE advertising (optional, configurable via config file)
|
||||||
# Format: RNS-{identity_hash} where identity_hash is first 16 hex chars of Transport.identity
|
# Default is None (no device name) to save advertisement packet space (31-byte limit).
|
||||||
# This enables reliable discovery even when bluezero doesn't expose service UUIDs to Bleak
|
# Discovery is based on service UUID only. Identity is obtained from the Identity
|
||||||
self.device_name = c.get("device_name", None) # Will be auto-generated from identity if None
|
# characteristic after connection. If set, keep it short (max 8 chars recommended).
|
||||||
|
self.device_name = c.get("device_name", None)
|
||||||
self.discovery_interval = float(c.get("discovery_interval", BLEInterface.DISCOVERY_INTERVAL))
|
self.discovery_interval = float(c.get("discovery_interval", BLEInterface.DISCOVERY_INTERVAL))
|
||||||
self.max_peers = int(c.get("max_connections", BLEInterface.MAX_PEERS))
|
self.max_peers = int(c.get("max_connections", BLEInterface.MAX_PEERS))
|
||||||
self.min_rssi = int(c.get("min_rssi", BLEInterface.MIN_RSSI))
|
self.min_rssi = int(c.get("min_rssi", BLEInterface.MIN_RSSI))
|
||||||
|
|
@ -487,19 +488,16 @@ class BLEInterface(Interface):
|
||||||
elapsed = time.time() - start_time
|
elapsed = time.time() - start_time
|
||||||
RNS.log(f"{self} Transport.identity available after {elapsed:.1f}s", RNS.LOG_INFO)
|
RNS.log(f"{self} Transport.identity available after {elapsed:.1f}s", RNS.LOG_INFO)
|
||||||
|
|
||||||
# Generate identity-based device name if not configured
|
|
||||||
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)
|
|
||||||
|
|
||||||
# Set identity on driver
|
# Set identity on driver
|
||||||
self.driver.set_identity(identity_hash)
|
self.driver.set_identity(identity_hash)
|
||||||
|
|
||||||
# Start advertising
|
# Start advertising
|
||||||
try:
|
try:
|
||||||
self.driver.start_advertising(self.device_name, identity_hash)
|
self.driver.start_advertising(self.device_name, identity_hash)
|
||||||
RNS.log(f"{self} Started advertising as {self.device_name}", RNS.LOG_INFO)
|
if self.device_name:
|
||||||
|
RNS.log(f"{self} Started advertising as {self.device_name}", RNS.LOG_INFO)
|
||||||
|
else:
|
||||||
|
RNS.log(f"{self} Started advertising (no device name)", RNS.LOG_INFO)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log(f"{self} Failed to start advertising: {e}", RNS.LOG_ERROR)
|
RNS.log(f"{self} Failed to start advertising: {e}", RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
|
@ -1138,16 +1136,16 @@ class BLEInterface(Interface):
|
||||||
|
|
||||||
def _get_fragmenter_key(self, peer_identity, peer_address):
|
def _get_fragmenter_key(self, peer_identity, peer_address):
|
||||||
"""
|
"""
|
||||||
Compute fragmenter/reassembler dictionary key using identity hash.
|
Compute fragmenter/reassembler dictionary key using full identity hash.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
peer_identity: 16-byte peer identity
|
peer_identity: 16-byte peer identity
|
||||||
peer_address: BLE MAC address (unused, kept for compatibility)
|
peer_address: BLE MAC address (unused, kept for compatibility)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Identity hash (16 hex chars)
|
str: Full 16-byte identity as 32 hex characters
|
||||||
"""
|
"""
|
||||||
return RNS.Identity.full_hash(peer_identity)[:16].hex()[:16]
|
return peer_identity.hex()
|
||||||
|
|
||||||
def _compute_identity_hash(self, peer_identity):
|
def _compute_identity_hash(self, peer_identity):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -107,10 +107,15 @@ class BLEDriverInterface(ABC):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def start_advertising(self, device_name: str, identity: bytes):
|
def start_advertising(self, device_name: Optional[str], identity: bytes):
|
||||||
"""
|
"""
|
||||||
Starts advertising the configured service UUID and the given device name.
|
Starts advertising the configured service UUID and optionally a device name.
|
||||||
The identity parameter is used to populate the Identity characteristic.
|
The identity parameter is used to populate the Identity characteristic.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
device_name: Optional device name to include in advertisement (None to omit).
|
||||||
|
Keep short (max 8 chars) to fit in 31-byte BLE advertisement packet.
|
||||||
|
identity: 16-byte identity hash for the Identity characteristic.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -622,7 +622,7 @@ class LinuxBluetoothDriver(BLEDriverInterface):
|
||||||
# Advertising (Peripheral Mode)
|
# Advertising (Peripheral Mode)
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
|
|
||||||
def start_advertising(self, device_name: str, identity: bytes):
|
def start_advertising(self, device_name: Optional[str], identity: bytes):
|
||||||
"""Start advertising as a BLE peripheral."""
|
"""Start advertising as a BLE peripheral."""
|
||||||
if not self._running:
|
if not self._running:
|
||||||
self._log("Cannot start advertising: driver not running", "ERROR")
|
self._log("Cannot start advertising: driver not running", "ERROR")
|
||||||
|
|
@ -638,7 +638,10 @@ class LinuxBluetoothDriver(BLEDriverInterface):
|
||||||
self._log("Already advertising", "DEBUG")
|
self._log("Already advertising", "DEBUG")
|
||||||
return
|
return
|
||||||
|
|
||||||
self._log(f"Starting BLE advertising as '{device_name}'...")
|
if device_name:
|
||||||
|
self._log(f"Starting BLE advertising as '{device_name}'...")
|
||||||
|
else:
|
||||||
|
self._log("Starting BLE advertising (no device name)...")
|
||||||
|
|
||||||
# Set identity
|
# Set identity
|
||||||
self.set_identity(identity)
|
self.set_identity(identity)
|
||||||
|
|
@ -1263,7 +1266,7 @@ class BluezeroGATTServer:
|
||||||
|
|
||||||
self._log(f"Identity set: {identity_bytes.hex()}")
|
self._log(f"Identity set: {identity_bytes.hex()}")
|
||||||
|
|
||||||
def start(self, device_name: str):
|
def start(self, device_name: Optional[str]):
|
||||||
"""Start GATT server and advertising."""
|
"""Start GATT server and advertising."""
|
||||||
if self.running:
|
if self.running:
|
||||||
self._log("Server already running", "WARNING")
|
self._log("Server already running", "WARNING")
|
||||||
|
|
@ -1273,7 +1276,10 @@ class BluezeroGATTServer:
|
||||||
if not self.identity_bytes:
|
if not self.identity_bytes:
|
||||||
raise RuntimeError("Identity must be set before starting GATT server. Call set_identity() first.")
|
raise RuntimeError("Identity must be set before starting GATT server. Call set_identity() first.")
|
||||||
|
|
||||||
self._log(f"Starting GATT server with device name '{device_name}'...")
|
if device_name:
|
||||||
|
self._log(f"Starting GATT server with device name '{device_name}'...")
|
||||||
|
else:
|
||||||
|
self._log("Starting GATT server (no device name)...")
|
||||||
|
|
||||||
# Reset events
|
# Reset events
|
||||||
self.stop_event.clear()
|
self.stop_event.clear()
|
||||||
|
|
@ -1362,11 +1368,14 @@ class BluezeroGATTServer:
|
||||||
adapter_address = local_adapter.address
|
adapter_address = local_adapter.address
|
||||||
self._log(f"Using adapter: {adapter_address}", "DEBUG")
|
self._log(f"Using adapter: {adapter_address}", "DEBUG")
|
||||||
|
|
||||||
# Create peripheral
|
# Create peripheral (omit local_name if None to save advertisement packet space)
|
||||||
self.peripheral_obj = peripheral.Peripheral(
|
if device_name:
|
||||||
adapter_address,
|
self.peripheral_obj = peripheral.Peripheral(
|
||||||
local_name=device_name
|
adapter_address,
|
||||||
)
|
local_name=device_name
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.peripheral_obj = peripheral.Peripheral(adapter_address)
|
||||||
|
|
||||||
# Add service
|
# Add service
|
||||||
self.peripheral_obj.add_service(
|
self.peripheral_obj.add_service(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue