How to convert MQTT Message to JSON format in Flutter - json

I already connect and get data from MQTT broker using snapshot method. However, I want to convert the MQTT message to JSON format cause I want to do some condition code to certain data.
My problem is when I stream data from the MQTT broker, my data only came out for the last data for that index. That index consists three different data, but since the index hold 3 data at the same time, only the last data of the index that displayed. This is my current code. How can I do that?
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter MQTT"),
),
body: FutureBuilder(
future: mqttSubscribe(topic: "/sensor_simulator/data"),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Center(
child: Text("Error: ${snapshot.error}"),
);
}
// if succeed to connect
if (snapshot.connectionState == ConnectionState.done) {
return StreamBuilder(
stream: snapshot.data,
builder: (BuildContext context, AsyncSnapshot snapshot) {
// if have error--> display
if (snapshot.hasError) {
return Center(
child: Text("Error: ${snapshot.error}"),
);
}
// if data detected--> display
if (snapshot.hasData) {
try {
final List<MqttReceivedMessage> receiveMessage =
snapshot.data;
final recMess =
receiveMessage[0].payload as MqttPublishMessage;
String payload = MqttPublishPayload.bytesToStringAsString(
recMess.payload.message);
return ListView(
children: [
Card(
child: ListTile(
title: Text(payload),
))
],
padding: EdgeInsets.all(10),
);
} catch (e) {
return Center(
child: Text("Error: ${e.toString()}"),
);
}
}
return Center(child: CircularProgressIndicator());
},
);
}
return Center(child: CircularProgressIndicator());
},
),
);
}
}

You can use this piece of code:
void _subscribeToTopic(String topicName) {
print('MQTTClientWrapper::Subscribing to the $topicName topic');
client.subscribe(topicName, MqttQos.atMostOnce);
client.updates!.listen((List<MqttReceivedMessage<MqttMessage>> c) {
final recMess = c[0].payload as MqttPublishMessage;
String message =
MqttPublishPayload.bytesToStringAsString(recMess.payload.message);
String decodeMessage = Utf8Decoder().convert(message.codeUnits);
print("MQTTClientWrapper::GOT A NEW MESSAGE $decodeMessage");
});
}

Related

Flutter Filtering Future with list builder

I have a widget that is meant to return a list/listtile of amenities in a location,
the data comes from a JSON file which I get when the page loads and displays a list of locations. the user then clicks on a location and gets a list of amenities in said location. can we do something like
tmp = amenities.filter(el => el.locationid=locationid
class _Locations extends State<Locations>
with SingleTickerProviderStateMixin {
late Future<Amenities> amenities;
#override
void initState() {
super.initState();
amenities = AmenitiesDataApi.getAmenities();
}
Widget localAttractionsTab(locationid) {
return Column(
children: <Widget>[
FutureBuilder(
future: amenities,
builder: (BuildContext context, AsyncSnapshot<Amenities> snapshot) {
if (snapshot.hasData) {
for (var amen in snapshot.data!.amenities) {
if (amen.locationid == locationid) {
return ListTile(Text(snapshot.data!.amenities[0].amenityname),);
}
}
throw ('error');
}
},
),
],
);
}
That should be possible, but you need to re-arrange your widget a litte.
The Column wants to see a <Widget>[] for its child parameter, so you can use filter and map on the list here:
Widget localAttractionsTab(locationid) {
return FutureBuilder(
future: amenities,
builder: (BuildContext context, AsyncSnapshot<Amenities> snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data!.amenities
.where((el) => el.locationid == locationid)
.map((el) => ListTile(Text(el.amenityname)))
.toList()
);
}
return Container();
},
);
}
You can try this
Widget localAttractionsTab(locationid) {
return FutureBuilder(
future: amenities,
builder: (BuildContext context, AsyncSnapshot<Amenities>
snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data!.amenities.where((amen) => amen.locationid ==
locationid)
.map((amen) => ListTile(Text(amen.amenityname),)
).toList());
}
return CircularProgressIndicator();
},
);
}
You can also update your code by moving the Column into the FutureBuilder and also do the filtration outside the for loop.
Widget localAttractionsTab(locationid) {
return FutureBuilder(
future: amenities,
builder: (BuildContext context, AsyncSnapshot<Amenities> snapshot) {
return Column(
children: <Widget>[
if (snapshot.hasData) {
for (var amen in snapshot.data!.amenities.where((amen)=> amen.locationid == locationid)
ListTile(Text(amen.amenityname))
}
]);
}),
);
}

Futubuilder snapshot.hasData returning false

