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