Meshtastic Flutter
A comprehensive Flutter package for communicating with Meshtastic devices over Bluetooth Low Energy (BLE).
Features
- Complete BLE Integration: Connect to Meshtastic devices using the official Meshtastic Bluetooth service
- Full Protocol Support: Implements the complete Meshtastic protocol including configuration, messaging, and telemetry
- Node Management: Track and manage all nodes in the mesh network
- Real-time Updates: Stream-based API for real-time packet and node updates
- Type-safe: Fully typed API with comprehensive wrapper classes
- Cross-platform: Works on both Android and iOS
Installation
Add this to your package's pubspec.yaml
file:
dependencies:
meshtastic_flutter: ^0.0.1
Complete the setup for permission_handler
plugin as given here
Permissions
Android
Add these permissions to your android/app/src/main/AndroidManifest.xml
:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
iOS
Add these to your ios/Runner/Info.plist
:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth to connect to Meshtastic devices</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app needs Bluetooth to connect to Meshtastic devices</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location for Bluetooth scanning</string>
Quick Start
import 'package:meshtastic_flutter/meshtastic_flutter.dart';
void main() async {
// Create and initialize the client
final client = MeshtasticClient();
await client.initialize();
// Listen for connection changes
client.connectionStream.listen((status) {
print('Connection: ${status.state}');
});
// Listen for incoming messages
client.packetStream.listen((packet) {
if (packet.isTextMessage) {
print('Message from ${packet.from.toRadixString(16)}: ${packet.textMessage}');
}
});
// Scan and connect to a device
await for (final device in client.scanForDevices()) {
await client.connectToDevice(device);
break; // Connect to first device found
}
// Send a message
await client.sendTextMessage('Hello Mesh!');
// Send position
await client.sendPosition(37.7749, -122.4194);
}
API Documentation
MeshtasticClient
The main client class for interacting with Meshtastic devices.
Methods
initialize()
- Initialize the client and request permissionsscanForDevices()
- Stream of nearby Meshtastic devicesconnectToDevice(BluetoothDevice)
- Connect to a specific devicedisconnect()
- Disconnect from current devicesendTextMessage(String, {int? destinationId, int channel})
- Send text messagesendPosition(double lat, double lon, {int? altitude})
- Send position update
Properties
connectionStream
- Stream of connection status changespacketStream
- Stream of incoming mesh packetsnodeStream
- Stream of node information updatesnodes
- Map of all known nodesmyNodeInfo
- Information about the local nodeconfig
- Device configurationisConnected
- Whether connected to a deviceisConfigured
- Whether initial configuration is complete
MeshPacketWrapper
Wrapper class for MeshPacket with convenience methods.
Properties
from
/to
- Sender and destination node IDschannel
- Channel numberisTextMessage
/isTelemetry
/isPosition
- Packet type checkstextMessage
- Text content (if text message)isEncrypted
/isDecoded
- Encryption statuspacketTypeDescription
- Human-readable packet type
NodeInfoWrapper
Wrapper class for NodeInfo with enhanced functionality.
Properties
displayName
- Best available name for the nodelongName
/shortName
- User nameslatitude
/longitude
/altitude
- Position databatteryLevel
/voltage
- Power informationlastHeard
- Last contact timestampisOnline
- Whether node is currently reachablestatusDescription
- Summary status string
ConnectionStatus
Information about the current connection state.
Properties
state
- Current connection state (disconnected, connecting, configuring, connected, error)deviceAddress
/deviceName
- Connected device informationerrorMessage
- Error description (if any)timestamp
- When status changed
Usage Examples
Basic Messaging
final client = MeshtasticClient();
await client.initialize();
// Connect to first device found
await for (final device in client.scanForDevices()) {
await client.connectToDevice(device);
break;
}
// Send broadcast message
await client.sendTextMessage('Hello everyone!');
// Send direct message to specific node
await client.sendTextMessage('Private message', destinationId: 0x12345678);
// Send on specific channel
await client.sendTextMessage('Channel message', channel: 1);
Node Monitoring
// Listen for node updates
client.nodeStream.listen((node) {
print('Node ${node.displayName}:');
print(' Battery: ${node.batteryLevel}%');
print(' Last heard: ${node.lastHeard}');
print(' Position: ${node.latitude}, ${node.longitude}');
print(' Distance: ${myNode.distanceFrom(node)}m');
});
// Get all nodes
for (final node in client.nodes.values) {
print('${node.displayName} - ${node.statusDescription}');
}
Configuration Access
final config = client.config;
if (config != null) {
print('Device role: ${config.deviceRole}');
print('LoRa region: ${config.region}');
print('Channels: ${config.channels.length}');
print('Primary channel: ${config.primaryChannel?.settings.name}');
}
Error Handling
try {
await client.connectToDevice(device);
} on BluetoothException catch (e) {
print('Bluetooth error: $e');
} on ConnectionException catch (e) {
print('Connection error: $e');
} on PermissionException catch (e) {
print('Permission error: $e');
} catch (e) {
print('Unexpected error: $e');
}
Protocol Implementation
This package implements the complete Meshtastic Bluetooth protocol:
BLE Service Details
- Service UUID:
6ba1b218-15a8-461f-9fa8-5dcae273eafd
- ToRadio:
f75c76d2-129e-4dad-a1dd-7866124401e7
(write commands/packets) - FromRadio:
2c55e69e-4993-11ed-b878-0242ac120002
(read responses) - FromNum:
ed9da18c-a800-4f66-a670-aa7547e34453
(notifications for new data)
Configuration Flow
- Connect to device and discover services
- Set MTU to 512 bytes
- Enable notifications on FromNum characteristic
- Send
wantConfigId
to start configuration download - Read configuration data until
configCompleteId
received - Continue reading for ongoing mesh packets
Supported Message Types
- Text messages (
TEXT_MESSAGE_APP
) - Position updates (
POSITION_APP
) - Node information (
NODEINFO_APP
) - Telemetry data (
TELEMETRY_APP
) - Administrative commands (
ADMIN_APP
) - Routing information (
ROUTING_APP
)
Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
License
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
Related Projects
- Meshtastic - The main Meshtastic project
- Meshtastic Android - Official Android app
- Meshtastic Protobuf - Protocol buffer definitions
Libraries
- generated/admin.pb
- generated/admin.pbenum
- generated/admin.pbjson
- generated/apponly.pb
- generated/apponly.pbenum
- generated/apponly.pbjson
- generated/atak.pb
- generated/atak.pbenum
- generated/atak.pbjson
- generated/cannedmessages.pb
- generated/cannedmessages.pbenum
- generated/cannedmessages.pbjson
- generated/channel.pb
- generated/channel.pbenum
- generated/channel.pbjson
- generated/clientonly.pb
- generated/clientonly.pbenum
- generated/clientonly.pbjson
- generated/config.pb
- generated/config.pbenum
- generated/config.pbjson
- generated/connection_status.pb
- generated/connection_status.pbenum
- generated/connection_status.pbjson
- generated/device_ui.pb
- generated/device_ui.pbenum
- generated/device_ui.pbjson
- generated/deviceonly.pb
- generated/deviceonly.pbenum
- generated/deviceonly.pbjson
- generated/interdevice.pb
- generated/interdevice.pbenum
- generated/interdevice.pbjson
- generated/localonly.pb
- generated/localonly.pbenum
- generated/localonly.pbjson
- generated/mesh.pb
- generated/mesh.pbenum
- generated/mesh.pbjson
- generated/module_config.pb
- generated/module_config.pbenum
- generated/module_config.pbjson
- generated/mqtt.pb
- generated/mqtt.pbenum
- generated/mqtt.pbjson
- generated/paxcount.pb
- generated/paxcount.pbenum
- generated/paxcount.pbjson
- generated/portnums.pb
- generated/portnums.pbenum
- generated/portnums.pbjson
- generated/powermon.pb
- generated/powermon.pbenum
- generated/powermon.pbjson
- generated/remote_hardware.pb
- generated/remote_hardware.pbenum
- generated/remote_hardware.pbjson
- generated/rtttl.pb
- generated/rtttl.pbenum
- generated/rtttl.pbjson
- generated/storeforward.pb
- generated/storeforward.pbenum
- generated/storeforward.pbjson
- generated/telemetry.pb
- generated/telemetry.pbenum
- generated/telemetry.pbjson
- generated/xmodem.pb
- generated/xmodem.pbenum
- generated/xmodem.pbjson
- meshtastic_flutter