I wrote code to fetch data and put them to GridView Buider.
But condition snapshot.hasData not working, its always False and return CircularProgressIndicator().
But If I change condition to !snapshot.hasData(true) my code is working, and fetch data shows on the screen correctly.
Fetch API
List<String> pcBusy = [];
Future fetchDataStandart() async {
final urlAuth =
Uri.parse('http://xxx.xx.xxx.xxx/api/usersessions/activeinfo');
final response = await http
.get(urlAuth, headers: <String, String>{'authorization': basicAuth});
if (response.statusCode == 200) {
List listPc = List.from(json.decode(response.body)['result']);
pcBusy.clear();
for (int i = 0; i < listPc.length; i++) {
pcBusy.add(listPc[i]['hostName']);
}
print(pcBusy);
} else {
throw Exception('Error');
}
Builder code
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'ЕВРОКО Стандарт',
),
),
body: FutureBuilder(
future: fetchDataStandart(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ComputerGrid();
} else {
return Center(
child: CircularProgressIndicator(),
);
}
Your fetchDataStandart() function does not have any return statement. Therefore calling it will not give you any data. You need to add a return statement. I do not know if you have just not shared the complete function, because one closing bracket is missing at the end.

How to convert a json data into a List<widgets> in flutter?

a sample of what i have in mind
var url = 'https://www.googleapis.com/books/v1/volumes?q=egg';
Future<BookResponse> getData() async {
var response = await http.get(url);
var responseBody = jsonDecode(response.body);
// print(responseBody);
return BookResponse.fromJson(responseBody);
}
-----
FutureBuilder<BookResponse>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) print(snapshot.error);
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.items.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title:
Text(snapshot.data.items[index].volumeInfo.title),
));
});
} else
return Center(child: CircularProgressIndicator());
},
)
im trying to create a method that will convert json map into a List<widgets> so i can use it to display items.
i can't find a way to display items as rows and columns.
is it possible to have multiple widgets using FutureBuilder? (one row of books and another row to show authors for example)
if so i will avoid converting it to List<widgets>
Convert JSON data to objects and:
Row(
children: entities.map((entity) => Text(entity.text)).toList();
),
It creates a list with widgets.

infinite loading for json data in flutter

EDIT - "When I tried to run print(snapshot.error), It gave "type int is not a subtype of type string""
I am trying to get json data from https://raw.githubusercontent.com/RahulBagdiOfficial/rto_app_flutter/master/assets/json/applyonline.json
using https request package then parsing it into json data,
I am using it to build a list using ListView.builder
that if the data is null return CircularProgressIndicator
and if it contain data return list
The problem is This
its Stuck on loading
This is my code
class ApplyOnline extends StatefulWidget {
#override
_ApplyOnlineState createState() => _ApplyOnlineState();
}
class _ApplyOnlineState extends State<ApplyOnline> {
#override
Future<List<ApplyOnlineList>> _getapplyonlinelist() async {
var data = await http.get(
"https://raw.githubusercontent.com/RahulBagdiOfficial/rto_app_flutter/master/assets/json/applyonline.json");
var jsonData = json.decode(data.body);
List<ApplyOnlineList> applyonlinelist = [];
for (var i in jsonData) {
ApplyOnlineList applyonlineobject =
ApplyOnlineList(i['index'], i['string'], i['url']);
applyonlinelist.add(applyonlineobject);
}
print(applyonlinelist.length);
return applyonlinelist;
}
Widget customURLButton(String text, String URL, Icon icon) {
;
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff655ee6),
appBar: AppBar(
backgroundColor: Color(0xff655ee6),
title: Text("Apply Online"),
),
body: SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: FutureBuilder(
future: _getapplyonlinelist(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
} if(snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(snapshot.data[index].string),
);
},
);
}
},
),
),
),
);
}
}
class ApplyOnlineList {
final int index;
final String url;
final String string;
ApplyOnlineList(this.url, this.index, this.string);
}
You should pass reference of the future since you're not accepting any params in future:
future: _getapplyonlinelist
Check all the connection state before getting into snapshot.
And for checking snapshot, You can do this way:
if(snapshot.hasData) {
// return something
} else if(snapshot.hasError) {
// play with error
}
return CircularProgressIndicator();
The problem is, you're checking for null, and returning the widget, doing this doesn't allow the FutureBuilder to rebuild because you're not checking its connection state, so the state of the data won't update. Try this instead.
...
FutureBuilder(
future: _getapplyonlinelist(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting || !snapshot.hasData)
{
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(snapshot.data[index].string),
);
);
}
...
Checking the ConnectionState will let the future builder resolve the future properly.
future: _getapplyonlinelist(),
Don't do this. This way, every time your build function is called, your Future will start over. You need to start it once and then wait for it.
In your state, outside the build method, have a variable to hold the future. Assign _getapplyonlinelist() to this variable once, probably in the void initState () method. Then use that variable in your build method. That way, no matter how often the build method is called, it will not start the Future over and over and over.
In your state class:
Future<List<ApplyOnlineList>> waitingForOnlineList;
void initState () {
waitingForOnlineList = _getapplyonlinelist();
}
... and then in your build method:
future: waitingForOnlineList,

Flutter http get json data

I am having difficulty with data get. I am very new to Flutter and although I read the articles, I could not overcome this problem. I was able to get the data individually, but I couldn't put it in a loop. The codes are below.
Future<List<Post>> getPosts() async {
var jsonData = await http.get("https://example.com/api/posts.php");
final jsonResponse = json.decode(jsonData.body);
Match postList= Post.fromJsonMap(jsonResponse);
return (jsonResponse as List)
.map((postList) => Post.fromJsonMap(postList))
.toList();
//print("post" + postList.result[1].home);
}
When I run the print method, I can print the data. However, when I send it to futurebuilder, the data is not coming.
body: FutureBuilder(
future: getPosts(),
builder: (BuildContext context, AsyncSnapshot<List<Post>> snapshot) {
if (snapshot.hasData) {
print("test");
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data[index].result[index].home),
subtitle: Text(snapshot.data[index].result[index].title),
leading: CircleAvatar(
child: Text(
snapshot.data[index].result[index].id.toString()),
),
);
});
} else {
return Center(child: CircularProgressIndicator());
}
}),
Note: The codes I used as an example: https://github.com/emrealtunbilek/flutter_json_http/blob/master/lib/remote_api.dart
Try add additional if branch like this
} else if (snapshot.hasError) {
print(snapshot.error);
} else {
You can use JsonToDart for parse data and cast to your model