Initial commit
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
.venv/
|
||||
venv/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
logs/*.log
|
||||
logs/*.txt
|
||||
.DS_Store
|
||||
.idea/
|
||||
.vscode/
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 PE1HVH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
341
README.md
Normal file
341
README.md
Normal file
@@ -0,0 +1,341 @@
|
||||
# MeshCore GUI
|
||||
|
||||
A graphical user interface for MeshCore mesh network devices via Bluetooth Low Energy (BLE).
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Why This Project Exists
|
||||
|
||||
MeshCore devices like the SenseCAP T1000-E can be managed through two interfaces: USB serial and BLE (Bluetooth Low Energy). The official companion apps communicate with devices over BLE, but they are mobile-only. If you want to manage your MeshCore device from a desktop or laptop, the usual approach is to **flash USB-serial firmware** via the web flasher. However, this replaces the BLE Companion firmware, which means you can no longer use the device with mobile companion apps (Android/iOS).
|
||||
|
||||
This project provides a **native desktop GUI** that connects to your MeshCore device over BLE — no firmware changes required. Your device stays on BLE Companion firmware and remains fully compatible with the mobile apps. The application is written in Python using cross-platform libraries and runs on **Linux, macOS and Windows**.
|
||||
|
||||
> **Note:** This application has only been tested on Linux (Ubuntu 24.04). macOS and Windows should work since all dependencies (`bleak`, `nicegui`, `meshcore`) are cross-platform, but this has not been verified. Feedback and contributions for other platforms are welcome.
|
||||
|
||||
Under the hood it uses `bleak` for Bluetooth Low Energy (which talks to BlueZ on Linux, CoreBluetooth on macOS, and WinRT on Windows), `meshcore` as the protocol layer, and `NiceGUI` for the web-based interface.
|
||||
|
||||
> **Linux users:** BLE on Linux can be temperamental. BlueZ occasionally gets into a bad state, especially after repeated connect/disconnect cycles. If you run into connection issues, see the [Troubleshooting Guide](docs/TROUBLESHOOTING.md). On macOS and Windows, BLE is generally more stable out of the box.
|
||||
|
||||
## TODO
|
||||
|
||||
- **Message route visualization** — Display message paths on the map showing the route (hops) each message has taken through the mesh network
|
||||
- **Message persistence** — Store sent and received messages to disk so chat history is preserved across sessions
|
||||
|
||||
## Features
|
||||
|
||||
- **Real-time Dashboard** - Device info, contacts, messages and RX log
|
||||
- **Interactive Map** - Leaflet map with markers for own position and contacts
|
||||
- **Channel Messages** - Send and receive messages on channels
|
||||
- **Direct Messages** - Click on a contact to send a DM
|
||||
- **Message Filtering** - Filter messages per channel via checkboxes
|
||||
- **Threaded Architecture** - BLE communication in separate thread for stable UI
|
||||
|
||||
## Screenshot
|
||||
|
||||
<img width="1002" height="532" alt="Screenshot from 2026-02-03 10-23-25" src="https://github.com/user-attachments/assets/7bc56b94-407c-4e20-aa30-8b2e0f03f820" />
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.10+
|
||||
- Bluetooth Low Energy compatible adapter (built-in or USB)
|
||||
- MeshCore device with BLE Companion firmware
|
||||
|
||||
### Platform support
|
||||
|
||||
| Platform | BLE Backend | Status |
|
||||
|---|---|---|
|
||||
| Linux (Ubuntu/Debian) | BlueZ/D-Bus | ✅ Tested |
|
||||
| macOS | CoreBluetooth | ⬜ Untested |
|
||||
| Windows 10/11 | WinRT | ⬜ Untested |
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. System dependencies
|
||||
|
||||
**Linux (Ubuntu/Debian):**
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install python3-pip python3-venv bluetooth bluez
|
||||
```
|
||||
|
||||
**macOS:**
|
||||
```bash
|
||||
# Python 3.10+ via Homebrew (if not already installed)
|
||||
brew install python
|
||||
```
|
||||
No additional Bluetooth packages needed — macOS has CoreBluetooth built in.
|
||||
|
||||
**Windows:**
|
||||
- Install [Python 3.10+](https://www.python.org/downloads/) (check "Add to PATH" during installation)
|
||||
- No additional Bluetooth packages needed — Windows 10/11 has WinRT built in.
|
||||
|
||||
### 2. Clone the repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/pe1hvh/meshcore-gui.git
|
||||
cd meshcore-gui
|
||||
```
|
||||
|
||||
### 3. Create virtual environment
|
||||
|
||||
**Linux / macOS:**
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```cmd
|
||||
python -m venv venv
|
||||
venv\Scripts\activate
|
||||
```
|
||||
|
||||
### 4. Install Python packages
|
||||
|
||||
```bash
|
||||
pip install nicegui meshcore bleak
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Activate the virtual environment
|
||||
|
||||
**Linux / macOS:**
|
||||
```bash
|
||||
cd meshcore-gui
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```cmd
|
||||
cd meshcore-gui
|
||||
venv\Scripts\activate
|
||||
```
|
||||
|
||||
### 2. Find your BLE device address
|
||||
|
||||
**Linux:**
|
||||
```bash
|
||||
bluetoothctl scan on
|
||||
```
|
||||
Look for your MeshCore device and note the MAC address (e.g., `literal:AA:BB:CC:DD:EE:FF`).
|
||||
|
||||
**macOS / Windows:**
|
||||
```bash
|
||||
python -c "
|
||||
import asyncio
|
||||
from bleak import BleakScanner
|
||||
async def scan():
|
||||
devices = await BleakScanner.discover(5.0)
|
||||
for d in devices:
|
||||
if 'MeshCore' in (d.name or ''):
|
||||
print(f'{d.address} {d.name}')
|
||||
asyncio.run(scan())
|
||||
"
|
||||
```
|
||||
On macOS the address will be a UUID (e.g., `12345678-ABCD-...`) rather than a MAC address.
|
||||
|
||||
### 3. Configure channels
|
||||
|
||||
Open `meshcore_gui.py` and adjust `CHANNELS_CONFIG` to your own channels:
|
||||
|
||||
```python
|
||||
CHANNELS_CONFIG = [
|
||||
{'idx': 0, 'name': 'Public'},
|
||||
{'idx': 1, 'name': '#test'},
|
||||
{'idx': 2, 'name': 'MyChannel'},
|
||||
{'idx': 3, 'name': '#local'},
|
||||
]
|
||||
```
|
||||
|
||||
**Tip:** Use `meshcli` to determine your channels:
|
||||
|
||||
```bash
|
||||
meshcli -d literal:AA:BB:CC:DD:EE:FF
|
||||
> get_channel 0
|
||||
> get_channel 1
|
||||
# etc.
|
||||
```
|
||||
|
||||
### 4. Start the GUI
|
||||
|
||||
```bash
|
||||
python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF
|
||||
```
|
||||
|
||||
Replace `literal:AA:BB:CC:DD:EE:FF` with the MAC address of your device.
|
||||
|
||||
### 5. Open the interface
|
||||
|
||||
The GUI opens automatically in your browser at `http://localhost:8080`
|
||||
|
||||
## Configuration
|
||||
|
||||
| Setting | Description |
|
||||
|---------|-------------|
|
||||
| `DEBUG` | Set to `True` for verbose logging |
|
||||
| `CHANNELS_CONFIG` | List of channels (hardcoded due to BLE timing issues) |
|
||||
| BLE Address | Command line argument |
|
||||
|
||||
## Functionality
|
||||
|
||||
### Device Info
|
||||
- Name, frequency, SF/BW, TX power, location, firmware version
|
||||
|
||||
### Contacts
|
||||
- List of known nodes with type and location
|
||||
- Click on a contact to send a DM
|
||||
|
||||
### Map
|
||||
- OpenStreetMap with markers for own position and contacts
|
||||
- Shows your own position (blue marker)
|
||||
- Automatically centers on your own position
|
||||
|
||||
### Channel Messages
|
||||
- Select a channel in the dropdown
|
||||
- Type your message and click "Send"
|
||||
- Received messages appear in the messages list
|
||||
- Filter messages via the checkboxes
|
||||
|
||||
### Direct Messages (DM)
|
||||
- Click on a contact in the contacts list
|
||||
- A dialog opens where you can type your message
|
||||
- Click "Send" to send the DM
|
||||
|
||||
### RX Log
|
||||
- Received packets with SNR and type
|
||||
|
||||
### Actions
|
||||
- Refresh data
|
||||
- Send advertisement
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Main Thread │ │ BLE Thread │
|
||||
│ (NiceGUI) │ │ (asyncio) │
|
||||
│ │ │ │
|
||||
│ ┌───────────┐ │ │ ┌───────────┐ │
|
||||
│ │ GUI │◄─┼──┬──┼─►│ BLEWorker │ │
|
||||
│ └───────────┘ │ │ │ └───────────┘ │
|
||||
│ │ │ │ │ │ │
|
||||
│ ▼ │ │ │ ▼ │
|
||||
│ ┌───────────┐ │ │ │ ┌───────────┐ │
|
||||
│ │ Timer │ │ │ │ │ MeshCore │ │
|
||||
│ │ (500ms) │ │ │ │ │ BLE │ │
|
||||
│ └───────────┘ │ │ │ └───────────┘ │
|
||||
└─────────────────┘ │ └─────────────────┘
|
||||
│
|
||||
┌──────┴──────┐
|
||||
│ SharedData │
|
||||
│ (thread- │
|
||||
│ safe) │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
- **BLEWorker**: Runs in separate thread with its own asyncio loop
|
||||
- **SharedData**: Thread-safe data sharing between BLE and GUI
|
||||
- **MeshCoreGUI**: NiceGUI interface in main thread
|
||||
- **Communication**: Via queue (GUI→BLE) and shared state with flags (BLE→GUI)
|
||||
|
||||
## Known Limitations
|
||||
|
||||
1. **Channels hardcoded** - The `get_channel()` function in meshcore-py is unreliable via BLE
|
||||
2. **send_appstart() sometimes fails** - Device info may remain empty with connection problems
|
||||
3. **Initial load time** - GUI waits for BLE data before the first render is complete
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Linux
|
||||
|
||||
For comprehensive Linux BLE troubleshooting (including the `EOFError` / `start_notify` issue), see [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md).
|
||||
|
||||
#### Quick fixes
|
||||
|
||||
##### GUI remains empty / BLE connection fails
|
||||
|
||||
1. First disconnect any existing BLE connections:
|
||||
```bash
|
||||
bluetoothctl disconnect literal:AA:BB:CC:DD:EE:FF
|
||||
```
|
||||
2. Wait 2 seconds:
|
||||
```bash
|
||||
sleep 2
|
||||
```
|
||||
3. Restart the GUI:
|
||||
```bash
|
||||
python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF
|
||||
```
|
||||
|
||||
##### Bluetooth permissions
|
||||
|
||||
```bash
|
||||
sudo usermod -a -G bluetooth $USER
|
||||
# Log out and back in
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
- Make sure Bluetooth is enabled in System Settings
|
||||
- Grant your terminal app Bluetooth access when prompted
|
||||
- Use the UUID address from BleakScanner, not a MAC address
|
||||
|
||||
### Windows
|
||||
|
||||
- Make sure Bluetooth is enabled in Settings → Bluetooth & devices
|
||||
- Run the terminal as a regular user (not as Administrator — WinRT BLE can behave unexpectedly with elevated privileges)
|
||||
|
||||
### All platforms
|
||||
|
||||
#### Device not found
|
||||
|
||||
Make sure the MeshCore device is powered on and in BLE Companion mode. Run the BleakScanner script from the Usage section to verify it is visible.
|
||||
|
||||
#### Messages not arriving
|
||||
|
||||
- Check if your channels are correctly configured
|
||||
- Use `meshcli` to verify that messages are arriving
|
||||
|
||||
## Development
|
||||
|
||||
### Debug mode
|
||||
|
||||
Set `DEBUG = True` in the script for verbose logging:
|
||||
|
||||
```python
|
||||
DEBUG = True
|
||||
```
|
||||
|
||||
### Project structure
|
||||
|
||||
```
|
||||
meshcore-gui/
|
||||
├── meshcore_gui.py # Main application
|
||||
├── README.md # This file
|
||||
└── docs/
|
||||
├── TROUBLESHOOTING.md # BLE troubleshooting guide (Linux)
|
||||
└── MeshCore_GUI_Design.docx # Design document
|
||||
```
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is an **independent community project** and is not affiliated with or endorsed by the official [MeshCore](https://github.com/meshcore-dev) development team. It is built on top of the open-source `meshcore` Python library and `bleak` BLE library.
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file
|
||||
|
||||
## Author
|
||||
|
||||
**PE1HVH** - [GitHub](https://github.com/pe1hvh)
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- [MeshCore](https://github.com/meshcore-dev) - Mesh networking firmware and protocol
|
||||
- [meshcore_py](https://github.com/meshcore-dev/meshcore_py) - Python bindings for MeshCore
|
||||
- [meshcore-cli](https://github.com/meshcore-dev/meshcore-cli) - Command line interface
|
||||
- [NiceGUI](https://nicegui.io/) - Python GUI framework
|
||||
- [Bleak](https://github.com/hbldh/bleak) - Cross-platform Bluetooth Low Energy library
|
||||
BIN
docs/MeshCore_GUI_Design.docx
Normal file
BIN
docs/MeshCore_GUI_Design.docx
Normal file
Binary file not shown.
182
docs/TROUBLESHOOTING.md
Normal file
182
docs/TROUBLESHOOTING.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# MeshCore GUI - BLE Troubleshooting Guide
|
||||
|
||||
## The Problem
|
||||
|
||||
BLE connection to MeshCore device fails with `EOFError` during `start_notify` on the UART TX characteristic. The error originates in `dbus_fast` (the D-Bus library used by `bleak`) and looks like this:
|
||||
|
||||
```
|
||||
File "src/dbus_fast/_private/unmarshaller.py", line 395, in dbus_fast._private.unmarshaller.Unmarshaller._read_sock_with_fds
|
||||
EOFError
|
||||
```
|
||||
|
||||
Basic BLE connect works fine, but subscribing to notifications (`start_notify`) crashes.
|
||||
|
||||
## Diagnostic Steps
|
||||
|
||||
### 1. Check adapter status
|
||||
|
||||
```bash
|
||||
hciconfig -a
|
||||
```
|
||||
|
||||
Expected: `UP RUNNING`. If it shows `DOWN`, reset with:
|
||||
|
||||
```bash
|
||||
sudo hciconfig hci0 down
|
||||
sudo hciconfig hci0 up
|
||||
```
|
||||
|
||||
### 2. Check if adapter is detected
|
||||
|
||||
```bash
|
||||
lsusb | grep -i blue
|
||||
```
|
||||
|
||||
### 3. Test basic BLE connection (without notify)
|
||||
|
||||
```bash
|
||||
python -c "
|
||||
import asyncio
|
||||
from bleak import BleakClient
|
||||
async def test():
|
||||
async with BleakClient('literal:AA:BB:CC:DD:EE:FF') as c:
|
||||
print('Connected:', c.is_connected)
|
||||
asyncio.run(test())
|
||||
"
|
||||
```
|
||||
|
||||
If this works but meshcli/meshcore_gui fails, the problem is specifically `start_notify`.
|
||||
|
||||
### 4. Test start_notify in isolation
|
||||
|
||||
```bash
|
||||
python -c "
|
||||
import asyncio
|
||||
from bleak import BleakClient
|
||||
UART_TX = '6e400003-b5a3-f393-e0a9-e50e24dcca9e'
|
||||
async def test():
|
||||
async with BleakClient('literal:AA:BB:CC:DD:EE:FF') as c:
|
||||
def cb(s, d): print(f'RX: {d.hex()}')
|
||||
await c.start_notify(UART_TX, cb)
|
||||
print('Notify OK!')
|
||||
await asyncio.sleep(2)
|
||||
asyncio.run(test())
|
||||
"
|
||||
```
|
||||
|
||||
If this also fails with `EOFError`, the issue is confirmed at the BlueZ/D-Bus level.
|
||||
|
||||
### 5. Test notifications via bluetoothctl (outside Python)
|
||||
|
||||
```bash
|
||||
bluetoothctl
|
||||
scan on
|
||||
# Wait for device to appear
|
||||
connect literal:AA:BB:CC:DD:EE:FF
|
||||
# Wait for "Connection successful"
|
||||
menu gatt
|
||||
select-attribute 6e400003-b5a3-f393-e0a9-e50e24dcca9e
|
||||
notify on
|
||||
```
|
||||
|
||||
If `connect` fails with `le-connection-abort-by-local`, the problem is at the BlueZ or device level. No Python fix will help.
|
||||
|
||||
## The Solution
|
||||
|
||||
In our case, the root cause was a stale BLE pairing state between the Linux adapter and the T1000-e device. The fix requires a clean reconnect sequence:
|
||||
|
||||
### Step 1 - Remove the device from BlueZ
|
||||
|
||||
```bash
|
||||
bluetoothctl
|
||||
remove literal:AA:BB:CC:DD:EE:FF
|
||||
exit
|
||||
```
|
||||
|
||||
### Step 2 - Hard power cycle the MeshCore device
|
||||
|
||||
Physically power off the T1000-e (not just a software reset). Wait 10 seconds, then power it back on.
|
||||
|
||||
### Step 3 - Scan and reconnect from scratch
|
||||
|
||||
```bash
|
||||
bluetoothctl
|
||||
scan on
|
||||
```
|
||||
|
||||
Wait until the device appears: `[NEW] Device literal:AA:BB:CC:DD:EE:FF MeshCore-PE1HVH T1000e`
|
||||
|
||||
Then immediately connect:
|
||||
|
||||
```
|
||||
connect literal:AA:BB:CC:DD:EE:FF
|
||||
```
|
||||
|
||||
### Step 4 - Verify notifications work
|
||||
|
||||
```
|
||||
menu gatt
|
||||
select-attribute 6e400003-b5a3-f393-e0a9-e50e24dcca9e
|
||||
notify on
|
||||
```
|
||||
|
||||
If this succeeds, disconnect cleanly:
|
||||
|
||||
```
|
||||
notify off
|
||||
back
|
||||
disconnect literal:AA:BB:CC:DD:EE:FF
|
||||
exit
|
||||
```
|
||||
|
||||
### Step 5 - Verify channels with meshcli
|
||||
|
||||
```bash
|
||||
meshcli -d literal:AA:BB:CC:DD:EE:FF
|
||||
> get_channels
|
||||
```
|
||||
|
||||
Confirm output matches `CHANNELS_CONFIG` in `meshcore_gui.py`, then:
|
||||
|
||||
```
|
||||
> exit
|
||||
```
|
||||
|
||||
### Step 6 - Start the GUI
|
||||
|
||||
```bash
|
||||
cd ~/Documents/Share/Web/meshcore-linux
|
||||
source venv/bin/activate
|
||||
python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF
|
||||
```
|
||||
|
||||
## Things That Did NOT Help
|
||||
|
||||
| Action | Result |
|
||||
|---|---|
|
||||
| `sudo systemctl restart bluetooth` | No effect |
|
||||
| `sudo hciconfig hci0 down/up` | No effect |
|
||||
| `sudo rmmod btusb && sudo modprobe btusb` | No effect |
|
||||
| `sudo usbreset "8087:0026"` | No effect |
|
||||
| `sudo reboot` | No effect |
|
||||
| Clearing BlueZ cache (`/var/lib/bluetooth/*/cache`) | No effect |
|
||||
| Recreating Python venv | No effect |
|
||||
| Downgrading `dbus_fast` / `bleak` | No effect |
|
||||
| Downgrading `linux-firmware` | No effect |
|
||||
|
||||
## Key Takeaway
|
||||
|
||||
When `start_notify` fails with `EOFError` but basic BLE connect works, the issue is almost always a stale BLE state between the host adapter and the peripheral device. The fix is:
|
||||
|
||||
1. **Remove** the device from bluetoothctl
|
||||
2. **Hard power cycle** the peripheral device
|
||||
3. **Re-scan** and reconnect from scratch
|
||||
|
||||
## Recommended Startup Sequence
|
||||
|
||||
For the most reliable BLE connection, always follow this order:
|
||||
|
||||
1. Ensure no other application holds the BLE connection (BT manager, bluetoothctl, meshcli)
|
||||
2. Verify the device is visible: `bluetoothctl scan on`
|
||||
3. Check channels: `meshcli -d <BLE_ADDRESS>` → `get_channels` → `exit`
|
||||
4. Start the GUI: `python meshcore_gui.py <BLE_ADDRESS>`
|
||||
737
docs/ble_capture_workflow_t_1000_e_uitleg.md
Normal file
737
docs/ble_capture_workflow_t_1000_e_uitleg.md
Normal file
@@ -0,0 +1,737 @@
|
||||
# BLE Capture Workflow T1000-e — Uitleg & Achtergrond
|
||||
|
||||
> **Bron:** `ble_capture_workflow_t_1000_e.md`
|
||||
>
|
||||
> Dit document is een **verdiepingsdocument** bij het originele technische werkdocument. Het biedt:
|
||||
> - Didactische uitleg van BLE-concepten en terminologie
|
||||
> - Achtergrondkennis over GATT-services en hun werking
|
||||
> - Context om toekomstige BLE-projecten beter te begrijpen
|
||||
>
|
||||
> **Doelgroep:** Mezelf, als referentie voor de lange termijn.
|
||||
|
||||
---
|
||||
|
||||
## 1. Waar gaat dit document over?
|
||||
|
||||
Het originele document beschrijft hoe je op een Linux-computer kunt "meeluisteren" naar de BLE-communicatie van een **MeshCore T1000-e** radio. Het legt uit:
|
||||
|
||||
- Welke stappen nodig zijn om een verbinding op te zetten
|
||||
- Waarom het vaak misgaat (en hoe je dat voorkomt)
|
||||
- Hoe je ruwe protocol-data kunt opslaan voor analyse
|
||||
|
||||
**De kernboodschap in één zin:**
|
||||
|
||||
> Er mag maar **één luisteraar tegelijk** verbonden zijn met de T1000-e. Als iets anders al verbonden is, faalt jouw capture.
|
||||
|
||||
---
|
||||
|
||||
## 2. Begrippen en afkortingen uitgelegd
|
||||
|
||||
### 2.1 BLE — Bluetooth Low Energy
|
||||
|
||||
BLE is een **zuinige variant van Bluetooth**, ontworpen voor apparaten die maanden of jaren op een batterij moeten werken.
|
||||
|
||||
| Eigenschap | Klassiek Bluetooth | BLE |
|
||||
|------------|-------------------|-----|
|
||||
| Stroomverbruik | Hoog | Zeer laag |
|
||||
| Datasnelheid | Hoog | Laag |
|
||||
| Typisch gebruik | Audio, bestanden | Sensoren, IoT, MeshCore |
|
||||
|
||||
**Analogie:** Klassiek Bluetooth is als een telefoongesprek (constant verbonden, veel energie). BLE is als SMS'jes sturen (kort contact wanneer nodig, weinig energie).
|
||||
|
||||
---
|
||||
|
||||
### 2.2 GATT — Generic Attribute Profile
|
||||
|
||||
GATT is de **structuur** waarmee BLE-apparaten hun data aanbieden. Zie het als een **digitaal prikbord** met een vaste indeling:
|
||||
|
||||
```
|
||||
Service (categorie)
|
||||
└── Characteristic (specifiek datapunt)
|
||||
└── Descriptor (extra configuratie)
|
||||
```
|
||||
|
||||
**Voorbeeld voor MeshCore:**
|
||||
|
||||
```
|
||||
Nordic UART Service (NUS)
|
||||
├── RX Characteristic → berichten van radio naar computer
|
||||
└── TX Characteristic → berichten van computer naar radio
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.3 NUS — Nordic UART Service
|
||||
|
||||
NUS is een **standaard BLE-service** ontwikkeld door Nordic Semiconductor. Het simuleert een ouderwetse seriële poort (UART) over Bluetooth.
|
||||
|
||||
- **RX** (Receive): Data die je **ontvangt** van het apparaat
|
||||
- **TX** (Transmit): Data die je **verstuurt** naar het apparaat
|
||||
|
||||
Let op: RX/TX zijn vanuit het perspectief van de computer, niet van de radio.
|
||||
|
||||
#### Is NUS een protocol?
|
||||
|
||||
**Nee.** NUS is een **servicespecificatie**, geen protocol. Dit is een belangrijk onderscheid:
|
||||
|
||||
| Niveau | Wat is het | Voorbeeld |
|
||||
|--------|-----------|-----------|
|
||||
| **Protocol** | Regels voor communicatie | BLE, ATT, GATT |
|
||||
| **Service** | Verzameling van gerelateerde characteristics | NUS, Heart Rate Service |
|
||||
| **Characteristic** | Specifiek datapunt binnen een service | RX, TX |
|
||||
|
||||
**Analogie met een restaurant:**
|
||||
|
||||
| Concept | Restaurant-analogie |
|
||||
|---------|---------------------|
|
||||
| **Protocol (GATT)** | De regels: je bestelt bij de ober, eten komt uit de keuken |
|
||||
| **Service (NUS)** | Een specifieke menukaart (bijv. "ontbijtmenu") |
|
||||
| **Characteristics** | De individuele gerechten op dat menu |
|
||||
|
||||
Mensen zeggen vaak "we gebruiken het NUS-protocol", maar strikt genomen is **GATT** het protocol en is **NUS** een service die via GATT wordt aangeboden.
|
||||
|
||||
---
|
||||
|
||||
### 2.4 Andere GATT-services (officieel en custom)
|
||||
|
||||
NUS is slechts één van vele BLE-services. De **Bluetooth SIG** (de organisatie achter Bluetooth) definieert tientallen officiële services. Daarnaast kunnen fabrikanten eigen (custom) services maken.
|
||||
|
||||
#### Officiële services (Bluetooth SIG)
|
||||
|
||||
Deze services hebben een **16-bit UUID** en zijn gestandaardiseerd voor interoperabiliteit:
|
||||
|
||||
| Service | UUID | Toepassing |
|
||||
|---------|------|------------|
|
||||
| **Heart Rate Service** | 0x180D | Hartslagmeters, fitnessapparaten |
|
||||
| **Battery Service** | 0x180F | Batterijniveau rapporteren |
|
||||
| **Device Information** | 0x180A | Fabrikant, modelnummer, firmwareversie |
|
||||
| **Blood Pressure** | 0x1810 | Bloeddrukmeters |
|
||||
| **Health Thermometer** | 0x1809 | Medische thermometers |
|
||||
| **Cycling Speed and Cadence** | 0x1816 | Fietssensoren |
|
||||
| **Environmental Sensing** | 0x181A | Temperatuur, luchtvochtigheid, druk |
|
||||
| **Glucose** | 0x1808 | Bloedglucosemeters |
|
||||
| **HID over GATT** | 0x1812 | Toetsenborden, muizen, gamepads |
|
||||
| **Proximity** | 0x1802 | "Find My"-functionaliteit |
|
||||
| **Generic Access** | 0x1800 | **Verplicht** — apparaatnaam en uiterlijk |
|
||||
|
||||
#### Custom/vendor-specific services
|
||||
|
||||
Fabrikanten kunnen eigen services definiëren met een **128-bit UUID**. Voorbeelden:
|
||||
|
||||
| Service | Fabrikant | Toepassing |
|
||||
|---------|-----------|------------|
|
||||
| **Nordic UART Service (NUS)** | Nordic Semiconductor | Seriële poort over BLE |
|
||||
| **Apple Notification Center** | Apple | iPhone notificaties naar wearables |
|
||||
| **Xiaomi Mi Band Service** | Xiaomi | Fitnesstracker communicatie |
|
||||
| **MeshCore Companion** | MeshCore | Radio-communicatie (gebruikt NUS) |
|
||||
|
||||
#### Het verschil: 16-bit vs. 128-bit UUID
|
||||
|
||||
| Type | Lengte | Voorbeeld | Wie mag het maken? |
|
||||
|------|--------|-----------|-------------------|
|
||||
| **Officieel (SIG)** | 16-bit | `0x180D` | Alleen Bluetooth SIG |
|
||||
| **Custom** | 128-bit | `6e400001-b5a3-f393-e0a9-e50e24dcca9e` | Iedereen |
|
||||
|
||||
De NUS-service gebruikt bijvoorbeeld deze 128-bit UUID:
|
||||
```
|
||||
6e400001-b5a3-f393-e0a9-e50e24dcca9e
|
||||
```
|
||||
|
||||
#### Waarom dit relevant is
|
||||
|
||||
In het MeshCore-project gebruiken we **NUS** (een custom service) voor de communicatie. Maar als je met andere BLE-apparaten werkt — zoals een hartslagmeter of een slimme thermostaat — dan gebruiken die vaak **officiële SIG-services**.
|
||||
|
||||
Het principe blijft hetzelfde:
|
||||
1. Ontdek welke services het apparaat aanbiedt
|
||||
2. Zoek de juiste characteristic
|
||||
3. Lees, schrijf, of abonneer op notify
|
||||
|
||||
---
|
||||
|
||||
### 2.5 Notify vs. Read
|
||||
|
||||
Er zijn twee manieren om data van een BLE-apparaat te krijgen:
|
||||
|
||||
| Methode | Werking | Wanneer gebruiken |
|
||||
|---------|---------|-------------------|
|
||||
| **Read** | Jij vraagt actief om data | Eenmalige waarden (bijv. batterijstatus) |
|
||||
| **Notify** | Apparaat stuurt automatisch bij nieuwe data | Continue datastroom (bijv. berichten) |
|
||||
|
||||
**Analogie:**
|
||||
- **Read** = Je belt iemand en vraagt "hoe gaat het?"
|
||||
- **Notify** = Je krijgt automatisch een WhatsApp-bericht als er nieuws is
|
||||
|
||||
Voor MeshCore-captures gebruik je **Notify** — je wilt immers weten wanneer er een bericht binnenkomt.
|
||||
|
||||
---
|
||||
|
||||
### 2.6 CCCD — Client Characteristic Configuration Descriptor
|
||||
|
||||
De CCCD is de **aan/uit-schakelaar voor Notify**. Technisch gezien:
|
||||
|
||||
1. Jouw computer schrijft een `1` naar de CCCD
|
||||
2. Het apparaat weet nu: "deze client wil notificaties"
|
||||
3. Bij nieuwe data stuurt het apparaat automatisch een bericht
|
||||
|
||||
**Het cruciale punt:** Slechts **één client tegelijk** kan de CCCD activeren. Een tweede client krijgt de foutmelding:
|
||||
|
||||
```
|
||||
Notify acquired
|
||||
```
|
||||
|
||||
Dit betekent: "iemand anders heeft notify al ingeschakeld."
|
||||
|
||||
---
|
||||
|
||||
### 2.7 Pairing, Bonding en Trust
|
||||
|
||||
Dit zijn drie afzonderlijke stappen in het BLE-beveiligingsproces:
|
||||
|
||||
| Stap | Wat gebeurt er | Analogie |
|
||||
|------|----------------|----------|
|
||||
| **Pairing** | Apparaten wisselen cryptografische sleutels uit | Je maakt kennis en wisselt telefoonnummers |
|
||||
| **Bonding** | De sleutels worden permanent opgeslagen | Je slaat het nummer op in je contacten |
|
||||
| **Trust** | Het systeem vertrouwt het apparaat automatisch | Je zet iemand in je favorieten |
|
||||
|
||||
Na deze drie stappen hoef je niet elke keer opnieuw de pincode in te voeren.
|
||||
|
||||
**Controle in Linux:**
|
||||
|
||||
```bash
|
||||
bluetoothctl info literal:AA:BB:CC:DD:EE:FF | egrep -i "Paired|Bonded|Trusted"
|
||||
```
|
||||
|
||||
Verwachte output:
|
||||
|
||||
```
|
||||
Paired: yes
|
||||
Bonded: yes
|
||||
Trusted: yes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.8 Ownership — Het kernprobleem
|
||||
|
||||
**Ownership** is een informele term die aangeeft: "welke client heeft op dit moment de actieve GATT-sessie met notify?"
|
||||
|
||||
**Analogie:** Denk aan een walkietalkie waarbij maar één persoon tegelijk kan luisteren:
|
||||
|
||||
- Als GNOME Bluetooth Manager al verbonden is → die is de "eigenaar"
|
||||
- Als jouw Python-script daarna probeert te verbinden → krijgt het geen toegang
|
||||
|
||||
**Typische "eigenaren" die problemen veroorzaken:**
|
||||
|
||||
- GNOME Bluetooth GUI (draait vaak op de achtergrond)
|
||||
- `bluetoothctl connect` (maakt bluetoothctl de eigenaar)
|
||||
- Telefoon met Bluetooth aan
|
||||
- Andere BLE-apps
|
||||
|
||||
---
|
||||
|
||||
### 2.9 BlueZ
|
||||
|
||||
**BlueZ** is de officiële Bluetooth-stack voor Linux. Het is de software die alle Bluetooth-communicatie afhandelt tussen je applicaties en de hardware.
|
||||
|
||||
---
|
||||
|
||||
### 2.10 Bleak
|
||||
|
||||
**Bleak** is een Python-bibliotheek voor BLE-communicatie. Het bouwt voort op BlueZ (Linux), Core Bluetooth (macOS) of WinRT (Windows).
|
||||
|
||||
---
|
||||
|
||||
## 3. BLE versus Classic Bluetooth
|
||||
|
||||
Een veelvoorkomende vraag: zijn BLE en "gewone" Bluetooth hetzelfde? Het antwoord is **nee** — het zijn verschillende technologieën die wel dezelfde naam en frequentieband delen.
|
||||
|
||||
### 3.1 Twee smaken van Bluetooth
|
||||
|
||||
Sinds Bluetooth 4.0 (2010) zijn er **twee afzonderlijke radiosystemen** binnen de Bluetooth-standaard:
|
||||
|
||||
| Naam | Technische term | Kenmerken |
|
||||
|------|-----------------|-----------|
|
||||
| **Classic Bluetooth** | BR/EDR (Basic Rate / Enhanced Data Rate) | Hoge datasnelheid, continue verbinding, meer stroom |
|
||||
| **Bluetooth Low Energy** | BLE (ook: Bluetooth Smart) | Lage datasnelheid, korte bursts, zeer zuinig |
|
||||
|
||||
**Cruciaal:** Dit zijn **verschillende radioprotocollen** die niet rechtstreeks met elkaar kunnen communiceren.
|
||||
|
||||
### 3.2 Protocol én hardware
|
||||
|
||||
Bluetooth (zowel Classic als BLE) omvat **meerdere lagen** — het is niet alleen een protocol, maar ook hardware:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ SOFTWARE │
|
||||
│ ┌───────────────────────────────────┐ │
|
||||
│ │ Applicatie (jouw code) │ │
|
||||
│ ├───────────────────────────────────┤ │
|
||||
│ │ Profielen / GATT Services │ │
|
||||
│ ├───────────────────────────────────┤ │
|
||||
│ │ Protocollen (ATT, L2CAP, etc.) │ │
|
||||
│ ├───────────────────────────────────┤ │
|
||||
│ │ Host Controller Interface (HCI) │ │ ← Grens software/firmware
|
||||
│ └───────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────┤
|
||||
│ FIRMWARE │
|
||||
│ ┌───────────────────────────────────┐ │
|
||||
│ │ Link Layer / Controller │ │
|
||||
│ └───────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────┤
|
||||
│ HARDWARE │
|
||||
│ ┌───────────────────────────────────┐ │
|
||||
│ │ Radio (2.4 GHz transceiver) │ │
|
||||
│ ├───────────────────────────────────┤ │
|
||||
│ │ Antenne │ │
|
||||
│ └───────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.3 Waar zit het verschil?
|
||||
|
||||
Het verschil zit op **meerdere lagen**, niet alleen protocol:
|
||||
|
||||
| Laag | Classic (BR/EDR) | BLE | Verschil in hardware? |
|
||||
|------|------------------|-----|----------------------|
|
||||
| **Radio** | GFSK, π/4-DQPSK, 8DPSK | GFSK | **Ja** — andere modulatie |
|
||||
| **Kanalen** | 79 kanalen, 1 MHz breed | 40 kanalen, 2 MHz breed | **Ja** — andere indeling |
|
||||
| **Link Layer** | LMP (Link Manager Protocol) | LL (Link Layer) | **Ja** — andere state machine |
|
||||
| **Protocollen** | L2CAP, RFCOMM, SDP | L2CAP, ATT, GATT | Nee — software |
|
||||
|
||||
### 3.4 Dual-mode apparaten
|
||||
|
||||
De overlap zit in apparaten die **beide** ondersteunen:
|
||||
|
||||
| Apparaattype | Ondersteunt | Voorbeeld |
|
||||
|--------------|-------------|-----------|
|
||||
| **Classic-only** | Alleen BR/EDR | Oude headsets, auto-audio |
|
||||
| **BLE-only** (Bluetooth Smart) | Alleen BLE | Fitnesstrackers, sensoren, T1000-e |
|
||||
| **Dual-Mode** (Bluetooth Smart Ready) | Beide | Smartphones, laptops, ESP32 |
|
||||
|
||||
**Jouw smartphone** is dual-mode: hij kan praten met je klassieke Bluetooth-koptelefoon (BR/EDR) én met je MeshCore T1000-e (BLE).
|
||||
|
||||
### 3.5 Praktijkvoorbeelden
|
||||
|
||||
| Scenario | Wat wordt gebruikt |
|
||||
|----------|-------------------|
|
||||
| Muziek naar je koptelefoon | **Classic** (A2DP profiel) |
|
||||
| Hartslag van je smartwatch | **BLE** (Heart Rate Service) |
|
||||
| Bestand naar laptop sturen | **Classic** (OBEX/FTP profiel) |
|
||||
| MeshCore T1000-e uitlezen | **BLE** (NUS service) |
|
||||
| Handsfree bellen in auto | **Classic** (HFP profiel) |
|
||||
| Slimme lamp bedienen | **BLE** (eigen GATT service) |
|
||||
|
||||
---
|
||||
|
||||
## 4. BLE kanaalindeling en frequency hopping
|
||||
|
||||
### 4.1 De 40 BLE-kanalen
|
||||
|
||||
De 2.4 GHz ISM-band loopt van **2400 MHz tot 2483.5 MHz** (83.5 MHz breed).
|
||||
|
||||
BLE verdeelt dit in **40 kanalen van elk 2 MHz**:
|
||||
|
||||
```
|
||||
2400 MHz 2480 MHz
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
|
||||
│00│01│02│03│04│05│06│07│08│09│10│11│12│13│14│15│16│17│18│19│...→ 39
|
||||
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
|
||||
└──────────────────────────────────────────────────────┘
|
||||
2 MHz per kanaal
|
||||
```
|
||||
|
||||
**Totaal:** 40 × 2 MHz = **80 MHz** gebruikt
|
||||
|
||||
### 4.2 Advertising vs. data kanalen
|
||||
|
||||
De 40 kanalen zijn niet allemaal gelijk:
|
||||
|
||||
| Type | Kanalen | Functie |
|
||||
|------|---------|---------|
|
||||
| **Advertising** | 3 (nrs. 37, 38, 39) | Apparaten vinden, verbinding starten |
|
||||
| **Data** | 37 (nrs. 0-36) | Daadwerkelijke communicatie na verbinding |
|
||||
|
||||
De advertising-kanalen zijn strategisch gekozen om **Wi-Fi-interferentie** te vermijden:
|
||||
|
||||
```
|
||||
Wi-Fi kanaal 1 Wi-Fi kanaal 6 Wi-Fi kanaal 11
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
────████████─────────────█████████────────────████████────
|
||||
|
||||
BLE: ▲ ▲ ▲
|
||||
Ch.37 Ch.38 Ch.39
|
||||
|
||||
(advertising kanalen zitten tússen de Wi-Fi kanalen)
|
||||
```
|
||||
|
||||
### 4.3 Vergelijking met Classic Bluetooth
|
||||
|
||||
| Aspect | Classic (BR/EDR) | BLE |
|
||||
|--------|------------------|-----|
|
||||
| **Aantal kanalen** | 79 | 40 |
|
||||
| **Kanaalbreedte** | 1 MHz | 2 MHz |
|
||||
| **Totale bandbreedte** | 79 MHz | 80 MHz |
|
||||
| **Frequency hopping** | Ja, alle 79 | Ja, 37 datakanalen |
|
||||
|
||||
Classic heeft **meer maar smallere** kanalen, BLE heeft **minder maar bredere** kanalen.
|
||||
|
||||
### 4.4 Frequency hopping: één kanaal tegelijk
|
||||
|
||||
**Belangrijk inzicht:** Je gebruikt altijd maar **één kanaal tegelijk**. De 40 kanalen zijn er voor **frequency hopping** — het afwisselend wisselen van kanaal om interferentie te vermijden:
|
||||
|
||||
```
|
||||
Tijd →
|
||||
┌───┐ ┌───┐ ┌───┐ ┌───┐
|
||||
Ch. 12 │ ▓ │ │ │ │ │ │ ▓ │
|
||||
└───┘ └───┘ └───┘ └───┘
|
||||
┌───┐ ┌───┐ ┌───┐ ┌───┐
|
||||
Ch. 07 │ │ │ ▓ │ │ │ │ │
|
||||
└───┘ └───┘ └───┘ └───┘
|
||||
┌───┐ ┌───┐ ┌───┐ ┌───┐
|
||||
Ch. 31 │ │ │ │ │ ▓ │ │ │
|
||||
└───┘ └───┘ └───┘ └───┘
|
||||
↑ ↑ ↑ ↑
|
||||
Pakket 1 Pakket 2 Pakket 3 Pakket 4
|
||||
```
|
||||
|
||||
Dit is **geen parallelle communicatie** — het is serieel met wisselende frequentie.
|
||||
|
||||
---
|
||||
|
||||
## 5. Twee betekenissen van "serieel"
|
||||
|
||||
Wanneer we zeggen "NUS is serieel", kan dit verwarring veroorzaken. Het woord "serieel" heeft namelijk **twee verschillende betekenissen** in deze context.
|
||||
|
||||
### 5.1 Radio-niveau: altijd serieel
|
||||
|
||||
**Alle** draadloze communicatie is serieel op fysiek niveau — je hebt maar **één radiokanaal tegelijk** en bits gaan **na elkaar** de lucht in:
|
||||
|
||||
```
|
||||
Radiogolf: ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁▂▃▄▅▆▇█▇▆▅▄▃▂▁
|
||||
|
||||
Bits: 0 1 1 0 1 0 0 1 1 1 0 1 0 0 1 0 → één voor één
|
||||
```
|
||||
|
||||
De 40 kanalen zijn voor **frequency hopping**, niet voor parallel versturen. Dit geldt voor **alle** BLE-services — NUS, Heart Rate, Battery, allemaal.
|
||||
|
||||
### 5.2 Data-niveau: NUS simuleert een seriële poort
|
||||
|
||||
Wanneer we zeggen "NUS is een seriële service", bedoelen we iets anders:
|
||||
|
||||
**NUS simuleert een oude seriële poort (RS-232/UART):**
|
||||
|
||||
```
|
||||
Historisch (jaren '80-'00):
|
||||
|
||||
Computer Apparaat
|
||||
┌──────┐ Seriële kabel ┌──────┐
|
||||
│ COM1 │←────────────────→│ UART │
|
||||
└──────┘ (RS-232) └──────┘
|
||||
|
||||
Bytes: 0x48 0x65 0x6C 0x6C 0x6F ("Hello")
|
||||
└─────────────────────┘
|
||||
Geen structuur, gewoon een stroom bytes
|
||||
```
|
||||
|
||||
**NUS bootst dit na over BLE:**
|
||||
|
||||
```
|
||||
Vandaag:
|
||||
|
||||
Computer Apparaat
|
||||
┌──────┐ BLE (NUS) ┌──────┐
|
||||
│ App │←~~~~~~~~~~~~~~~~~~~~→│ MCU │
|
||||
└──────┘ (draadloos) └──────┘
|
||||
|
||||
Gedraagt zich alsof er een seriële kabel zit
|
||||
```
|
||||
|
||||
### 5.3 Vergelijking: serieel vs. gestructureerd
|
||||
|
||||
| Aspect | NUS (serieel) | Heart Rate (gestructureerd) |
|
||||
|--------|---------------|----------------------------|
|
||||
| **Radio** | Serieel, frequency hopping | Serieel, frequency hopping |
|
||||
| **Data** | Ongestructureerde bytestroom | Vaste velden met betekenis |
|
||||
| **Wie bepaalt formaat?** | Jij (eigen protocol) | Bluetooth SIG (specificatie) |
|
||||
|
||||
### 5.4 Analogie: snelweg met rijstroken
|
||||
|
||||
Denk aan een **snelweg met 40 rijstroken** (de kanalen):
|
||||
|
||||
- Je mag maar **één rijstrook tegelijk** gebruiken
|
||||
- Je wisselt regelmatig van rijstrook (frequency hopping, om botsingen te vermijden)
|
||||
- De **vracht** die je vervoert kan verschillen:
|
||||
|
||||
| Service | Vracht-analogie |
|
||||
|---------|-----------------|
|
||||
| **NUS** | Losse spullen door elkaar (flexibel, maar jij moet uitzoeken wat wat is) |
|
||||
| **Heart Rate** | Gestandaardiseerde pallets (iedereen weet wat waar zit) |
|
||||
|
||||
De **snelweg werkt hetzelfde** — het verschil zit in hoe je de vracht organiseert.
|
||||
|
||||
---
|
||||
|
||||
## 6. Seriële vs. gestructureerde services (verdieping)
|
||||
|
||||
Een belangrijk onderscheid dat vaak over het hoofd wordt gezien: **niet alle BLE-services werken hetzelfde**. Er zijn fundamenteel twee benaderingen.
|
||||
|
||||
### 6.1 Seriële services (stream-gebaseerd)
|
||||
|
||||
**NUS (Nordic UART Service)** is ontworpen om een **seriële poort te simuleren**:
|
||||
|
||||
- Continue datastroom van ruwe bytes
|
||||
- Geen opgelegde structuur
|
||||
- Jij bepaalt zelf het formaat en de betekenis
|
||||
|
||||
**Analogie:** Een seriële service is als een **telefoonlijn** — je kunt alles zeggen wat je wilt, in elke taal, zonder vaste regels.
|
||||
|
||||
```
|
||||
Voorbeeld NUS-data (MeshCore):
|
||||
0x01 0x0A 0x48 0x65 0x6C 0x6C 0x6F ...
|
||||
└── Betekenis bepaald door MeshCore protocol, niet door BLE
|
||||
```
|
||||
|
||||
### 6.2 Gestructureerde services (veld-gebaseerd)
|
||||
|
||||
De meeste officiële SIG-services werken **anders** — ze definiëren **exact** welke bytes wat betekenen:
|
||||
|
||||
**Analogie:** Een gestructureerde service is als een **belastingformulier** — elk vakje heeft een vaste betekenis en een voorgeschreven formaat.
|
||||
|
||||
#### Voorbeeld: Heart Rate Measurement
|
||||
|
||||
```
|
||||
Byte 0: Flags (bitfield)
|
||||
├── Bit 0: 0 = hartslag in 1 byte, 1 = hartslag in 2 bytes
|
||||
├── Bit 1-2: Sensor contact status
|
||||
├── Bit 3: Energy expended aanwezig?
|
||||
└── Bit 4: RR-interval aanwezig?
|
||||
|
||||
Byte 1(-2): Heart rate waarde
|
||||
Byte N...: Optionele extra velden (afhankelijk van flags)
|
||||
```
|
||||
|
||||
**Concreet voorbeeld:**
|
||||
|
||||
```
|
||||
Ontvangen bytes: 0x00 0x73
|
||||
|
||||
0x00 = Flags: 8-bit formaat, geen extra velden
|
||||
0x73 = 115 decimaal → hartslag is 115 bpm
|
||||
```
|
||||
|
||||
Je krijgt dus niet de tekst "115", maar een binair pakket dat je moet **parsen** volgens de specificatie.
|
||||
|
||||
#### Voorbeeld: Battery Level
|
||||
|
||||
Eenvoudiger — slechts **1 byte**:
|
||||
|
||||
```
|
||||
Ontvangen byte: 0x5A
|
||||
|
||||
0x5A = 90 decimaal → batterij is 90%
|
||||
```
|
||||
|
||||
#### Voorbeeld: Environmental Sensing (temperatuur)
|
||||
|
||||
```
|
||||
Ontvangen bytes: 0x9C 0x08
|
||||
|
||||
Little-endian 16-bit signed integer: 0x089C = 2204
|
||||
Resolutie: 0.01°C
|
||||
Temperatuur: 2204 × 0.01 = 22.04°C
|
||||
```
|
||||
|
||||
### 6.3 Vergelijkingstabel
|
||||
|
||||
| Aspect | Serieel (NUS) | Gestructureerd (SIG) |
|
||||
|--------|---------------|----------------------|
|
||||
| **Data-indeling** | Vrij, zelf bepalen | Vast, door specificatie |
|
||||
| **Wie definieert het formaat?** | Jij / de fabrikant | Bluetooth SIG |
|
||||
| **Waar vind je de specificatie?** | Eigen documentatie / broncode | bluetooth.com/specifications |
|
||||
| **Parsing** | Eigen parser bouwen | Standaard parser mogelijk |
|
||||
| **Interoperabiliteit** | Alleen eigen software | Elke conforme app/device |
|
||||
| **Flexibiliteit** | Maximaal | Beperkt tot spec |
|
||||
| **Complexiteit** | Eenvoudig te starten | Spec lezen vereist |
|
||||
|
||||
### 6.4 Voorbeelden van gestructureerde services
|
||||
|
||||
| Service | Characteristic | Data-formaat |
|
||||
|---------|----------------|--------------|
|
||||
| **Battery Service** | Battery Level | 1 byte: 0-100 (percentage) |
|
||||
| **Heart Rate** | Heart Rate Measurement | Flags + 8/16-bit HR + optionele velden |
|
||||
| **Health Thermometer** | Temperature Measurement | IEEE-11073 FLOAT (4 bytes) |
|
||||
| **Blood Pressure** | Blood Pressure Measurement | Compound: systolisch, diastolisch, MAP, pulse |
|
||||
| **Cycling Speed & Cadence** | CSC Measurement | 32-bit tellers + 16-bit tijd |
|
||||
| **Environmental Sensing** | Temperature | 16-bit signed, resolutie 0.01°C |
|
||||
| **Environmental Sensing** | Humidity | 16-bit unsigned, resolutie 0.01% |
|
||||
| **Environmental Sensing** | Pressure | 32-bit unsigned, resolutie 0.1 Pa |
|
||||
|
||||
### 6.5 Wanneer welke aanpak?
|
||||
|
||||
| Situatie | Aanbevolen aanpak |
|
||||
|----------|-------------------|
|
||||
| Eigen protocol (MeshCore, custom IoT) | **Serieel** (NUS of eigen service) |
|
||||
| Standaard use-case (hartslag, batterij) | **Gestructureerd** (SIG-service) |
|
||||
| Interoperabiliteit met bestaande apps vereist | **Gestructureerd** (SIG-service) |
|
||||
| Complexe, variabele datastructuren | **Serieel** met eigen protocol |
|
||||
| Snel prototype zonder spec-studie | **Serieel** (NUS) |
|
||||
|
||||
### 6.6 Waarom MeshCore NUS gebruikt
|
||||
|
||||
MeshCore koos voor NUS (serieel) omdat:
|
||||
|
||||
1. **Flexibiliteit** — Het Companion Protocol heeft eigen framing nodig
|
||||
2. **Geen passende SIG-service** — Er is geen "Mesh Radio Service" standaard
|
||||
3. **Bidirectionele communicatie** — NUS biedt RX én TX characteristics
|
||||
4. **Eenvoud** — Geen complexe SIG-specificatie implementeren
|
||||
|
||||
Het nadeel: je kunt niet zomaar een willekeurige BLE-app gebruiken om met MeshCore te praten — je hebt software nodig die het MeshCore Companion Protocol begrijpt.
|
||||
|
||||
---
|
||||
|
||||
## 7. Het OSI-model in context
|
||||
|
||||
Het document plaatst het probleem in een **lagenmodel**. Dit helpt begrijpen *waar* het probleem zit:
|
||||
|
||||
| Laag | Naam | In dit project | Probleem hier? |
|
||||
|------|------|----------------|----------------|
|
||||
| 7 | Applicatie | MeshCore Companion Protocol | Nee |
|
||||
| 6 | Presentatie | Frame-encoding (hex) | Nee |
|
||||
| **5** | **Sessie** | **GATT client ↔ server sessie** | **★ JA** |
|
||||
| 4 | Transport | ATT / GATT | Nee |
|
||||
| 2 | Data Link | BLE Link Layer | Nee |
|
||||
| 1 | Fysiek | 2.4 GHz radio | Nee |
|
||||
|
||||
**Conclusie:** Het ownership-probleem zit op **laag 5 (sessie)**. De firmware en het protocol zijn niet het probleem — het gaat om wie de sessie "bezit".
|
||||
|
||||
---
|
||||
|
||||
## 8. De workflow samengevat
|
||||
|
||||
### 8.1 Eenmalige voorbereiding
|
||||
|
||||
```bash
|
||||
# Start bluetoothctl
|
||||
bluetoothctl
|
||||
|
||||
# Activeer Bluetooth
|
||||
power on
|
||||
agent on
|
||||
default-agent
|
||||
scan on
|
||||
|
||||
# Wacht tot device zichtbaar is, dan pairen
|
||||
pair literal:AA:BB:CC:DD:EE:FF
|
||||
# Voer pincode in (bijv. 123456)
|
||||
|
||||
# Vertrouw het apparaat
|
||||
trust literal:AA:BB:CC:DD:EE:FF
|
||||
quit
|
||||
```
|
||||
|
||||
### 8.2 Vóór elke capture
|
||||
|
||||
1. **Telefoon Bluetooth UIT**
|
||||
2. **GNOME Bluetooth GUI SLUITEN**
|
||||
3. **Expliciet disconnecten:**
|
||||
|
||||
```bash
|
||||
bluetoothctl disconnect literal:AA:BB:CC:DD:EE:FF
|
||||
```
|
||||
|
||||
4. **Controleer dat niemand verbonden is:**
|
||||
|
||||
```bash
|
||||
bluetoothctl info literal:AA:BB:CC:DD:EE:FF | egrep -i "Connected"
|
||||
# Verwacht: Connected: no
|
||||
```
|
||||
|
||||
### 8.3 Capture starten
|
||||
|
||||
```bash
|
||||
python tools/ble_observe.py \
|
||||
--address literal:AA:BB:CC:DD:EE:FF \
|
||||
--pre-scan-seconds 10 \
|
||||
--connect-timeout 30 \
|
||||
--notify \
|
||||
--notify-seconds 30 \
|
||||
--notify-start-timeout 30 \
|
||||
--disconnect-timeout 15 \
|
||||
--capture captures/session_$(date -u +%Y-%m-%d_%H%M%S).raw
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Veelgemaakte fouten
|
||||
|
||||
| Fout | Gevolg | Oplossing |
|
||||
|------|--------|-----------|
|
||||
| GNOME Bluetooth Manager open | `Notify acquired` | GUI sluiten |
|
||||
| `bluetoothctl connect` gedaan | Tool faalt bij notify | Altijd `disconnect` eerst |
|
||||
| Telefoon Bluetooth aan | Telefoon claimt verbinding | Telefoon BT uit |
|
||||
| Meerdere scripts tegelijk | Eerste wint, rest faalt | Één tool tegelijk |
|
||||
|
||||
---
|
||||
|
||||
## 10. Visueel overzicht (sequentiediagram)
|
||||
|
||||
```
|
||||
┌──────┐ ┌───────┐ ┌───────┐ ┌───────┐
|
||||
│ User │ │ Linux │ │ BlueZ │ │ Radio │
|
||||
└──┬───┘ └───┬───┘ └───┬───┘ └───┬───┘
|
||||
│ │ │ │
|
||||
│ pair/trust │ │ │
|
||||
│────────────>│────────────────────────-->│ (eenmalig)
|
||||
│ │ │ │
|
||||
│ │ Geen actieve verbinding│
|
||||
│ │ │ │
|
||||
│ start tool │ │ │
|
||||
│────────────>│ │ │
|
||||
│ │ connect() │ │
|
||||
│ │────────────>│────────────>│
|
||||
│ │ │ │
|
||||
│ │start_notify │ │
|
||||
│ │────────────>│────────────>│
|
||||
│ │ │ │
|
||||
│ │ notify (data frames) │
|
||||
│ │<────────────│<────────────│
|
||||
│ │ │ │
|
||||
│ │ stop_notify │ │
|
||||
│ │────────────>│────────────>│
|
||||
│ │ │ │
|
||||
│ │ disconnect │ │
|
||||
│ │────────────>│────────────>│
|
||||
│ │ │ │
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Conclusie
|
||||
|
||||
Het document bewijst dat:
|
||||
|
||||
- ✅ MeshCore BLE companion **werkt correct** op Linux
|
||||
- ✅ De firmware **blokkeert notify niet**
|
||||
- ✅ Het enige vereiste is: **exact één actieve BLE client per radio**
|
||||
|
||||
Wanneer je deze workflow volgt, zijn captures reproduceerbaar en is verdere protocol-analyse mogelijk.
|
||||
|
||||
---
|
||||
|
||||
## 12. Referenties
|
||||
|
||||
- MeshCore Companion Radio Protocol: [GitHub Wiki](https://github.com/meshcore-dev/MeshCore/wiki/Companion-Radio-Protocol)
|
||||
- Bluetooth SIG Assigned Numbers (officiële services): [bluetooth.com/specifications/assigned-numbers](https://www.bluetooth.com/specifications/assigned-numbers/)
|
||||
- Bluetooth SIG GATT Specifications: [bluetooth.com/specifications/specs](https://www.bluetooth.com/specifications/specs/)
|
||||
- Nordic Bluetooth Numbers Database: [GitHub](https://github.com/NordicSemiconductor/bluetooth-numbers-database)
|
||||
- GATT Uitleg (Adafruit): [learn.adafruit.com](https://learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt)
|
||||
- Bleak documentatie: [bleak.readthedocs.io](https://bleak.readthedocs.io/)
|
||||
- BlueZ: [bluez.org](http://www.bluez.org/)
|
||||
|
||||
---
|
||||
|
||||
> **Document:** `ble_capture_workflow_t_1000_e_uitleg.md`
|
||||
> **Gebaseerd op:** `ble_capture_workflow_t_1000_e.md`
|
||||
1105
meshcore_gui.py
Normal file
1105
meshcore_gui.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user