https://i.stack.imgur.com/9k5MB.png
I am new to flutter and I'm working on social distancing app in flutter. I wanted to push the uuid of bluetooth devices discovered to the firestore can someone please help me in doing this
I can print out the discovered devices in my app and i can get rssi uuid txpower but as rssi keeps varying and scanning happens continuously the devices get pushed into firestore multiple times i wanted UUID to be pushed into the firestore only once.
Nearby.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:beacon_broadcast/beacon_broadcast.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'homescreen.dart';
import 'material.dart';
class BlueApp extends StatefulWidget {
@override
_BlueAppState createState() => _BlueAppState();
}
BeaconBroadcast beaconBroadcast = BeaconBroadcast();
BeaconStatus _isTransmissionSupported;
bool _isAdvertising = false;
StreamSubscription<bool> _isAdvertisingSubscription;
final databaseReference=Firestore.instance;
String UUID = "3E4D7TJ9008";
void createRecord(String usid) async {
await databaseReference.collection("users")
.document("1")
.setData({
'uuid':usid
});
print('senddddddddingggggg');
DocumentReference ref = await databaseReference.collection("users")
.add({
'uuid':usid
});
print(ref.documentID);
}
class _BlueAppState extends State<BlueApp> {
static const UUID = '39ED98FF';
static const MAJOR_ID = 1;
static const MINOR_ID = 100;
static const TRANSMISSION_POWER = -59;
static const IDENTIFIER = 'com.example.myDeviceRegion';
static const LAYOUT = BeaconBroadcast.ALTBEACON_LAYOUT;
static const MANUFACTURER_ID = 0x0118;
void initState() {
// TODO: implement initState
super.initState();
FlutterBlue.instance.state.listen((state) {
print("im in the init");
print(state);
if (state == BluetoothState.off) {
print("bluetooth is off");
} else if (state == BluetoothState.on) {
print("bluethooth on");
//print(device.id);
}
print("printing eacon");
});
beaconBroadcast.checkTransmissionSupported().then((isTransmissionSupported) {
setState(() {
_isTransmissionSupported = isTransmissionSupported;
print(_isTransmissionSupported);
});
});
_isAdvertisingSubscription =
beaconBroadcast.getAdvertisingStateChange().listen((isAdvertising) {
setState(() {
_isAdvertising = isAdvertising;
});
});
beaconBroadcast
.setUUID(UUID)
.setMajorId(MAJOR_ID)
.setMinorId(MINOR_ID)
.setTransmissionPower(-59)
.setIdentifier(IDENTIFIER)
.setLayout(LAYOUT)
.setManufacturerId(MANUFACTURER_ID)
.start();
if(_isAdvertising==true){
print('Beacon started Advertising');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
color: Colors.lightBlue,
home: StreamBuilder<BluetoothState>(
stream: FlutterBlue.instance.state,
initialData: BluetoothState.turningOn,
builder: (c, snapshot) {
final state = snapshot.data;
print(state);
if (state == BluetoothState.on) {
print("BlueTooth is on");
return FindDevicesScreen();
}
print("BlueTooth is off");
return BluetoothOffScreen(state: state);
}),
);
}
}
class BluetoothOffScreen extends StatelessWidget {
const BluetoothOffScreen({Key key, this.state}) : super(key: key);
final BluetoothState state;
@override
Widget build(BuildContext context) {
_BlueAppState a=new _BlueAppState();
createRecord(UUID);
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.bluetooth_disabled,
size: 200.0,
color: Colors.white54,
),
Text(
'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.',
style: Theme.of(context)
.primaryTextTheme
.subhead
.copyWith(color: Colors.white),
),
],
),
),
);
}
}
class FindDevicesScreen extends StatefulWidget {
@override
_FindDevicesScreenState createState() => _FindDevicesScreenState();
}
class _FindDevicesScreenState extends State<FindDevicesScreen> {
@override
void initState() {
// TODO: implement initState
super.initState();
FlutterBlue.instance.startScan();
beaconBroadcast.checkTransmissionSupported().then((isTransmissionSupported) {
setState(() {
_isTransmissionSupported = isTransmissionSupported;
print(_isTransmissionSupported);
});
});
_isAdvertisingSubscription =
beaconBroadcast.getAdvertisingStateChange().listen((isAdvertising) {
setState(() {
_isAdvertising = isAdvertising;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Find Devices'),
),
body: RefreshIndicator(
onRefresh: () =>
FlutterBlue.instance.startScan(),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
StreamBuilder<List<BluetoothDevice>>(
stream: Stream.periodic(Duration(seconds: 4))
.asyncMap((_) => FlutterBlue.instance.connectedDevices),
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data
.map((d) => ListTile(
title: Text(d.name),
subtitle: Text(d.id.toString()),
trailing: StreamBuilder<BluetoothDeviceState>(
stream: d.state,
initialData: BluetoothDeviceState.disconnected,
builder: (c, snapshot) {
print('entering if');
if (true) {
print('id----------------------------------------------did');
}
return Text(snapshot.data.toString());
},
),
))
.toList(),
),
),
StreamBuilder<List<ScanResult>>(
stream: FlutterBlue.instance.scanResults,
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data
.map(
(r) => Card(
child: ScanResultTile(
result: r,
onTap: () => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return null;
})),
),
),
)
.toList(),
),
),
],
),
),
),
);
}
}
material.dart
import 'package:flutter_blue/flutter_blue.dart';
import 'nearby.dart';
class ScanResultTile extends StatelessWidget {
const ScanResultTile({Key key, this.result, this.onTap}) : super(key: key);
final ScanResult result;
final VoidCallback onTap;
Widget _buildTitle(BuildContext context) {
if (result.device.name.length > 0) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
result.device.name,
overflow: TextOverflow.ellipsis,
),
Text(
result.device.id.toString(),
style: Theme.of(context).textTheme.caption,
),
// _buildAdvRow(
// context, 'Distance of the device',(result.rssi!=null && result.advertisementData.txPowerLevel!=null)?"${getDistance(result.rssi,result.advertisementData.txPowerLevel)}":"N/A" ),
],
);
} else {
return Text(result.device.id.toString());
}
}
Widget _buildAdvRow(BuildContext context, String title, String value) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(title, style: Theme.of(context).textTheme.caption),
SizedBox(
width: 12.0,
),
Expanded(
child: Text(
value,
style: Theme.of(context)
.textTheme
.caption
.apply(color: Colors.black),
softWrap: true,
),
),
],
),
);
}
String getNiceHexArray(List<int> bytes) {
return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
.toUpperCase();
}
int getDistance(int rssi, int txPower) {
print("rssi");
print(rssi);
return 10 ^ ((txPower - rssi) / (10 * 2)).round();
}
@override
Widget build(BuildContext context) {
print("rssi");
print(result.rssi);
print("Transmit power");
print(result.advertisementData.txPowerLevel);
// print(result.device.name);
print(result);
// if((getDistance(result.rssi,result.advertisementData.txPowerLevel))<=2)
// {
// createRecord(result.advertisementData.serviceUuids.iterator.moveNext().toString());
// }
return ExpansionTile(
title: _buildTitle(context),
leading: Column(
children: <Widget>[
Text("Tap for more...",style: TextStyle(fontSize: 10.0,color: Colors.lightBlueAccent),)
],
),
children: <Widget>[
_buildAdvRow(
context, 'Distance of the device',(result.rssi!=null && result.advertisementData.txPowerLevel!=null)?"${getDistance(result.rssi,result.advertisementData.txPowerLevel)}":"N/A" ),
_buildAdvRow(context, 'Tx Power Level',
'${result.advertisementData.txPowerLevel ?? 'N/A'}'),
_buildAdvRow(
context,
'Service UUIDs',
(result.advertisementData.serviceUuids.isNotEmpty)? result.advertisementData.serviceUuids.join(', ').toUpperCase(): 'N/A'),
],
);
}
}
class ServiceTile extends StatelessWidget {
final BluetoothService service;
final List<CharacteristicTile> characteristicTiles;
const ServiceTile({Key key, this.service, this.characteristicTiles})
: super(key: key);
@override
Widget build(BuildContext context) {
if (characteristicTiles.length > 0) {
return ExpansionTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Service'),
Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
),
children: characteristicTiles,
);
} else {
return ListTile(
title: Text('Service'),
subtitle:
Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}'),
);
}
}
}
class CharacteristicTile extends StatelessWidget {
final BluetoothCharacteristic characteristic;
final List<DescriptorTile> descriptorTiles;
final VoidCallback onReadPressed;
final VoidCallback onWritePressed;
final VoidCallback onNotificationPressed;
const CharacteristicTile(
{Key key,
this.characteristic,
this.descriptorTiles,
this.onReadPressed,
this.onWritePressed,
this.onNotificationPressed})
: super(key: key);
@override
Widget build(BuildContext context) {
return StreamBuilder<List<int>>(
stream: characteristic.value,
initialData: characteristic.lastValue,
builder: (c, snapshot) {
final value = snapshot.data;
return ExpansionTile(
title: ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Characteristic'),
Text(
'0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context).textTheme.body1.copyWith(
color: Theme.of(context).textTheme.caption.color))
],
),
subtitle: Text(value.toString()),
contentPadding: EdgeInsets.all(0.0),
),
children: descriptorTiles,
);
},
);
}
}
class DescriptorTile extends StatelessWidget {
final BluetoothDescriptor descriptor;
final VoidCallback onReadPressed;
final VoidCallback onWritePressed;
const DescriptorTile(
{Key key, this.descriptor, this.onReadPressed, this.onWritePressed})
: super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Descriptor'),
Text('0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
),
subtitle: StreamBuilder<List<int>>(
stream: descriptor.value,
initialData: descriptor.lastValue,
builder: (c, snapshot) => Text(snapshot.data.toString()),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(
Icons.file_download,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onReadPressed,
),
IconButton(
icon: Icon(
Icons.file_upload,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onWritePressed,
)
],
),
);
}
}
class AdapterStateTile extends StatelessWidget {
const AdapterStateTile({Key key, @required this.state}) : super(key: key);
final BluetoothState state;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.redAccent,
child: ListTile(
title: Text(
'Bluetooth adapter is ${state.toString().substring(15)}',
style: Theme.of(context).primaryTextTheme.subhead,
),
trailing: Icon(
Icons.error,
color: Theme.of(context).primaryTextTheme.subhead.color,
),
),
);
}
}```
To avoid adding it additional times there are two altenatives.
Alternative 1:
This alternative has the advantage that no changes need to be done on firestore and minimun changes on the code, however will have the disadvantage that each write attempt will be preceeded by a read and reads are billed.
Alternative 2:
Change the data structucture on Firestore so that the UUID is the document ID
This has the advantage that the writes won't be preceeded by a read therefore its cheaper on firestore costs. However it needs more code edition and will need to change the data stucture.
for the code the main change is on the following method:
void createRecord(String usid) async {
await databaseReference.collection("users")
.document(usid)
.setData({
'uuid':usid
});
print('senddddddddingggggg');
DocumentReference ref = await databaseReference.collection("users")
.document(usid)
.setData({
'uuid':usid
});
print(ref.documentID);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.