flutter_ota 0.1.8 copy "flutter_ota: ^0.1.8" to clipboard
flutter_ota: ^0.1.8 copied to clipboard

A Flutter package for OTA updating firmware of ESP32 using Bluetooth Low Energy (BLE).

example/lib/main.dart

// ignore_for_file: use_build_context_synchronously

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:flutter_ota/ota_package.dart';
import 'package:get/get.dart';

import 'controllers/bleUart_controller.dart';
import 'controllers/ble_servicescontroller.dart';

// This class represents a page for OTA (Over-The-Air) firmware updates.
class OtaUpdatePage extends StatelessWidget {
  // Controllers for handling user input and displaying received data.
  final TextEditingController commandController = TextEditingController();
  final TextEditingController receivedController = TextEditingController();

  // Controller for managing Bluetooth Low Energy UART communication.
  final BleUartController bleUartController = BleUartController();

  // Flags to control UI elements.
  bool showProgressDialog = true; // Flag to show progress dialog.
  bool firmwareFileSelected = false; // Flag indicating whether firmware file is selected.

  // Bluetooth Characteristics for data and control.
  BluetoothCharacteristic? dataUuid;
  BluetoothCharacteristic? controlUuid;

  // File path for the firmware binary file.
  String? binfile;

  @override
Widget build(BuildContext context) {
  // Completer to handle asynchronous completion for confirming Bluetooth disconnection.
  Completer<bool> _completer = Completer<bool>();
  // Variable to store the custom path for firmware updates.
  String? customPath;

  // Build method returns a WillPopScope widget to handle the back button press.
  return WillPopScope(
    // onWillPop callback is triggered when the back button is pressed.
    onWillPop: () async {
      // Show a confirmation dialog before navigating back.
      showDialog(
        context: context,
        builder: (context) => AlertDialog(
          title: const Text('Disconnect and Go Back?'),
          content: const Text(
            'Do you want to disconnect from the available Bluetooth devices and go back to the scanning page?',
          ),
          actions: [
            // Disconnect button pressed.
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                // Add any custom styling for the button if needed.
              ),
              onPressed: () async {
                // Close the dialog, navigate to scanning page, and complete with true.
                Navigator.pop(context);
                Navigator.pushReplacementNamed(context, '/scanningpage');
                _completer.complete(true);
              },
              child: const Text('Disconnect'),
            ),
            // Cancel button pressed.
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                // Add any custom styling for the button if needed.
              ),
              onPressed: () {
                // Close the dialog and complete with false.
                Navigator.pop(context);
                _completer.complete(false);
              },
              child: const Text('Cancel'),
            ),
          ],
        ),
      );
      // Wait for the completion of user's choice before allowing the back navigation.
      return await _completer.future;
    },
      child: Container(
  // Container with a gradient background.
  decoration: const BoxDecoration(
    gradient: LinearGradient(
      colors: [
        Color.fromRGBO(125, 186, 236, 1),
        Color.fromRGBO(82, 116, 211, 0.933),
      ],
      begin: Alignment.topCenter,
      end: Alignment.bottomCenter,
    ),
  ),
  child: Scaffold(
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // Elevated button for initiating firmware update.
          ElevatedButton(
            onPressed: () async {
              // Assume the user will type the path manually.
              customPath = await showDialog(
                context: context,
                builder: (context) => AlertDialog(
                  title: const Text('Enter Custom Firmware Path'),
                  content: TextField(
                    onChanged: (value) {
                      customPath = value;
                    },
                    decoration: const InputDecoration(
                      hintText: 'Enter Firmware Path',
                    ),
                  ),
                  actions: [
                    // OK button pressed after entering the custom path.
                    ElevatedButton(
                      onPressed: () {
                        Navigator.pop(context, customPath);
                      },
                      child: const Text('OK'),
                    ),
                  ],
                ),
              );

              // Check if user canceled or did not enter a path.
              if (customPath == null || customPath!.isEmpty) {
                // User canceled or did not enter a path.
                firmwareFileSelected = false;
                return;
              } else {
                // User provided a custom firmware path.
                firmwareFileSelected = true;
              }

              // Get connected Bluetooth device and services from the BLE controller.
              BluetoothDevice? device =
                  Get.find<BleDeviceController>().connectedDevice;
              List<BluetoothService> services =
                  Get.find<BleDeviceController>().bleServices;

              // Check if device and services are available for OTA update.
              if (device == null || services.isEmpty) {
                print("Device or services not available for OTA update");
                return;
              }

              // Flag to check if required characteristics are found.
              bool characteristicsFound = false;

              // Iterate through the available services to find the required characteristics.
              for (BluetoothService service in services) {
                if (service.uuid.toString() ==
                    'd6f1d96d-594c-4c53-b1c6-144a1dfde6d8') {
                  final characteristics = service.characteristics;
                  BluetoothCharacteristic? dataUuid;
                  BluetoothCharacteristic? controlUuid;

                  // Iterate through characteristics to find data and control UUIDs.
                  for (BluetoothCharacteristic c in characteristics) {
                    if (c.uuid.toString() ==
                        '23408888-1f40-4cd8-9b89-ca8d45f8a5b0') {
                      dataUuid = c;
                    }
                    if (c.uuid.toString() ==
                        '7ad671aa-21c0-46a4-b722-270e3ae3d830') {
                      controlUuid = c;
                    }
                  }

                  // If both data and control UUIDs are found, proceed with OTA update.
                  if (dataUuid != null && controlUuid != null) {
                    // Adjust MTU size based on the platform (Android or iOS).
                    if (Platform.isAndroid) {
                      const newMtu = 300;
                      await device.requestMtu(newMtu);
                      print('New MTU size (Android): $newMtu');
                    } else if (Platform.isIOS) {
                      const newMtu = 185;
                      print('New MTU size (iOS): $newMtu');
                    }

                    // Create an OTA package instance.
                    final esp32otaPackage = Esp32OtaPackage(dataUuid, controlUuid);

                                                  // Show a progress dialog during the OTA update.
                          showDialog(
                            context: context,
                            barrierDismissible: false,
                            builder: (context) => AlertDialog(
                              title: const Text('OTA Update in Progress'),
                              content: StreamBuilder<int>(
                                stream: esp32otaPackage.percentageStream,
                                initialData: 0,
                                builder: (BuildContext context,
                                    AsyncSnapshot<int> snapshot) {
                                  double progress =
                                      snapshot.data! / 100.toDouble();

                                  // Handle completion of OTA update and show a snackbar.
                                  if (progress >= 1.0 && showProgressDialog) {
                                    WidgetsBinding.instance
                                        ?.addPostFrameCallback((_) {
                                      showProgressDialog = false;
                                      Navigator.pop(context);
                                      ScaffoldMessenger.of(context)
                                          .showSnackBar(
                                        const SnackBar(
                                          content: Text('OTA Update Complete'),
                                          duration: Duration(seconds: 2),
                                        ),
                                      );
                                    });
                                  }

                                  return LinearProgressIndicator(
                                    value: progress,
                                    valueColor:
                                        const AlwaysStoppedAnimation<Color>(
                                            Colors.blue),
                                    backgroundColor: Colors.grey[300],
                                  );
                                },
                              ),
                            ),
                          );

                          // Perform the firmware update if a firmware file is selected.
                          if (firmwareFileSelected) {
                            await esp32otaPackage.updateFirmware(
                              device,
                              2, // Set firmwareType to 2 for file picker
                              service,
                              dataUuid,
                              controlUuid,
                            );
                          }

                          // Set flag to indicate that characteristics were found.
                          characteristicsFound = true;
                          break;
                        }
                      }
                    }

                    // Show a dialog if the required characteristics are not found.
                    if (!characteristicsFound) {
                      showDialog(
                        context: context,
                        builder: (context) => AlertDialog(
                          title: const Text('Device Not Compatible'),
                          content: const Text(
                            'The device does not have the required characteristics for OTA firmware update.',
                          ),
                          actions: [
                            ElevatedButton(
                              onPressed: () {
                                Navigator.pop(context);
                              },
                              child: const Text('OK'),
                            ),
                          ],
                        ),
                      );
                    }
                  },
                  // Elevated button for initiating OTA update.
                  child: const Text('OTA Update'),
                ),
                const SizedBox(height: 50),
                const Text(
                  'Send Command',
                  style: TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 20),
                // Text field for entering commands.
                Padding(
                  padding: const EdgeInsets.symmetric(
                      horizontal: 20), // Add desired horizontal padding
                  child: TextField(
                    controller: commandController,
                    enabled: true,
                    keyboardType: TextInputType.text,
                    decoration: InputDecoration(
                      hintText: 'Enter Command Here',
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(10),
                      ),
                      contentPadding: const EdgeInsets.all(16),
                    ),
                  ),
                ),
                // Elevated button for sending commands via BLE.
                ElevatedButton(
                  onPressed: () {
                    String command = commandController.text;
                    print("Sent data:  $command");

                    // Send the command via BLE UART.
                    bleUartController.sendCommand(command);

                    // Hide the keyboard after sending the command.
                    FocusScope.of(context).unfocus();
                  },
                  child: const Text('Send'),
                ),
                const SizedBox(height: 20),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
14
likes
0
pub points
66%
popularity

Publisher

verified publishersparkleo.io

A Flutter package for OTA updating firmware of ESP32 using Bluetooth Low Energy (BLE).

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

cupertino_icons, file_picker, flutter, flutter_blue_plus, get, http, mockito, path, path_provider, permission_handler

More

Packages that depend on flutter_ota