You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:使用Flutter Blue Plus获取BLE体重秤数据并转Double

Problem

I need to get the precise weight in grams from a BLE scale using the Flutter Blue Plus package when pressing a button that calls the getWeight function. This function should receive the data sent by the scale and return a double value representing the weight in grams. However, I'm unable to assign the data sent by the scale to a list and convert the corresponding bytes to the weight value. I've tried enabling characteristic subscription and assigning the sent values to an int list, but it didn't work.

Log Output

Weight 335.0 grams
flutter: [FBP] [[ OnCharacteristicReceived ]] result: {remote_id: D5522E08-AAA5-292F-1ADF-6207EF692C2A, secondary_service_uuid: null, characteristic_uuid: fff1, success: 1, value: 1012004101020501f80d167e1f0258020181, error_code: 0, service_uuid: fff0, error_string: success}
Weight 0.0 grams
flutter: [FBP] [[ OnCharacteristicReceived ]] result: {remote_id: D5522E08-AAA5-292F-1ADF-6207EF692C2A, secondary_service_uuid: null, characteristic_uuid: fff1, success: 1, value: 1012004101020501f900007e1f025802015f, error_code: 0, service_uuid: fff0, error_string: success}

Current Code

// ignore_for_file: unused_import

import 'dart:async';
import 'dart:ffi';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

class ReadData extends StatefulWidget {
  const ReadData({Key? key}) : super(key: key);

  @override
  State<ReadData> createState() => _ReadDataState();
}

class _ReadDataState extends State<ReadData> {
  String weightRemoteID = 'D5522E08-AAA5-292F-1ADF-6207EF692C2A';
  String weightServiceID = 'FFF0';
  String weightCharacterisicsID = 'FFF1';
  List<int> weightReceivedValue = [];
  double weightValue = 0;

  @override
  void initState() {
    _wait();
    _startScanning();
    _listenScanResult();
    super.initState();
  }

  void _wait() async {
    await FlutterBluePlus.adapterState
        .where((state) => state == BluetoothAdapterState.on)
        .first;
  }

  void _startScanning() {
    FlutterBluePlus.startScan(timeout: const Duration(seconds: 2));
  }

  void _listenScanResult() {
    FlutterBluePlus.setLogLevel(LogLevel.verbose, color: false);
    FlutterBluePlus.scanResults.listen((scanList) async {
      for (ScanResult result in scanList) {
        if (result.device.remoteId.toString() == weightRemoteID) {
          result.device.connect(autoConnect: true);
          List<BluetoothService> services =
              await result.device.discoverServices();
          services.forEach((service) async {
            var characteristics = service.characteristics;
            for (BluetoothCharacteristic c in characteristics) {
              await c.setNotifyValue(true);
              weightReceivedValue = await c.read();
              setState(() {
              });
            }
          });
        }
      }
    });
  }

  double getWeight(List<int> weightReceivedValue) {
    // to code

    return weightValue;
  }

  Widget buildButton(BuildContext context) {
    // to code

    return const FloatingActionButton(onPressed: null);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: SizedBox(
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text("Weight"),
            const SizedBox(height: 16.0),
            Text("$getWeight g"),
          ],
        ),
      ),
    );
  }
}

Solution

1. Fix Characteristic Subscription & Data Listening

Your code uses c.read() which only fetches a single snapshot of the characteristic value. To receive continuous updates from the scale, listen to the characteristic's value stream instead. Also, filter for the specific service and characteristic UUIDs to avoid unnecessary iterations:

void _listenScanResult() {
  FlutterBluePlus.setLogLevel(LogLevel.verbose, color: false);
  FlutterBluePlus.scanResults.listen((scanList) async {
    for (ScanResult result in scanList) {
      if (result.device.remoteId.toString() == weightRemoteID) {
        // Avoid re-connecting if already connected
        if (result.device.connectionState != BluetoothConnectionState.connected) {
          await result.device.connect(autoConnect: true);
        }
        List<BluetoothService> services = await result.device.discoverServices();
        for (var service in services) {
          if (service.uuid.toString().toLowerCase() == weightServiceID.toLowerCase()) {
            for (BluetoothCharacteristic c in service.characteristics) {
              if (c.uuid.toString().toLowerCase() == weightCharacterisicsID.toLowerCase()) {
                await c.setNotifyValue(true);
                // Listen to the value stream for real-time updates
                c.value.listen((value) {
                  setState(() {
                    weightReceivedValue = value;
                    weightValue = getWeight(value);
                  });
                });
              }
            }
          }
        }
      }
    }
  });
}

2. Parse BLE Data to Grams

Based on your log output, the weight data is stored in bytes 9 and 10 (0x0D and 0x16 for 335.0g, 0x00 and 0x00 for 0.0g). Combine these bytes into a raw integer and divide by 10 to get the final weight:

double getWeight(List<int> weightReceivedValue) {
  // Ensure there are enough data bytes to parse
  if (weightReceivedValue.length < 11) return 0.0;
  
  // Combine bytes 9 and 10 into a single integer (big-endian)
  int weightRaw = (weightReceivedValue[10] << 8) | weightReceivedValue[9];
  // Convert to grams (raw value is multiplied by 10)
  return weightRaw / 10.0;
}

3. Fix UI and Button Functionality

Update the button to trigger UI refreshes, and fix the weight display to show the parsed value:

Widget buildButton(BuildContext context) {
  return FloatingActionButton(
    onPressed: () {
      // Force UI refresh (subscription handles real-time updates, this is a fallback)
      setState(() {});
    },
    child: const Icon(Icons.refresh),
  );
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text("BLE Weight Scale")),
    body: SizedBox(
      width: double.infinity,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("Weight"),
          const SizedBox(height: 16.0),
          Text("${weightValue.toStringAsFixed(1)} g"),
        ],
      ),
    ),
    floatingActionButton: buildButton(context),
  );
}

4. Additional Improvements

  • Add error handling with try/catch blocks around connect() and discoverServices() to handle Bluetooth connection failures.
  • Listen to the device's connectionState stream to handle disconnections automatically.
  • Stop scanning once the target device is found to save battery.

内容的提问来源于stack exchange,提问作者mknnnnnnn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:07:08