-
Notifications
You must be signed in to change notification settings - Fork 189
Description
Hello I Have This Code in flutter:
`import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_beacon/flutter_beacon.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:simple_sensor/simple_sensor.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await flutterBeacon.initializeScanning; // Initialize flutter_beacon
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return MaterialApp(
title: 'Beacon Locator',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RadarScreen(),
);
}
}
class RadarScreen extends StatefulWidget {
@OverRide
_RadarScreenState createState() => _RadarScreenState();
}
class _RadarScreenState extends State {
final StreamController _beaconEventsController =
StreamController.broadcast();
List _beacons = [];
bool _haveDetected = false;
// Sensors
StreamSubscription? _accelerometerSubscription;
StreamSubscription? _magnetometerSubscription;
StreamSubscription? _beaconSubscription;
List _accelerometerValues = [0.0, 0.0, 0.0];
List _magnetometerValues = [0.0, 0.0, 0.0];
double _bearing = 0.0;
final AngleLowpassFilter _angleLowpassFilter = AngleLowpassFilter();
final Region _beaconRegion = Region(
identifier: 'Exit 3p LA',
proximityUUID: 'FDA50693-A4E2-4FB1-AFCF-C6EB07647820');
@OverRide
void initState() {
super.initState();
requestPermissions().then(() {
_startSensors();
_startBeaconScan();
}).catchError((e) {
print("Permission request failed: $e");
});
}
@OverRide
void dispose() {
_stopSensors();
_beaconSubscription?.cancel();
_beaconEventsController.close();
super.dispose();
}
Future _requestPermissions() async {
var status = await [
Permission.bluetoothScan,
Permission.location,
].request();
if (status[Permission.location]?.isDenied ?? true) {
throw Exception("Location permission is required to scan beacons.");
}
}
void _startSensors() {
_accelerometerSubscription =
simpleSensor.accelerometer.listen((AccelerometerEvent event) {
setState(() {
_accelerometerValues = [event.x, event.y, event.z];
_calculateBearing();
});
});
_magnetometerSubscription =
simpleSensor.magnetometer.listen((MagnetometerEvent event) {
setState(() {
_magnetometerValues = [event.x, event.y, event.z];
_calculateBearing();
});
});
}
void _stopSensors() {
_accelerometerSubscription?.cancel();
_magnetometerSubscription?.cancel();
}
void _calculateBearing() {
if (_accelerometerValues.isEmpty || _magnetometerValues.isEmpty) return;
double ax = _accelerometerValues[0];
double ay = _accelerometerValues[1];
double az = _accelerometerValues[2];
double mx = _magnetometerValues[0];
double my = _magnetometerValues[1];
double mz = _magnetometerValues[2];
double roll = atan2(ay, az);
double pitch = atan2(-ax, sqrt(ay * ay + az * az));
double declination = 0; // Adjust based on your location
double azimuth = atan2(
my * cos(roll) - mz * sin(roll),
mx * cos(pitch) +
my * sin(roll) * sin(pitch) +
mz * cos(roll) * sin(pitch));
_angleLowpassFilter.add(azimuth);
double azimuthInDegrees =
(_angleLowpassFilter.average() * (180 / pi) + 360) % 360;
setState(() {
_bearing = azimuthInDegrees;
});
}
Future _startBeaconScan() async {
final regions = [
_beaconRegion,
];
_beaconSubscription = flutterBeacon.ranging(regions).listen(
(RangingResult result) {
List<BeaconData> updatedBeacons = [];
for (var beacon in result.beacons) {
final beaconData =
BeaconData.fromBeacon(beacon, _bearing, _beaconRegion.identifier);
updatedBeacons.add(beaconData);
}
setState(() {
_beacons = updatedBeacons;
_haveDetected = true;
});
},
onError: (error) {
print("Error ranging beacons: $error");
},
);
}
@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Beacon Locator'),
centerTitle: true,
),
body: Center(
child: CustomPaint(
painter: RadarPainter(
bearing: _bearing,
beacons: _beacons,
haveDetected: _haveDetected,
),
child: Container(
width: 300,
height: 300,
),
),
),
);
}
}
class RadarPainter extends CustomPainter {
final double bearing;
final List beacons;
final bool haveDetected;
final double maxDistance = 15.0;
RadarPainter({
required this.bearing,
required this.beacons,
required this.haveDetected,
});
@OverRide
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
final radius = min(size.width, size.height) / 2 - 8;
final gridPaint = Paint()
..color = Colors.orangeAccent
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
canvas.drawCircle(center, radius, gridPaint);
canvas.drawCircle(center, radius * 0.75, gridPaint);
canvas.drawCircle(center, radius * 0.5, gridPaint);
canvas.drawCircle(center, radius * 0.25, gridPaint);
canvas.drawLine(Offset(center.dx, center.dy - radius),
Offset(center.dx, center.dy + radius), gridPaint);
canvas.drawLine(Offset(center.dx - radius, center.dy),
Offset(center.dx + radius, center.dy), gridPaint);
canvas.drawLine(Offset(center.dx - 4, center.dy - 4),
Offset(center.dx + 4, center.dy + 4), gridPaint);
canvas.drawLine(Offset(center.dx - 4, center.dy + 4),
Offset(center.dx + 4, center.dy - 4), gridPaint);
_drawDistanceLabels(canvas, center, radius);
if (haveDetected) {
final beaconPaint = Paint()
..color = Colors.red
..style = PaintingStyle.fill;
final textStyle = TextStyle(
color: Colors.green,
fontSize: 12,
);
for (var beacon in beacons) {
double distance = beacon.distance;
if (distance > maxDistance) continue;
double angle = (beacon.angle - bearing) * (pi / 180);
double beaconX =
center.dx + (distance / maxDistance) * radius * sin(angle);
double beaconY =
center.dy - (distance / maxDistance) * radius * cos(angle);
canvas.drawCircle(Offset(beaconX, beaconY), 8, beaconPaint);
final textSpan = TextSpan(
text: beacon.identifier,
style: textStyle,
);
final textPainter = TextPainter(
text: textSpan,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
)..layout();
textPainter.paint(
canvas,
Offset(beaconX - textPainter.width / 2,
beaconY - textPainter.height - 10));
}
}
}
void _drawDistanceLabels(Canvas canvas, Offset center, double radius) {
final textStyle = TextStyle(
color: Colors.black,
fontSize: 12,
);
final textPainter = TextPainter(
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
for (int i = 1; i <= 4; i++) {
double dist = (maxDistance / 4) * i;
String text = '${dist.toStringAsFixed(1)}m';
textPainter.text = TextSpan(text: text, style: textStyle);
textPainter.layout();
double textHeight = textPainter.height;
canvas.save();
canvas.translate(
center.dx, center.dy - (radius / 4) * i + textHeight / 2);
textPainter.paint(canvas, Offset(-textPainter.width / 2, 0));
canvas.restore();
}
}
@OverRide
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
class AngleLowpassFilter {
final List _values = [];
final int _windowSize = 10;
void add(double value) {
_values.add(value);
if (_values.length > _windowSize) {
_values.removeAt(0);
}
}
double average() {
if (_values.isEmpty) return 0.0;
return _values.reduce((a, b) => a + b) / _values.length;
}
}
class BeaconData {
final double distance;
final double angle;
final String identifier;
BeaconData({
required this.distance,
required this.angle,
required this.identifier,
});
factory BeaconData.fromBeacon(
Beacon beacon, double bearing, String regionIdentifier) {
double beaconAngle = calculateAngle(beacon, bearing);
return BeaconData(
distance: beacon.accuracy,
angle: beaconAngle,
identifier: regionIdentifier,
);
}
static double calculateAngle(Beacon beacon, double bearing) {
double rssi = beacon.rssi.toDouble();
double maxRssi = -30; // RSSI at 1 meter (example)
double minRssi = -100; // RSSI at max distance (example)
double normalizedRssi = (rssi - minRssi) / (maxRssi - minRssi);
double angle = normalizedRssi * 360.0;
double adjustedAngle = (bearing + angle) % 360;
return adjustedAngle;
}
}
`
The visualization of iBeacons on radar sometime is intermittent . Can Someone test the code for to know if depending on FLutter_Beacon plugin or by another piece of my code ? Thanks in Advances