nrf_mesh_flutter 6.6.0 copy "nrf_mesh_flutter: ^6.6.0" to clipboard
nrf_mesh_flutter: ^6.6.0 copied to clipboard

Flutter plugin for Bluetooth Mesh using Nordic nRF Mesh libraries

example/lib/main.dart

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:nrf_mesh_flutter/nrf_mesh_flutter.dart';
import 'group_messaging_page.dart';
import 'real_p1_page.dart';
import 'provisioning_demo_page.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await PlatoJobsNrfMeshManager.instance.initialize();
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _meshManager = PlatoJobsNrfMeshManager.instance;
  MeshNetwork? _network;
  List<UnprovisionedDevice> _devices = [];
  List<ProvisionedNode> _nodes = [];
  List<MeshGroup> _groups = [];
  bool _isScanning = false;
  String _status = 'Ready';

  @override
  void initState() {
    super.initState();
    _loadNetwork();
    _listenToMessages();
  }

  Future<void> _loadNetwork() async {
    try {
      setState(() => _status = 'Loading network...');
      _network = await _meshManager.loadNetwork();
      if (_network == null) {
        _network = await _meshManager.createNetwork('My Mesh Network');
        setState(() => _status = 'Network created');
      } else {
        setState(() => _status = 'Network loaded');
      }
      _loadNodesAndGroups();
    } catch (e) {
      setState(() => _status = 'Error: $e');
    }
  }

  Future<void> _loadNodesAndGroups() async {
    _nodes = await _meshManager.getNodes();
    _groups = await _meshManager.getGroups();
    setState(() {});
  }

  void _listenToMessages() {
    _meshManager.messageStream.listen((message) {
      setState(() {
        _status = 'Received message: ${message.opcode}';
      });
    });
  }

  Future<void> _startScan() async {
    setState(() {
      _isScanning = true;
      _devices = [];
      _status = 'Scanning for devices...';
    });

    _meshManager.scanForDevices().listen((device) {
      setState(() {
        final id = device.deviceId;
        if (!_devices.any((d) => d.deviceId == id)) {
          _devices.add(device);
        }
      });
    });
  }

  Future<void> _stopScan() async {
    await _meshManager.stopScan();
    setState(() {
      _isScanning = false;
      _status = 'Scan stopped';
    });
  }

  Future<void> _provisionDevice(UnprovisionedDevice device) async {
    try {
      setState(() => _status = 'Provisioning device...');
      await _meshManager.provisionDevice(
        device,
        ProvisioningParameters(
          deviceName: device.name.isEmpty ? 'Mesh Device' : device.name,
        ),
      );
      setState(() => _status = 'Device provisioned');
      await _loadNodesAndGroups();
    } catch (e) {
      setState(() => _status = 'Provisioning error: $e');
    }
  }

  Future<void> _sendTestMessage() async {
    try {
      if (_nodes.isEmpty) {
        setState(() => _status = 'No nodes available');
        return;
      }

      setState(() => _status = 'Sending test message...');
      await _meshManager.sendMessage(
        GenericOnOffSet(
          state: true,
          transitionTime: 0,
          delay: 0,
          address: 0xC000,
          appKeyIndex: 0,
        ),
      );
      setState(() => _status = 'Message sent');
    } catch (e) {
      setState(() => _status = 'Send error: $e');
    }
  }

  Future<void> _configDemo() async {
    try {
      if (_nodes.isEmpty) {
        setState(() => _status = 'No nodes available');
        return;
      }
      final first = _nodes.first;
      if (first.elements.isEmpty || first.elements.first.models.isEmpty) {
        setState(() => _status = 'Node has no models');
        return;
      }
      final elementAddress = int.tryParse(
            first.elements.first.address.replaceAll('0x', ''),
            radix: 16,
          ) ??
          1;
      final modelId = int.tryParse(first.elements.first.models.first.modelId) ?? 0x1000;

      setState(() => _status = 'Configuring model...');
      await _meshManager.bindAppKey(elementAddress, modelId, 0);
      await _meshManager.addSubscription(elementAddress, modelId, 0xC000);
      await _meshManager.setPublication(elementAddress, modelId, 0xC000, 0, ttl: 5);
      setState(() => _status = 'Config updated');
      await _loadNodesAndGroups();
    } catch (e) {
      setState(() => _status = 'Config error: $e');
    }
  }

  Future<void> _createGroup() async {
    try {
      setState(() => _status = 'Creating group...');
      await _meshManager.createGroup('Test Group');
      setState(() => _status = 'Group created');
      await _loadNodesAndGroups();
    } catch (e) {
      setState(() => _status = 'Create group error: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('PlatoJobs nRF Mesh Example')),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text('Status: $_status', style: const TextStyle(fontSize: 16)),
              const SizedBox(height: 16),
              if (_network != null)
                Card(
                  child: Padding(
                    padding: const EdgeInsets.all(12.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        const Text(
                          'Network',
                          style: TextStyle(fontWeight: FontWeight.bold),
                        ),
                        Text('Name: ${_network?.name}'),
                        Text('Nodes: ${_nodes.length}'),
                        Text('Groups: ${_groups.length}'),
                      ],
                    ),
                  ),
                ),
              const SizedBox(height: 16),
              Row(
                children: [
                  ElevatedButton(
                    onPressed: _isScanning ? _stopScan : _startScan,
                    child: Text(_isScanning ? 'Stop Scan' : 'Start Scan'),
                  ),
                  const SizedBox(width: 16),
                  ElevatedButton(
                    onPressed: _sendTestMessage,
                    child: const Text('Send Test Message'),
                  ),
                  const SizedBox(width: 16),
                  ElevatedButton(
                    onPressed: _createGroup,
                    child: const Text('Create Group'),
                  ),
                  const SizedBox(width: 16),
                  ElevatedButton(
                    onPressed: _configDemo,
                    child: const Text('Config Demo'),
                  ),
                  const SizedBox(width: 16),
                  ElevatedButton(
                    onPressed: () {
                      Navigator.of(context).push(
                        MaterialPageRoute<void>(
                          builder: (_) => const RealP1Page(),
                        ),
                      );
                    },
                    child: const Text('P1 Real Flow'),
                  ),
                  const SizedBox(width: 16),
                  ElevatedButton(
                    onPressed: () {
                      Navigator.of(context).push(
                        MaterialPageRoute<void>(
                          builder: (_) => const ProvisioningDemoPage(),
                        ),
                      );
                    },
                    child: const Text('M1 Provisioning'),
                  ),
                  const SizedBox(width: 16),
                  ElevatedButton(
                    onPressed: () {
                      Navigator.of(context).push(
                        MaterialPageRoute<void>(
                          builder: (_) => const GroupMessagingPage(),
                        ),
                      );
                    },
                    child: const Text('M3 Groupcast'),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              const Text(
                'Provisioned Nodes',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              SizedBox(
                height: 160,
                child: ListView.builder(
                  itemCount: _nodes.length,
                  itemBuilder: (context, index) {
                    final node = _nodes[index];
                    final element = node.elements.isNotEmpty ? node.elements.first : null;
                    final model = (element != null && element.models.isNotEmpty) ? element.models.first : null;
                    return ListTile(
                      dense: true,
                      title: Text('Node ${node.uuid} @ ${node.unicastAddress}'),
                      subtitle: model == null
                          ? const Text('No model info')
                          : Text(
                              'Element: ${element!.address}\n'
                              'Model: ${model.modelName} (${model.modelId})\n'
                              'Bound AppKeys: ${model.boundAppKeyIndexes}\n'
                              'Subs: ${model.subscriptions}\n'
                              'Pub: ${model.publication == null ? 'null' : 'addr=${model.publication!.address} appKey=${model.publication!.appKeyIndex} ttl=${model.publication!.ttl}'}',
                            ),
                    );
                  },
                ),
              ),
              const SizedBox(height: 16),
              const Text(
                'Discovered Devices',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              Expanded(
                child: ListView.builder(
                  itemCount: _devices.length,
                  itemBuilder: (context, index) {
                    final device = _devices[index];
                    return ListTile(
                      title: Text(device.name),
                      subtitle: Text(
                        'ID: ${device.deviceId}\nRSSI: ${device.rssi}',
                      ),
                      trailing: ElevatedButton(
                        onPressed: () => _provisionDevice(device),
                        child: const Text('Provision'),
                      ),
                    );
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
2
likes
0
points
77
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for Bluetooth Mesh using Nordic nRF Mesh libraries

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

convert, crypto, flutter, meta, plugin_platform_interface, pointycastle

More

Packages that depend on nrf_mesh_flutter

Packages that implement nrf_mesh_flutter