Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBeacon Scan with Radarview No beacon scanned #78

Open
micfio opened this issue Sep 2, 2024 · 0 comments
Open

IBeacon Scan with Radarview No beacon scanned #78

micfio opened this issue Sep 2, 2024 · 0 comments

Comments

@micfio
Copy link

micfio commented Sep 2, 2024

Hello, This is my code :`import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:beacons_plugin/beacons_plugin.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:simple_sensor/simple_sensor.dart';

void main() {
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;

List _accelerometerValues = [0.0, 0.0, 0.0];
List _magnetometerValues = [0.0, 0.0, 0.0];
double _bearing = 0.0;

final AngleLowpassFilter _angleLowpassFilter = AngleLowpassFilter();

@OverRide
void initState() {
super.initState();
requestPermissions().then(() {
_startSensors();
_startBeaconScan();
}).catchError((e) {
print("Permission request failed: $e");
});
}

@OverRide
void dispose() {
_stopSensors();
_beaconEventsController.close();
BeaconsPlugin.stopMonitoring().catchError((e) {
print("Failed to stop monitoring: $e");
});
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 {
BeaconsPlugin.listenToBeacons(_beaconEventsController);

_beaconEventsController.stream.listen(
  (data) {
    if (data.isNotEmpty) {
      try {
        final beaconData = BeaconData.fromJson(data);
        setState(() {
          _beacons.add(beaconData);
          _haveDetected = true;
        });
        print("Beacons Data Received: $data");
      } catch (e) {
        print("Error parsing beacon data: $e");
      }
    }
  },
  onDone: () {
    print("Beacon scan completed.");
  },
  onError: (error) {
    print("Error: $error");
  },
);

try {
  if (Platform.isAndroid) {
    await BeaconsPlugin.addRegion(
        "Exit", "FDA50693-A4E2-4FB1-AFCF-C6EB07647820");
    await BeaconsPlugin.addBeaconLayoutForAndroid(
        "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24");
  }

  await BeaconsPlugin.startMonitoring();
  print("Started monitoring for beacons.");
} catch (e) {
  print("Error starting beacon monitoring: $e");
}

}

@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;

  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);
  }
}

}

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;

BeaconData({
required this.distance,
required this.angle,
});

factory BeaconData.fromJson(String json) {
final data = jsonDecode(json);
return BeaconData(
distance: data['distance'].toDouble(),
angle: data['angle'].toDouble(),
);
}
}
`

The scanning not Work on android 14 No IBeacon Showed On RadarView. Where Is The error ? Can Help Me ? Thaks In Advanced

Permissions:

<uses-permission android:name="android.permission.BLUETOOTH"
                 android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
                 android:maxSdkVersion="30" />

<!-- Needed only if your app looks for Bluetooth devices.
     If your app doesn't use Bluetooth scan results to derive physical
     location information, you can
     <a href="#assert-never-for-location">strongly assert that your app
     doesn't derive physical location</a>. -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

<!-- Needed only if your app makes the device discoverable to Bluetooth
     devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

<!-- Needed only if your app communicates with already-paired Bluetooth
     devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant