Reputation: 1
I'm trying to build an IoT app with Flutter and then control the IoT devices using a Bluetooth Serial Connection. I'm using the flutter_bluetooth_serial plugin and the HC-05 Bluetooth module for the IoT devices. Everything works but I'm unable to establish a connection with the HC-05. When I tap the "connect" button, nothing literally happens.
For all the tutorials I watched, version ^0.2.2 of the flutter_bluetooth_serial and it worked well for them. The current version is ^0.4.0. I changed to the previous version I saw in the tutorial but the problem still persists. I was expecting the connection to be established after this but didn't unfortunately.
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class ChatPage extends StatefulWidget {
final BluetoothDevice server;
const ChatPage({required this.server});
@override
_ChatPage createState() => new _ChatPage();
}
class _Message {
int whom;
String text;
_Message(this.whom, this.text);
}
class _ChatPage extends State<ChatPage> {
static final clientID = 0;
BluetoothConnection? connection = null;
List<_Message> messages = <_Message>[];
String _messageBuffer = '';
final TextEditingController textEditingController =
new TextEditingController();
final ScrollController listScrollController = new ScrollController();
bool isConnecting = true;
bool get isConnected => connection != null && connection!.isConnected;
bool isDisconnecting = false;
@override
void initState() {
super.initState();
BluetoothConnection.toAddress(widget.server.address)
.then((_connection) {
print('Connected to the device');
connection = _connection;
setState(() {
isConnecting = false;
isDisconnecting = false;
});
connection!.input.listen(_onDataReceived).onDone(() {
// Example: Detect which side closed the connection
// There should be `isDisconnecting` flag to show are we are (locally)
// in middle of disconnecting process, should be set before calling
// `dispose`, `finish` or `close`, which all causes to disconnect.
// If we except the disconnection, `onDone` should be fired as result.
// If we didn't except this (no flag set), it means closing by remote.
if (isDisconnecting) {
print('Disconnecting locally!');
} else {
print('Disconnected remotely!');
}
if (this.mounted) {
setState(() {});
}
});
}).catchError((error) {
print('Cannot connect, exception occured');
print(error);
});
}
@override
void dispose() {
// Avoid memory leak (`setState` after dispose) and disconnect
if (isConnected) {
isDisconnecting = true;
connection!.dispose();
connection = null!;
}
super.dispose();
}
double _value = 90.0;
@override
Widget build(BuildContext context) {
final List<Row> list = messages.map((_message) {
return Row(
children: <Widget>[
Container(
child: Text(
(text) {
return text == '/shrug' ? '¯\\_(ツ)_/¯' : text;
}(_message.text.trim()),
style: TextStyle(color: Colors.white)),
padding: EdgeInsets.all(12.0),
margin: EdgeInsets.only(bottom: 8.0, left: 8.0, right: 8.0),
width: 222.0,
decoration: BoxDecoration(
color:
_message.whom == clientID ? Colors.blueAccent : Colors.grey,
borderRadius: BorderRadius.circular(7.0)),
),
],
mainAxisAlignment: _message.whom == clientID
? MainAxisAlignment.end
: MainAxisAlignment.start,
);
}).toList();
return Scaffold(
appBar: AppBar(
title: (isConnecting
? Text('Connecting chat to ' + widget.server.name + '...')
: isConnected
? Text('Live chat with ' + widget.server.name)
: Text('Chat log with ' + widget.server.name))),
body: SafeArea(
child: Column(
children: <Widget>[
Flexible(
child: ListView(
padding: const EdgeInsets.all(12.0),
controller: listScrollController,
children: list),
),
Row(
children: <Widget>[
Flexible(
child: Container(
margin: const EdgeInsets.only(left: 16.0),
child: TextField(
style: const TextStyle(fontSize: 15.0),
controller: textEditingController,
decoration: InputDecoration.collapsed(
hintText: isConnecting
? 'Wait until connected...'
: isConnected
? 'Type your message...'
: 'Chat got disconnected',
hintStyle: const TextStyle(color: Colors.grey),
),
enabled: isConnected,
),
),
),
Container(
margin: const EdgeInsets.all(8.0),
child: IconButton(
icon: const Icon(Icons.send),
onPressed: isConnected
? () => _sendMessage(textEditingController.text)
: null),
),
],
)
],
),
),
);
}
void _onDataReceived(Uint8List data) {
// Allocate buffer for parsed data
int backspacesCounter = 0;
data.forEach((byte) {
if (byte == 8 || byte == 127) {
backspacesCounter++;
}
});
Uint8List buffer = Uint8List(data.length - backspacesCounter);
int bufferIndex = buffer.length;
// Apply backspace control character
backspacesCounter = 0;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i] == 8 || data[i] == 127) {
backspacesCounter++;
} else {
if (backspacesCounter > 0) {
backspacesCounter--;
} else {
buffer[--bufferIndex] = data[i];
}
}
}
// Create message if there is new line character
String dataString = String.fromCharCodes(buffer);
int index = buffer.indexOf(13);
if (~index != 0) {
setState(() {
messages.add(
_Message(
1,
backspacesCounter > 0
? _messageBuffer.substring(
0, _messageBuffer.length - backspacesCounter)
: _messageBuffer + dataString.substring(0, index),
),
);
_messageBuffer = dataString.substring(index);
});
} else {
_messageBuffer = (backspacesCounter > 0
? _messageBuffer.substring(
0, _messageBuffer.length - backspacesCounter)
: _messageBuffer + dataString);
}
}
void _sendMessage(String text) async {
text = text.trim();
textEditingController.clear();
if (text.length > 0) {
try {
connection!.output.add(Uint8List.fromList(utf8.encode(text + "\r\n")));
await connection!.output.allSent;
setState(() {
messages.add(_Message(clientID, text));
});
Future.delayed(Duration(milliseconds: 333)).then((_) {
listScrollController.animateTo(
listScrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 333),
curve: Curves.easeOut);
});
} catch (e) {
// Ignore error, but notify state
setState(() {});
}
}
}
}
Upvotes: 0
Views: 642
Reputation: 1
Can you tell where is the exact problem or you can try this code below 👇
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class ChatPage extends StatefulWidget {
final BluetoothDevice server;
const ChatPage({required this.server});
@override
_ChatPage createState() => new _ChatPage();
}
class _Message {
int whom;
String text;
_Message(this.whom, this.text);
}
class _ChatPage extends State<ChatPage> {
static final clientID = 0;
BluetoothConnection? connection;
List<_Message> messages = List<_Message>.empty(growable: true);
String _messageBuffer = '';
final TextEditingController textEditingController =
new TextEditingController();
final ScrollController listScrollController = new ScrollController();
bool isConnecting = true;
bool get isConnected => (connection?.isConnected ?? false);
bool isDisconnecting = false;
@override
void initState() {
super.initState();
BluetoothConnection.toAddress(widget.server.address).then((_connection) {
print('Connected to the device');
connection = _connection;
setState(() {
isConnecting = false;
isDisconnecting = false;
});
connection!.input!.listen(_onDataReceived).onDone(() {
// Example: Detect which side closed the connection
// There should be `isDisconnecting` flag to show are we are (locally)
// in middle of disconnecting process, should be set before calling
// `dispose`, `finish` or `close`, which all causes to disconnect.
// If we except the disconnection, `onDone` should be fired as result.
// If we didn't except this (no flag set), it means closing by remote.
if (isDisconnecting) {
print('Disconnecting locally!');
} else {
print('Disconnected remotely!');
}
if (this.mounted) {
setState(() {});
}
});
}).catchError((error) {
print('Cannot connect, exception occured');
print(error);
});
}
@override
void dispose() {
// Avoid memory leak (`setState` after dispose) and disconnect
if (isConnected) {
isDisconnecting = true;
connection?.dispose();
connection = null;
}
super.dispose();
}
@override
Widget build(BuildContext context) {
final List<Row> list = messages.map((_message) {
return Row(
children: <Widget>[
Container(
child: Text(
(text) {
return text == '/shrug' ? '¯\\_(ツ)_/¯' : text;
}(_message.text.trim()),
style: TextStyle(color: Colors.white)),
padding: EdgeInsets.all(12.0),
margin: EdgeInsets.only(bottom: 8.0, left: 8.0, right: 8.0),
width: 222.0,
decoration: BoxDecoration(
color:
_message.whom == clientID ? Colors.blueAccent : Colors.grey,
borderRadius: BorderRadius.circular(7.0)),
),
],
mainAxisAlignment: _message.whom == clientID
? MainAxisAlignment.end
: MainAxisAlignment.start,
);
}).toList();
final serverName = widget.server.name ?? "Unknown";
return Scaffold(
appBar: AppBar(
title: (isConnecting
? Text('Connecting chat to ' + serverName + '...')
: isConnected
? Text('Live chat with ' + serverName)
: Text('Chat log with ' + serverName))),
body: SafeArea(
child: Column(
children: <Widget>[
Flexible(
child: ListView(
padding: const EdgeInsets.all(12.0),
controller: listScrollController,
children: list),
),
Row(
children: <Widget>[
Flexible(
child: Container(
margin: const EdgeInsets.only(left: 16.0),
child: TextField(
style: const TextStyle(fontSize: 15.0),
controller: textEditingController,
decoration: InputDecoration.collapsed(
hintText: isConnecting
? 'Wait until connected...'
: isConnected
? 'Type your message...'
: 'Chat got disconnected',
hintStyle: const TextStyle(color: Colors.grey),
),
enabled: isConnected,
),
),
),
Container(
margin: const EdgeInsets.all(8.0),
child: IconButton(
icon: const Icon(Icons.send),
onPressed: isConnected
? () => _sendMessage(textEditingController.text)
: null),
),
],
)
],
),
),
);
}
void _onDataReceived(Uint8List data) {
// Allocate buffer for parsed data
int backspacesCounter = 0;
data.forEach((byte) {
if (byte == 8 || byte == 127) {
backspacesCounter++;
}
});
Uint8List buffer = Uint8List(data.length - backspacesCounter);
int bufferIndex = buffer.length;
// Apply backspace control character
backspacesCounter = 0;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i] == 8 || data[i] == 127) {
backspacesCounter++;
} else {
if (backspacesCounter > 0) {
backspacesCounter--;
} else {
buffer[--bufferIndex] = data[i];
}
}
}
// Create message if there is new line character
String dataString = String.fromCharCodes(buffer);
int index = buffer.indexOf(13);
if (~index != 0) {
setState(() {
messages.add(
_Message(
1,
backspacesCounter > 0
? _messageBuffer.substring(
0, _messageBuffer.length - backspacesCounter)
: _messageBuffer + dataString.substring(0, index),
),
);
_messageBuffer = dataString.substring(index);
});
} else {
_messageBuffer = (backspacesCounter > 0
? _messageBuffer.substring(
0, _messageBuffer.length - backspacesCounter)
: _messageBuffer + dataString);
}
}
void _sendMessage(String text) async {
text = text.trim();
textEditingController.clear();
if (text.length > 0) {
try {
connection!.output.add(Uint8List.fromList(utf8.encode(text + "\r\n")));
await connection!.output.allSent;
setState(() {
messages.add(_Message(clientID, text));
});
Future.delayed(Duration(milliseconds: 333)).then((_) {
listScrollController.animateTo(
listScrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 333),
curve: Curves.easeOut);
});
} catch (e) {
// Ignore error, but notify state
setState(() {});
}
}
}
}
Or you can refer my source code which I have recently created
https://github.com/Churanta/NERU
Upvotes: 0