I tried several ways to complete the app functionality but i can't and im frustrated.
The device (being specific because the weight measurement device and the body composition monitor have different types of connection methods) is OMRON HBF-222T
Basically when you start using the device you press the bluetooth button and the device starts on "P" mode so you can start sending the connection things to receive the weight, imc, etc.
By the documentation the connection must be
Connection Established <-- this is easy because you just need search for the BLE devices and that things
The problems starts here because some of the characteristics are not readed or found so the connection cannot continue, and the characteristics and the services are the same, that doesn't change because it is a standard for bluetooth:
- Read Characteristic (Device Information)
- Read Characteristic (Weight Scale Feature)
- Write CCCD (Current Time)
- Write CCCD (Battery Level)
- Write CCCD (User Control Point)
- Write CCCD (Database Change Increment)
- Write CCCD (Record Access Control Point)
- Write CCCD (OMRON Measurement(BC))
- Read Descripter (Presentation Format)
- Write Characteristic (User Control Point:Register New User With User Index)
- Indication (User Control Point:Register New User With User Index Response)
- Write Characteristic (User Control Point:Consent)
- Indication (User Control Point:Consent Response)
- Notification (Current Time)
- Write Characteristic (Current Time)
- Notification (Battery Level)
- Notification (Database Change Increment)
- Write Characteristic (Database Change Increment)
- Write Characteristic (Record Access Control Point:- ReportNumberOfStoredRecoeds)
- Indication (Record Access Control Point:ReportNumberOfStoredRecoeds Response)
- Write Characteristic (Record Access Control Point:ReportStoredRecord)
- Indication (OMRON Measurement(BCM) part1)
- Indication (OMRON Measurement(BCM) part2)
- Indication (Record Access Control Point:ReportStoredRecord Response)
- Write Characteristic (Record Access Control Point:ReportSequenceNumberOfLatestRecord)
- Indication (Record Access Control Point: ReportSequenceNumberOfLatestRecord Response)
- Disconnect
My code it is:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:permission_handler/permission_handler.dart';
import 'upload_method_page.dart';
import 'dart:async';
class BluetoothScreen extends StatefulWidget {
final DeviceModel bluetoothModel;
const BluetoothScreen({Key? key, required this.bluetoothModel}) : super(key: key);
@override
_BluetoothScreenState createState() => _BluetoothScreenState();
}
class _BluetoothScreenState extends State<BluetoothScreen> {
final _ble = FlutterReactiveBle();
List<DiscoveredDevice> _foundDevices = [];
List<StreamSubscription<List<int>>> _characteristicSubscriptions = [];
Set<String> _connectedDevicesIds = Set<String>();
List<DiscoveredService> _discoveredServices = [];
late StreamSubscription<ConnectionStateUpdate> _connection;
Map<String, dynamic> characteristicValues = {};
@override
void initState() {
super.initState();
requestBluetoothPermissions();
_startScan();
}
Future<void> requestBluetoothPermissions() async {
final status = await Permission.location.request();
PermissionStatus bluetoothScanStatus = PermissionStatus.denied;
PermissionStatus bluetoothConnectStatus = PermissionStatus.denied;
if (Platform.isAndroid) {
if (await Permission.bluetooth.isDenied || await Permission.location.isDenied) {
bluetoothScanStatus = await Permission.bluetoothScan.request();
bluetoothConnectStatus = await Permission.bluetoothConnect.request();
if (bluetoothScanStatus == PermissionStatus.granted && bluetoothConnectStatus == PermissionStatus.granted) {
print("Bluetooth scan and connect permissions granted");
} else {
print("Bluetooth scan or connect permissions denied");
}
}
}
if (status == PermissionStatus.granted && bluetoothScanStatus == PermissionStatus.granted && bluetoothConnectStatus == PermissionStatus.granted) {
print("All necessary permissions granted");
} else {
print("Some permissions are denied");
}
}
final Map<String, String> _bluetoothServicesNames = {
'00001800-0000-1000-8000-00805f9b34fb': 'Generic Access',
'00001801-0000-1000-8000-00805f9b34fb': 'Generic Attribute',
'0000180a-0000-1000-8000-00805f9b34fb': 'Device Information',
'0000181d-0000-1000-8000-00805f9b34fb': 'Weight Scale',
'0000181b-0000-1000-8000-00805f9b34fb': 'Body Composition',
};
final Map<String, String> _bluetoothCharacteristicNames = {
'00002a9e-0000-1000-8000-00805f9b34fb': 'Capacidades báscula peso',
'00002a9d-0000-1000-8000-00805f9b34fb': 'Medicion de peso',
'00002a9c-0000-1000-8000-00805f9b34fb': 'Medición de composición corporal',
'00002a9b-0000-1000-8000-00805f9b34fb': 'Capacidades báscula composición corporal',
};
String getCharacteristicName(String uuid) {
return _bluetoothCharacteristicNames[uuid] ?? 'Unknown Characteristic ($uuid)';
}
void _startScan() {
_ble.scanForDevices(withServices: []).listen((device) {
if (!_foundDevices.any((existingDevice) => existingDevice.id == device.id) && device.name.startsWith('BLE')) {
setState(() {
_foundDevices.add(device);
});
}
});
}
Future<void> readStoredData(DiscoveredDevice device) async {
final characteristicUuid = Uuid.parse("00002a9c-0000-1000-8000-00805f9b34fb");
final commandToReadStoredData = [0x02];
try {
await _ble.writeCharacteristicWithResponse(
QualifiedCharacteristic(
serviceId: Uuid.parse("0000180f-0000-1000-8000-00805f9b34fb"),
characteristicId: characteristicUuid,
deviceId: device.id,
),
value: commandToReadStoredData,
);
print("It works the command to save.");
} catch (e) {
print("Error sending the command: $e");
}
}
Future<void> connectToDevice(DiscoveredDevice device) async {
print("Starting connection with the device: ${device.id}");
final connectionStream = _ble.connectToDevice(
id: device.id,
connectionTimeout: const Duration(seconds: 10),
);
_connection = connectionStream.listen(
(connectionState) async {
print("Actual connection status: ${connectionState.connectionState}");
if (connectionState.connectionState == DeviceConnectionState.connected) {
print("Connected device: ${device.id}");
// Discovering services
final services = await _ble.discoverServices(device.id);
print("Services discovered: ${services.length}");
print("List of services: ${services.map((service) => service.serviceId)}");
setState(() {
_connectedDevicesIds.add(device.id);
_discoveredServices = services; // Storing discovered services
});
await readStoredData(device);
// Subscribing to characteristics
for (var service in services) {
for (var characteristic in service.characteristics) {
final qualifiedCharacteristic = QualifiedCharacteristic(
serviceId: characteristic.serviceId,
characteristicId: characteristic.characteristicId,
deviceId: device.id,
);
final characteristicSubscription = _ble.subscribeToCharacteristic(qualifiedCharacteristic).listen(
(data) {
setState(() {
characteristicValues[characteristic.characteristicId.toString()] = data;
});
print("Received data from ${characteristic.characteristicId}: $data");
},
onError: (dynamic error) {
print("Error subscribing to the characteristic: $error");
},
);
_characteristicSubscriptions.add(characteristicSubscription);
}
}
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Success connection"),
content: Text("Success connection with the device ${widget.bluetoothModel.name}"),
actions: <Widget>[
TextButton(
child: Text("OK"),
onPressed: () => Navigator.of(context).pop(),
),
],
);
},
);
}
},
onError: (error) {
print("Error during the connection: $error");
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Buscando ${widget.bluetoothModel.name}'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
"Please pick your device in the list",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
Expanded(
child: ListView.builder(
itemCount: _foundDevices.length,
itemBuilder: (context, index) {
final device = _foundDevices[index];
bool isConnected = _connectedDevicesIds.contains(device.id);
return ListTile(
leading: isConnected ? Icon(Icons.circle, color: Colors.green) : null,
title: Text(widget.bluetoothModel.name),
subtitle: Text(device.id),
onTap: () => connectToDevice(device),
);
},
),
),
if (_discoveredServices.isNotEmpty) ...[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
"Services",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
textAlign: TextAlign.left,
),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: _discoveredServices.length,
itemBuilder: (context, index) {
final service = _discoveredServices[index];
String serviceName = _bluetoothServicesNames[service.serviceId.toString()] ?? service.serviceId.toString();
return ExpansionTile(
title: Text("Service: $serviceName"),
children: service.characteristicIds.map((characteristic) {
String characteristicName = getCharacteristicName(characteristic.toString());
dynamic value = characteristicValues[characteristic.toString()];
String valueString = value != null ? value.toString() : "No data";
return ListTile(
title: Text("$characteristicName: $valueString"),
);
}).toList(),
);
},
),
),
],
],
),
);
}
@override
void dispose() {
_connection?.cancel();
_characteristicSubscriptions.forEach((subscription) {
subscription.cancel();
});
super.dispose();
}
}
I tried read all the services and all the characteristics to search the required but i have no good results, if someone know any other thing to try for this app it must be good received please