nrf_mesh_flutter 6.9.0
nrf_mesh_flutter: ^6.9.0 copied to clipboard
Flutter plugin for Bluetooth Mesh using Nordic nRF Mesh libraries
nRF Mesh Flutter Plugin #
A Flutter plugin for Bluetooth Mesh networking, based on Nordic Semiconductor's nRF Mesh libraries (iOS / Android).
Features #
- Network Management: Create, load, save, export, and import mesh networks
- Device Provisioning: Provision unprovisioned devices into the mesh network
- Device Scanning: Scan for nearby unprovisioned BLE devices
- Message Communication: Send and receive mesh messages
- Node Management: Manage provisioned nodes in the network
- Group Management: Create and manage mesh groups
- Standard Models: Support for Generic On/Off, Light, and other standard BLE Mesh models
Supported Platforms #
- iOS: 13.0+
- Android: API 24+ (Android 7.0 Nougat)
Installation #
Add nrf_mesh_flutter to your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
nrf_mesh_flutter: ^6.9.0
Release notes language #
Release notes in CHANGELOG.md are maintained in English only.
Recommended: sending raw Access messages #
If you need to send vendor/custom messages (or want to avoid the implicit parameters['bytes'] convention), prefer sendAccess(...):
await PlatoJobsNrfMeshManager.instance.sendAccess(
opCode: 0x8202, // example: Generic OnOff Set (ack)
parameters: const [0x01, 0x01], // payload bytes
address: 0x0003, // destination (unicast/group/virtual)
appKeyIndex: 0,
);
Notes:
messageStreammay emit messages withaddress == nullon some platforms / library versions (when the native side cannot reliably extract the source address). Always handle that case.
iOS Configuration #
Add the following to your ios/Podfile:
platform :ios, '13.0'
use_frameworks!
Android Configuration #
Add Bluetooth permissions to your android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Quick Start #
import 'package:nrf_mesh_flutter/nrf_mesh_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize the mesh manager
await PlatoJobsNrfMeshManager.instance.initialize();
runApp(const MyApp());
}
Provisioning Flow (High Level) #
flowchart TD
A[initialize()] --> B[loadNetwork()]
B -->|null / empty| C[createNetwork()]
B -->|exists| D[scanForDevices()]
C --> D
D --> E[provisionDevice()]
E --> F[sendMessage()]
F --> G[messageStream]
Mocking (No Hardware Needed) #
For UI development without real Mesh hardware you can inject a fake bridge:
import 'package:nrf_mesh_flutter/nrf_mesh_flutter.dart';
final fake = FakePlatoJobsMeshBridge(
scenario: FakeMeshScenario()
.add(
FakeMeshScenarioStep.discoveredDevice(
UnprovisionedDevice(
deviceId: 'dev-1',
name: 'Demo',
serviceUuid: '',
rssi: -40,
serviceData: const <int>[1, 2, 3],
),
),
)
.add(
FakeMeshScenarioStep.incomingMessage(GenericOnOffSet(state: true)),
),
);
PlatoJobsNrfMeshManager.setBridgeForTesting(fake);
await PlatoJobsNrfMeshManager.instance.initialize();
Notes:
- Call
scanForDevices()to start the scripted scenario (it runs once per fake instance). - You can still push events manually with
emitDiscoveredDevice(...)/emitIncomingMessage(...).
Usage #
Network Management #
// Create a new mesh network
final network = await PlatoJobsNrfMeshManager.instance.createNetwork('My Mesh Network');
// Load an existing network
final loadedNetwork = await PlatoJobsNrfMeshManager.instance.loadNetwork();
// Save the current network
await PlatoJobsNrfMeshManager.instance.saveNetwork();
// Export network to a file
await PlatoJobsNrfMeshManager.instance.exportNetwork('/path/to/export.json');
// Import network from a file
await PlatoJobsNrfMeshManager.instance.importNetwork('/path/to/import.json');
Device Scanning #
// Start scanning for unprovisioned devices
StreamSubscription<UnprovisionedDevice> subscription =
PlatoJobsNrfMeshManager.instance.scanForDevices().listen((device) {
print('Discovered: ${device.name} (${device.deviceId})');
});
// Stop scanning
await PlatoJobsNrfMeshManager.instance.stopScan();
// Cancel subscription when done
await subscription.cancel();
Device Provisioning #
// Provision a device
final node = await PlatoJobsNrfMeshManager.instance.provisionDevice(
device,
ProvisioningParameters(
deviceName: 'My Device',
oobMethod: 0,
enablePrivacy: false,
),
);
Sending Messages #
// Send a Generic On/Off message
await PlatoJobsNrfMeshManager.instance.sendMessage(
GenericOnOffSet(
state: true,
transitionTime: 0,
delay: 0,
address: 0xC000, // e.g. group address or node unicast
appKeyIndex: 0,
),
);
// Listen for incoming messages
PlatoJobsNrfMeshManager.instance.messageStream.listen((message) {
print('Received message: ${message.opcode}');
});
Node Management #
// Get all provisioned nodes
final nodes = await PlatoJobsNrfMeshManager.instance.getNodes();
// Remove a node
await PlatoJobsNrfMeshManager.instance.removeNode(nodeId);
Group Management #
// Create a new group
final group = await PlatoJobsNrfMeshManager.instance.createGroup('Living Room');
// Get all groups
final groups = await PlatoJobsNrfMeshManager.instance.getGroups();
// Add a node to a group
await PlatoJobsNrfMeshManager.instance.addNodeToGroup(nodeId, groupId);
API Reference #
Core Class #
PlatoJobsNrfMeshManager
The main entry point for the plugin. Uses singleton pattern.
Singleton Access:
PlatoJobsNrfMeshManager.instance
Methods:
| Method | Description |
|---|---|
initialize() |
Initialize the mesh manager |
createNetwork(name) |
Create a new mesh network |
loadNetwork() |
Load an existing mesh network |
saveNetwork() |
Save the current mesh network |
exportNetwork(path) |
Export network to a JSON file |
importNetwork(path) |
Import network from a JSON file |
scanForDevices() |
Start scanning for unprovisioned devices |
stopScan() |
Stop scanning |
provisionDevice(device, params) |
Provision a device |
sendMessage(message) |
Send a mesh message |
getNodes() |
Get all provisioned nodes |
removeNode(nodeId) |
Remove a node |
createGroup(name) |
Create a new group |
getGroups() |
Get all groups |
addNodeToGroup(nodeId, groupId) |
Add a node to a group |
Properties:
| Property | Type | Description |
|---|---|---|
messageStream |
Stream<MeshMessage> |
Stream of received mesh messages |
Data Models #
MeshNetwork
Represents a Bluetooth Mesh network.
Properties:
networkId: Unique network identifiername: Network namenetworkKeys: List of network keysappKeys: List of application keysnodes: List of provisioned nodesgroups: List of mesh groupsprovisioner: Network provisioner info
ProvisionedNode
Represents a provisioned mesh node.
Properties:
uuid: Node UUIDunicastAddress: Node unicast addresselements: List of elementsnetworkKeys: List of network keysappKeys: List of application keysfeatures: Node features (relay, proxy, friend, low power)
UnprovisionedDevice
Represents a discovered unprovisioned device.
Properties:
deviceId: Device identifiername: Device nameserviceUuid: Service UUIDrssi: Signal strengthserviceData: Service data from advertising packets
MeshGroup
Represents a mesh group.
Properties:
groupId: Group identifiername: Group nameaddress: Group addressnodeIds: List of node IDs in the group
MeshMessage
Base class for mesh messages.
Properties:
opcode: Message opcodeparameters: Message parameters
Architecture #
The plugin follows a layered architecture:
┌─────────────────────────────────┐
│ Dart Layer │
│ (PlatoJobsNrfMeshManager) │
├─────────────────────────────────┤
│ Platform Interface │
│ (PlatoJobsMeshPlatform) │
├─────────────────────────────────┤
│ Pigeon Generated Code │
│ (Auto-generated codec) │
├─────────────────────────────────┤
│ Native Layer │
│ (Swift / Kotlin) │
├─────────────────────────────────┤
│ Nordic nRF Mesh Library │
│ (iOS / Android) │
└─────────────────────────────────┘
Dependencies #
Flutter Dependencies #
plugin_platform_interface: ^2.0.2- Platform interface supportconvert: ^3.1.1- JSON conversioncrypto: ^3.0.3- Cryptographic functionsmeta: ^1.10.0- Annotations
Native Dependencies #
- iOS:
nRFMeshProvision ~> 4.8.0 - Android: Nordic Android nRF Mesh Library
Error Handling #
All async methods may throw PlatoJobsMeshException (a readable wrapper over platform errors, timeouts, and common BLE failures).
try {
await PlatoJobsNrfMeshManager.instance.initialize();
} on PlatoJobsMeshException catch (e) {
// e.g. permission / connection / timeout / invalid state
print('Mesh error: $e');
}
Android 12+ / 14+ Notes #
- Android 12+ needs runtime permissions:
BLUETOOTH_SCAN/BLUETOOTH_CONNECT. - Android 13+ 如果要在通知中提示连接状态,可能需要
POST_NOTIFICATIONS(由你的 App 决定是否需要)。 - Android 14+ background scan/connection restrictions are stricter: keep provisioning/proxy connection in a user-visible flow, and implement retry + timeouts.
iOS 13+ / 17+ Notes #
- Add Bluetooth usage descriptions to
Info.plist(e.g.NSBluetoothAlwaysUsageDescription). - iOS 17+ is more sensitive about background operations: keep mesh actions in the foreground flow where possible.
Examples #
See the example directory for a complete demo application demonstrating all features.
License #
MIT License - see LICENSE file for details.
Author #
PlatoJobs
Changelog #
For the full history, see CHANGELOG.md.
Latest #
See CHANGELOG.md for the full history and the latest release notes.