我无法使用 flutter_Blue_Plus 在 ESP32 上同时读写数据

问题描述 投票:0回答:1

我在 Flutter 应用程序中使用 ESP32 作为 BLE 设备时遇到了问题(我使用 Flutter_Blue_Plus 包)。我希望能够读取 ESP 发送的信息并同时写入另一个特征。 但是当我读完之后开始写作时,我会遇到很大的延迟,这是我想避免的。

我的问题如下:

我有一个 ESP32,配置为充当 BLE 设备。 我的 Flutter 应用程序通过 BLE 连接到该 ESP32,并尝试从特征中读取数据。 我开始通过应用程序将 JSON 文件写入 EPS32 上的另一个特征。 此时在 ESP32 接收数据之前我有一个很大的延迟,该延迟对应于读取的持续时间。 (如果没有开始读取,我就没有这个延迟)

(抱歉我的代码没有优化)

这是我的主页(其中包含已读内容):


class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key,}) : super(key: key);
  
  @override
  State<HomeScreen> createState() => _HomeScreenState();
  
}

class _HomeScreenState extends State<HomeScreen> {
  int? _rssi;
  int? _mtuSize;
  BluetoothConnectionState _connectionState = BluetoothConnectionState.disconnected;

  bool _isConnectingOrDisconnecting = false;

  StreamSubscription<BluetoothConnectionState>? _connectionStateSubscription; // pb avec ça j'ai rajouter ? et enlever late mais erreur : _HomeScreenState.dispose failed to call super.dispose. psq pas init 
  StreamSubscription<bool>? _isConnectingOrDisconnectingSubscription;
  StreamSubscription<int>? _mtuSubscription;


  @override
  void initState() {
    super.initState();
    if (BLEdevice?.remoteId.toString() != '00:00:00:00:00:00') {

      _connectionStateSubscription = BLEdevice!.connectionState.listen((state) async {
        _connectionState = state;
        if (state == BluetoothConnectionState.connected) {
          services = []; 
        }
        if (state == BluetoothConnectionState.connected && _rssi == null) {
          _rssi = await BLEdevice!.readRssi();
        }
        setState(() {});
      });

      _mtuSubscription = BLEdevice!.mtu.listen((value) {
        _mtuSize = value;
        setState(() {});
      });

      _isConnectingOrDisconnectingSubscription = BLEdevice!.isConnectingOrDisconnecting.listen((value) {
        _isConnectingOrDisconnecting = value;
        setState(() {});
      });

      getServices();

    }
  }

  @override
  void dispose() {
    //print(BLEdevice?.remoteId.toString());
    if (BLEdevice?.remoteId.toString() != '00:00:00:00:00:00') {
      _connectionStateSubscription?.cancel();
      _mtuSubscription?.cancel();
      _isConnectingOrDisconnectingSubscription?.cancel();
      super.dispose();
    }
    else 
    {
      super.dispose();
    }
  }



  bool get isConnected {
    return _connectionState == BluetoothConnectionState.connected;
  }

  Future onConnectPressed() async {
    try {
      await BLEdevice!.connectAndUpdateStream();
    } catch (e) {
      print("Connect Error");
    }
  }

  Future onDisconnectPressed() async {
    try {
      await BLEdevice!.disconnectAndUpdateStream();
      BLEdevice = BluetoothDevice(remoteId: const DeviceIdentifier('00:00:00:00:00:00'));
      MaterialPageRoute route = MaterialPageRoute(
      builder: (context) => HomeScreen(), settings: const RouteSettings(name: '/ScanScreen'));
      Navigator.of(context).push(route);
    } catch (e) {
      print("Disconnect Error");
    }
  }

  Future getServices() async { 

    try {
      services = await BLEdevice!.discoverServices();
    } catch (e) {
      print('Error: service discovery failed');

    }
  }

  Widget buildCustomCard(BuildContext context, Icon icon, String text, double valueBLE, [Widget? destinationScreen]) // build custom card avec data
  {
    Size size =  MediaQuery.of(context).size; 
    return FutureBuilder<void>(
      future: getServices(),
      builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
        if (snapshot.hasError)
        {
          return Text('Error line 166 home: ${snapshot.error}');
        }
        else
        {
          BluetoothCharacteristic? firstCharacteristic;
          if (services.isNotEmpty && services[0].characteristics.isNotEmpty) {
            firstCharacteristic = services[0].characteristics[0];
            BluetoothUtil.readCharacteristic(firstCharacteristic,() => mounted? {setState(() {})}:null);  
          }
          return firstCharacteristic != null
              ? CustomCard(
                size: size,
                title: text,
                icon: icon,
                valueBLE: valueBLE,
                destinationScreen:destinationScreen 
              )
              : CustomCard(
                size: size,
                title: text,
                icon: icon, 
                valueBLE: valueBLE,
              );
        }
      }
    );
  }
   
  Widget buildCustomCardSelect(BuildContext context,Icon icon, String title, Color color, bool state, Function() onToggle) //build customCard avec bouton 
  { 
    Size size =  MediaQuery.of(context).size; 
    return FutureBuilder<void>(
      future: getServices(),
      builder: (BuildContext context, AsyncSnapshot<void> snapshot) {

        if (snapshot.connectionState == ConnectionState.waiting)
        {
          return CustomCardSelect(
                size: size,
                title: title,
                icon: icon,
                color: color,
                state: state,
                onToggle: onToggle,
              );
        }
        else if (snapshot.hasError)
        {
          return Text('Error: ${snapshot.error}');
        }
        else
        {
          BluetoothCharacteristic? writeCharacteristic;
          if (services.isNotEmpty && services[0].characteristics.isNotEmpty) {
            writeCharacteristic = services[0].characteristics[1];
          }
          return writeCharacteristic != null
              ? CustomCardSelect(
                size: size,
                title: title,
                icon: icon,
                color: color,
                state: state,
                onToggle: onToggle,
                characteristic: writeCharacteristic
              ):CustomCardSelect(
                size: size,
                title: title,
                icon: icon,
                color: color,
                state: state,
                onToggle: onToggle,
              );
        }
      }
    );
  }

  @override
  Widget build(BuildContext context, ) {
    Size size =  MediaQuery.of(context).size; //Size(400, 400);// !!!! ???
    return  Scaffold(

      backgroundColor: WhiteColor,
      body: SafeArea(

        child: SingleChildScrollView(
          child: Padding(
            padding: EdgeInsets.symmetric(horizontal: size.width * 0.01),
            child: Column(
              children: [
                Container(
                  alignment: Alignment.centerLeft,
                  padding: EdgeInsets.only(left: size.width * 0.01),
                  child: Text(
                    "Data ",
                    style: TextStyle(fontSize: 23, fontWeight: FontWeight.bold, color: Color.fromARGB(255, 0, 0, 0)),
                  ),
                ),
                SizedBox(height: size.height * 0.02),
                Container(
                  padding: EdgeInsets.only(left: size.width * 0.02),
                height: size.height * 0.20,
                child: ListView(
                  clipBehavior: Clip.none,
                  scrollDirection: Axis.horizontal,
                  children:[
                    buildCustomCard(context, Icon(Icons.thermostat, size: 99 ,color: Colors.grey.shade400), "Température",currentTemp ,temperatureScreen()),
                    SizedBox(width: size.width * 0.05),
                    buildCustomCard(context, Icon(Icons.bubble_chart_outlined, size :55,color: Colors.grey.shade400), "TDS",currentTDS.toDouble()),
                    SizedBox(width: size.width * 0.05),
                    buildCustomCard(context, Icon(Icons.science_outlined, size: 99 ,color: Colors.grey.shade400), "PH",currentPH),
                    SizedBox(width: size.width * 0.05),
                    ]
                  ),
                ),
                Padding(padding: EdgeInsets.only(bottom: size.width * 0.05)),
                Container(
                  alignment: Alignment.centerLeft,
                  padding: EdgeInsets.only(left: size.width * 0.01),
                  child: const Text(
                    "Action ",
                    style: TextStyle(fontSize: 23, fontWeight: FontWeight.bold, color: Color.fromARGB(255, 0, 0, 0),),
                    
                  ),
                ),
                SizedBox(height: size.height * 0.02),
              //  buildCustomCardSelect(context, const Icon(Icons.water_drop_outlined) ,"Pompe à air", Colors.blue.shade400),
                Padding(padding: EdgeInsets.only(bottom: size.width * 0.05)),
                buildCustomCardSelect(context, const Icon(Icons.light_mode) ,"Lumière", Colors.yellow.shade400, light, () => setState(() {light = !light;})),
                Padding(padding: EdgeInsets.only(bottom: size.width * 0.07  )),
              ]
            ),
          )
        )
      ),
    );
  }
}


这是我的读写功能:

import 'dart:convert';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:fishbotica/constants/data.dart';

class BluetoothUtil {
  
  static Future<void> writeCharacteristic(
   //< BluetoothCharacteristic? characteristic,
  ) async {
    try {
      await services[0].characteristics[1].write(
        jsonToByte(),
        withoutResponse: services[0].characteristics[1].properties.writeWithoutResponse,
      );
    } catch (e) {
      print('error write ble : $e');
    }
  }

  static List<int>  jsonToByte() {
    String jsonData = 
    json.encode(
      {
        "regulationTemp" :1// regulationTemp,
       // "forceTemp" : forceTemp ? 1 : 0,
       // "light" : setLight ? 1: 0,
      }
    );

    List<int> dataByte = utf8.encode(jsonData);

    return dataByte;
  }


  static Future<void> readCharacteristic(BluetoothCharacteristic characteristic, Function() onToggle) async {
    String characteristicValue = "999";
    double doubleValue = 999;
    try {

      final List<int> value = await characteristic.read();
      print(value.toString());
      // Convertir les données de la caractéristique en chaîne
      String jsonString = String.fromCharCodes(value );

      Map<String, dynamic> jsonData = json.decode(jsonString);

      currentTemp = double.parse(jsonData["temp"]);
      currentPH = jsonData["pH"];
      currentTDS = jsonData["TDS"];
      
      onToggle();

    } catch (e) {
      print('Erreur lors de la lecture de la caractéristique : $e');
    }

  }  

}

这是我管理写入并在主页上启动的小部件:

class CustomCardSelect extends StatefulWidget {
  Size size;
  String title;
  Icon icon;
  Color color;
  bool state;
  Function() onToggle;
  BluetoothCharacteristic? characteristic;

  CustomCardSelect(
  {super.key, 
    required this.size, 
    required this.title,
    required this.icon,
    required this.color,
    required this.state,
    required this.onToggle,
    this.characteristic,
  });

  @override
  State<CustomCardSelect> createState() => _CustomCardSelectState();
}

class _CustomCardSelectState extends State<CustomCardSelect> 
  with SingleTickerProviderStateMixin {
  // BLE
  late bool isChecked;
  //bool temp = false;
  BluetoothCharacteristic? get c => widget.characteristic;

  @override
  void initState() {
    super.initState();
    isChecked = widget.state;
  }
  
  @override
  void dispose() {
    super.dispose();
  }

  void setIconColor() {
    setState(() {
      if (!isChecked) {
        widget.icon = Icon(widget.icon.icon, size: 35, color: Colors.grey.shade400);
      } else {
        widget.icon = Icon(widget.icon.icon, size: 35, color: widget.color);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return 
    Container(
      height: widget.size.height * 0.14,
      width: widget.size.width * 0.9,
      decoration: BoxDecoration(
        color: KCustomCard,
        borderRadius: BorderRadius.circular(20),
        border: Border.all(color: Colors.grey.shade400),
        boxShadow: const [
          BoxShadow(
            color: Colors.black12,
            offset: Offset(3, 3),
            blurRadius: 8,
          ),
          BoxShadow(
            color: Colors.white,
            offset: Offset(-3, -3),
            blurRadius: 8,
          ),
        ],
      ),
      child: Padding(
        padding: EdgeInsets.all(15),
        child:Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: 
              [
                Icon(widget.icon.icon, color: Colors.black, size: 35), 
                Padding(padding: EdgeInsets.only(left: 15)),
                Text(widget.title, style: const TextStyle(fontSize: 19, fontWeight: FontWeight.bold, color: kBlueColor)) ,
              ]
            ),
            Transform.scale(
              scale: 1.1,
              child: CupertinoSwitch(
                value: isChecked, 
                onChanged: (isChecked) async { 
                  this.isChecked = isChecked;
                    setState(() {
                      if (isChecked) {
                        setIconColor();
                      } else {
                        setIconColor();
                      }
                    });
                    
                    await BluetoothUtil.writeCharacteristic();
                    widget.onToggle();
                  }
              )
            ),
          ]
        ),
      )
    );
  }
}

我还没有找到任何人谈论这个问题。 预先感谢您的回复;)

flutter dart bluetooth-lowenergy flutter-dependencies esp32
1个回答
0
投票

我想建议,为了避免等待蓝色被读取,您可以将蓝色读取条目保存在列表中,并在写入 json 文件之前监听此列表中的更改。

© www.soinside.com 2019 - 2024. All rights reserved.