flutter mqtt
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mqtt_client/mqtt_client.dart';
import 'audio.dart';
import 'mqtt/client.dart';
import 'mqtt/message.dart';
import 'dialog.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Car Controller',
debugShowCheckedModeBanner: false, // 不显示debug标签
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Car Controller'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
var speed = 0;
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
// TODO: implement initState
super.initState();
Myclient.connect();
Myclient.mqttclient.updates //收信,更新mqtt信息
.listen((List<MqttReceivedMessage<MqttMessage>> c) {
final MqttPublishMessage recMess = c[0].payload;
final String pt =
MqttPublishPayload.bytesToStringAsString(recMess.payload.message);
print(
'EXAMPLE::Change notifification:: topic is <${c[0].topic}>, payload is <-- $pt -->');
setState(() {
messages.add(new Message(c[0].topic, pt, MqttQos.atMostOnce));
});
try {
subMsgScrollController.animateTo(
//滚动
0.0,
duration: Duration(milliseconds: 400),
curve: Curves.easeOut,
);
} catch (_) {}
});
}
@override
void dispose() {
//
//为了避免内存泄露,需要调⽤subMsgScrollController.dispose
super.dispose();
subMsgScrollController.dispose();
}
// Widget btnAudioPage(){
// return btnBeautifulTeal(onPressed: () {
// Navigator.push(context, MaterialPageRoute(builder: (_){
// return new RecorderPage();
// }));
// },);
// }
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: <Widget>[
btnSubWithIcon(), //界面,sub按钮,sub信息的列表,方向盘
SubMsgList(),
colSpeed(),
steelingWheelWithBorder(),
],
),
));
}
Widget steelingWheelWithBorder(){
return Container(
width: 180,
child:(
steeringWheelWithIcon()
),
decoration: BoxDecoration(
// color: Colors.blue,
// borderRadius: BorderRadius.all(Radius.circular(250.0)),
border: new Border.all(width: 1, color: Colors.black),
shape: BoxShape.circle
),
);
}
//控制速度的几个按钮
Widget colSpeed() {
return Column(children: [
Text('speed'),
btnSpeed(1000),
btnSpeed(750),
btnSpeed(500),
btnSpeed(250),
btnSpeed(0),
]);
}
Widget btnSpeed(speed_in) {
return btnBeautifulTeal(
onPressed: () {
speed = speed_in;
},child: Text(speed_in.toString()),
);
}
//订阅的主题显示的表
Widget SubMsgList() {
return Expanded(
child: Container(
margin: EdgeInsets.all(15), //边缘,镶嵌inset
child: ListView(
scrollDirection: Axis.vertical, //轴
shrinkWrap: true,
controller: subMsgScrollController,
children: _buildSubList(),
),
));
}
Widget steeringWheelWithIcon() {
Widget rowForward() {
return Row(
mainAxisAlignment: MainAxisAlignment.center, //居中
children: <Widget>[
btnForwardWithIcon(),
],
);
}
Widget rowLeftBrakeRight() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
btnLeftWithIcon(),
btnBrakeWithIcon(),
btnRightWithIcon(),
],
);
}
Widget rowBack() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[btnBackWithIcon()],
);
}
return Column(
children: <Widget>[rowForward(), rowLeftBrakeRight(), rowBack()],
);
}
//小车的方向盘,在网上查不到方向盘布局的空间,只能自己写三个row,第一个row包含一个前进按钮
//第二行包含左,刹车,右按钮,第三行包括后退按钮
Widget steeringWheel() {
Widget rowForward() {
return Row(
mainAxisAlignment: MainAxisAlignment.center, //居中
children: <Widget>[
btnForward(),
],
);
}
Widget rowLeftBrakeRight() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
btnLeft(),
btnBrake(),
btnRight(),
],
);
}
Widget rowBack() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[btnBack()],
);
}
return Column(
children: <Widget>[rowForward(), rowLeftBrakeRight(), rowBack()],
);
}
//订阅的按钮,按了之后订阅主题,就可以接受esp32的信息了
//按了会弹出已经订阅的弹窗提醒
Widget btnSub() {
return btnBeautifulTeal(
child: Text('Sub'),
onPressed: () {
Myclient.subscribe('esp32mqp');
print('已经订阅');
showAlertDialog(context); //弹窗
},
);
}
void showAlertDialog(BuildContext context) {
showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
content: Text('已经订阅'),
title: Center(
child: Text(
'alertdialog',
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
fontWeight: FontWeight.bold),
)),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('确定')),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('取消')),
],
);
});
}
//前后左右的按钮,是圆形的,并且调节了大小
Widget btnForwardWithIcon(){
return SizedBox(
height: 50,
width: 50,
child: IconButton(
//child: Text('△'),
onPressed: () {
_pubMoveMsg('forward' + speed.toString());
print('forward ' + speed.toString());
},
// shape: CircleBorder(),
icon: Icon(Icons.arrow_drop_up),
));
}
Widget btnBackWithIcon(){
return SizedBox(
height: 50,
width: 50,
child: IconButton(
//child: Text('△'),
onPressed: () {
_pubMoveMsg('back' + speed.toString());
print('back ' + speed.toString());
},
// shape: CircleBorder(),
icon: Icon(Icons.arrow_drop_down),
));
}
Widget btnLeftWithIcon(){
return SizedBox(
height: 50,
width: 50,
child: IconButton(
//child: Text('△'),
onPressed: () {
_pubMoveMsg('left' + speed.toString());
print('left ' + speed.toString());
},
// shape: CircleBorder(),
icon: Icon(Icons.arrow_left),
));
}
Widget btnRightWithIcon(){
return SizedBox(
height: 50,
width: 50,
child: IconButton(
//child: Text('△'),
onPressed: () {
_pubMoveMsg('right' + speed.toString());
print('right ' + speed.toString());
},
// shape: CircleBorder(),
icon: Icon(Icons.arrow_right),
));
}
Widget btnBrakeWithIcon(){
return SizedBox(
height: 50,
width: 50,
child: IconButton(
//child: Text('△'),
onPressed: () {
_pubMoveMsg('brake' );
print('brake ' );
},
// shape: CircleBorder(),
icon: Icon(Icons.stop),
));
}
Widget btnSubWithIcon(){
return SizedBox(
height: 50,
width: 50,
child: IconButton(
//child: Text('△'),
onPressed: () {
Myclient.subscribe('esp32mqp');
print('sub');
showAlertDialog(context); //弹窗
},
// shape: CircleBorder(),
icon: Icon(Icons.subscriptions),
));
}
Widget btnForward() {
return SizedBox(
height: 50,
width: 50,
child: btnBeautifulTeal(
child: Text('△'),
onPressed: () {
_pubMoveMsg('forward' + speed.toString());
print('forward ' + speed.toString());
},
shape: CircleBorder(),
));
}
Widget btnBack() {
return SizedBox(
height: 50,
width: 50,
child: btnBeautifulTeal(
child: Text('▽'),
onPressed: () {
_pubMoveMsg('back' + speed.toString());
print('back ' + speed.toString());
},
shape: CircleBorder(),
));
}
Widget btnLeft() {
return SizedBox(
height: 50,
width: 50,
child: btnBeautifulTeal(
child: Text('◁'),
onPressed: () {
_pubMoveMsg('left' + speed.toString());
print('left ' + speed.toString());
},
shape: CircleBorder(),
));
}
Widget btnRight() {
return SizedBox(
height: 50,
width: 50,
child: btnBeautifulTeal(
child: Text('▷'),
onPressed: () {
_pubMoveMsg('right' + speed.toString());
print('right ' + speed.toString());
},
shape: CircleBorder(),
));
}
Widget btnBrake() {
return SizedBox(
height: 50,
width: 50,
child: btnBeautifulTeal(
child: Text('✖'),
onPressed: () {
_pubMoveMsg('brake');
print('brake');
},
shape: CircleBorder(),
));
}
//接收信息的list
List<Widget> _buildSubList() {
return messages
.map((Message message) => Container(
padding: EdgeInsets.all(5),
margin: EdgeInsets.all(5),
decoration: new BoxDecoration(color: Colors.white),
child: Wrap(
children: <Widget>[Text("${message.topic}:${message.msg}")],
)))
.toList()
.reversed //颠倒
.toList();
}
//把小车移动的信息发送到mqtt
void _pubMoveMsg(direction) {
Myclient.pubscribe(_pubTopic, direction);
}
Mqtt Myclient = new Mqtt(
'1111',
1883,
'111',
'111',
"1111",
); //新建⼀个刚刚写好的Mqtt对象
String _subTopic = 'esp32mqp'; //接收的主题
String _pubTopic = 'phonemqp'; //发布主题
//关于form的设置,负责校验form中的内容,并且接收相关的输⼊数据
GlobalKey<FormState> _pubMsgFormKey = new GlobalKey<FormState>();
GlobalKey<FormState> _subTopicFormKey = new GlobalKey<FormState>();
ScrollController subMsgScrollController = new ScrollController();
//给滚动控件呈现的数据
List<Message> messages = <Message>[];
//接下来我们修改布局,这⾥先完成发布消息这个部分:
}
//定义一个比较好看的按钮类,可以重复使用
class btnBeautifulTeal extends RaisedButton {
// ignore: missing_required_param
btnBeautifulTeal({
Key key,
@required VoidCallback onPressed,
ButtonTextTheme textTheme,
double elevation,
Color color,
ShapeBorder shape,
Clip clipBehavior = Clip.none,
bool autofocus = false,
// ignore: missing_required_param
Widget child,
}) : assert(autofocus != null),
assert(elevation == null || elevation >= 0.0),
assert(focusElevation == null || focusElevation >= 0.0),
assert(hoverElevation == null || hoverElevation >= 0.0),
assert(highlightElevation == null || highlightElevation >= 0.0),
assert(disabledElevation == null || disabledElevation >= 0.0),
assert(clipBehavior != null),
super(
key: key,
onPressed: onPressed,
color: Colors.teal,
highlightColor: Colors.deepPurpleAccent,
//长按
splashColor: Colors.deepOrangeAccent,
//速点了一下
colorBrightness: Brightness.dark,
elevation: 50.0,
//海拔
highlightElevation: 100.0,
disabledElevation: 20.0,
child: child,
shape: shape);
// ignore: missing_required_param
}