Update
This commit is contained in:
parent
84a37b9603
commit
5dbac7f8f5
|
|
@ -1,4 +1,4 @@
|
|||
# Eagle Tr@cker
|
||||
|
||||
## Installation
|
||||
flutter build --release
|
||||
flutter run --release
|
||||
|
|
@ -23,7 +23,7 @@ if (flutterVersionName == null) {
|
|||
}
|
||||
|
||||
android {
|
||||
namespace "com.example.gps_map_flowpoint"
|
||||
namespace "com.example.eagletracker"
|
||||
compileSdkVersion flutter.compileSdkVersion
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
|
||||
<application
|
||||
android:label="gps_map_flowpoint"
|
||||
android:label="eagletracker"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
|
||||
/*
|
||||
* Class for the BLE provider
|
||||
*/
|
||||
|
||||
class BLEProvider with ChangeNotifier {
|
||||
List<ScanResult> _scanResults = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ import 'dart:convert';
|
|||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/*
|
||||
* Class to save the devices pinned by the user
|
||||
*/
|
||||
class DevicesSaved {
|
||||
String deviceName = '';
|
||||
String deviceAddress = '';
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ class GeoPosition {
|
|||
final double altitude;
|
||||
final double speed;
|
||||
|
||||
/*
|
||||
* Class for the geographical position element needed for tracking the bird
|
||||
*/
|
||||
GeoPosition({
|
||||
required this.latitude,
|
||||
required this.longitude,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ import 'dart:convert';
|
|||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/*
|
||||
* Class to save the preferences of the user
|
||||
*/
|
||||
class PreferenceSaved {
|
||||
int timeTakingPointSecond = 0;
|
||||
|
||||
|
|
|
|||
20
lib/config.dart
Normal file
20
lib/config.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Singleton class for configuration
|
||||
*/
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class Config {
|
||||
static final Config _instance = Config._internal();
|
||||
|
||||
Config._internal();
|
||||
|
||||
factory Config() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
String projectName = 'Eagle Tr@cker';
|
||||
bool debug = kDebugMode; // Set to true to enable debug logs
|
||||
int manufacturerId = 49406; // Manufacturer ID setted in arduino code
|
||||
int defaultTimeCapture = 10; // Default time capture in seconds
|
||||
}
|
||||
|
|
@ -1,9 +1,15 @@
|
|||
import 'package:eagletracker/config.dart';
|
||||
import 'package:eagletracker/function.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
|
||||
|
||||
import 'package:eagletracker/class/BLEProvider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
/*
|
||||
* Class for the device advertisement scan information screen
|
||||
*/
|
||||
class DeviceAdvertizinScan extends StatefulWidget {
|
||||
const DeviceAdvertizinScan(
|
||||
{super.key,
|
||||
|
|
@ -20,38 +26,66 @@ class DeviceAdvertizinScan extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _DeviceAdvertizinScanState extends State<DeviceAdvertizinScan> {
|
||||
Config config = Config();
|
||||
List<ScanResult> scanResults = [];
|
||||
|
||||
TextEditingController tecTakingPoint = TextEditingController();
|
||||
MapController mapController = MapController(
|
||||
initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324),
|
||||
);
|
||||
double latitude = 0;
|
||||
double longitude = 0;
|
||||
double altitude = 0;
|
||||
double speed = 0;
|
||||
|
||||
String value = 'Aucune valeur reçue';
|
||||
|
||||
TextEditingController tecTakingPoint = TextEditingController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
//Get the BLE provider and the scan results
|
||||
final bleProvider = Provider.of<BLEProvider>(context);
|
||||
scanResults = bleProvider.scanResults;
|
||||
|
||||
//Check if the device is in the list of scanned devices, make sure the manufacturer data is not empty and the remoteId is the same as the one selected
|
||||
if (scanResults
|
||||
.where((element) =>
|
||||
element.advertisementData.manufacturerData.isNotEmpty &&
|
||||
element.device.remoteId.toString() == widget.remoteId)
|
||||
.isNotEmpty) {
|
||||
value = scanResults
|
||||
.where((element) =>
|
||||
element.device.remoteId.toString() == widget.remoteId)
|
||||
.map((e) => e.advertisementData.toString())
|
||||
.first;
|
||||
.where((element) {
|
||||
if (element.device.remoteId.toString() == widget.remoteId) {
|
||||
if (element.advertisementData.manufacturerData[49406] != null) {
|
||||
List<int> data =
|
||||
element.advertisementData.manufacturerData[49406]!;
|
||||
|
||||
// Faites quelque chose avec la variable 'value' ici
|
||||
//Convert the data to hexadecimal
|
||||
List<String> hexList =
|
||||
data.map((int value) => value.toRadixString(16)).toList();
|
||||
|
||||
if (config.debug) {
|
||||
print(data);
|
||||
print(hexList);
|
||||
}
|
||||
|
||||
//Get the values from the advertisement data
|
||||
List<double> values = getValueFromAdvData(data);
|
||||
latitude = values[0];
|
||||
longitude = values[1];
|
||||
altitude = values[2];
|
||||
speed = values[3];
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
return element.device.remoteId.toString() == widget.remoteId;
|
||||
})
|
||||
.map((e) => e.toString())
|
||||
.first;
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title:
|
||||
const Text("Eagle Tr@cker", style: TextStyle(color: Colors.white)),
|
||||
title: Text(config.projectName, style: TextStyle(color: Colors.white)),
|
||||
backgroundColor: Colors.blue,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
||||
|
|
@ -97,6 +131,13 @@ class _DeviceAdvertizinScanState extends State<DeviceAdvertizinScan> {
|
|||
child: Text(value,
|
||||
style: const TextStyle(
|
||||
color: Colors.black, fontWeight: FontWeight.bold))),
|
||||
Container(
|
||||
margin: const EdgeInsets.all(10),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
"Valeurs de la longitude ($longitude), latitude ($latitude), altitude ($altitude) et vitesse ($speed)",
|
||||
style: const TextStyle(
|
||||
color: Colors.black, fontWeight: FontWeight.bold)))
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'dart:typed_data';
|
||||
import 'package:eagletracker/config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
|
||||
import 'package:eagletracker/class/BLEProvider.dart';
|
||||
|
|
@ -10,6 +12,9 @@ import 'package:eagletracker/class/preferenceSaved.dart';
|
|||
import 'package:eagletracker/function.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
/*
|
||||
* Class for the device flow map screen
|
||||
*/
|
||||
class DeviceFlowMap extends StatefulWidget {
|
||||
const DeviceFlowMap(
|
||||
{super.key, required this.deviceName, required this.deviceAddress});
|
||||
|
|
@ -22,46 +27,146 @@ class DeviceFlowMap extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
||||
final Config config = Config();
|
||||
PreferenceSaved preferenceSaved = PreferenceSaved.empty();
|
||||
|
||||
MapController mapController = MapController(
|
||||
initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324),
|
||||
);
|
||||
initPosition: GeoPoint(latitude: 46.1723, longitude: 7.1841));
|
||||
|
||||
List<ScanResult> scanResults = [];
|
||||
List<GeoPosition> geoPositions = [];
|
||||
List<int> advDataLastReception = [];
|
||||
|
||||
Timer? timer;
|
||||
double progression = 0.0;
|
||||
int timeTakingPointSecond = 10;
|
||||
int updateInterval = 500; // Intervalle de mise à jour en millisecondes
|
||||
int updateInterval = 500;
|
||||
|
||||
PreferenceSaved preferenceSaved = PreferenceSaved.empty();
|
||||
double vitesseMax = 0.0;
|
||||
double altitudeMax = 0.0;
|
||||
|
||||
double latitude = 0;
|
||||
double longitude = 0;
|
||||
double altitude = 0;
|
||||
double speed = 0;
|
||||
|
||||
bool targetTracking = false;
|
||||
bool drawRoad = false;
|
||||
|
||||
GeoPoint targetTrackingPoint = GeoPoint(latitude: 0, longitude: 0);
|
||||
GeoPoint targetTrackingPointHistory = GeoPoint(latitude: 0, longitude: 0);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
//Positions de test
|
||||
geoPositions = [
|
||||
GeoPosition(latitude: 1.0, longitude: 2.0, altitude: 100.0, speed: 10.0),
|
||||
GeoPosition(latitude: 3.0, longitude: 4.0, altitude: 200.0, speed: 20.0),
|
||||
];
|
||||
SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.portraitDown,
|
||||
DeviceOrientation.landscapeLeft,
|
||||
DeviceOrientation.landscapeRight,
|
||||
]);
|
||||
|
||||
restoreLocal().then((value) {
|
||||
setState(() {
|
||||
restoreLocal().then((value) async {
|
||||
preferenceSaved = value;
|
||||
timeTakingPointSecond = preferenceSaved.timeTakingPointSecond;
|
||||
|
||||
if (timeTakingPointSecond > 0) {
|
||||
// set the default time capture if the value is 0
|
||||
if (timeTakingPointSecond == 0) {
|
||||
timeTakingPointSecond = config.defaultTimeCapture;
|
||||
}
|
||||
|
||||
int totalUpdates = (timeTakingPointSecond * 1000) ~/ updateInterval;
|
||||
|
||||
timer = Timer.periodic(Duration(milliseconds: updateInterval),
|
||||
(Timer timer) {
|
||||
(Timer timer) async {
|
||||
setState(() {
|
||||
progression = (timer.tick % totalUpdates) / totalUpdates * 100.0;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
print('Erreur: timeTakingPointSecond doit être supérieur à zéro.');
|
||||
|
||||
// Check if the manufacturer data is not empty and the last reception is not empty
|
||||
if (advDataLastReception.isNotEmpty && timer.tick % totalUpdates == 0) {
|
||||
List<String> hexList = advDataLastReception
|
||||
.map((int value) => value.toRadixString(16))
|
||||
.toList();
|
||||
|
||||
if (config.debug) {
|
||||
print(advDataLastReception);
|
||||
print(hexList);
|
||||
}
|
||||
|
||||
//Get the values from the advertisement data
|
||||
List<double> values = getValueFromAdvData(advDataLastReception);
|
||||
latitude = values[0];
|
||||
longitude = values[1];
|
||||
altitude = values[2];
|
||||
speed = values[3];
|
||||
|
||||
//Ajout de la position
|
||||
GeoPosition geoPosition = GeoPosition(
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
altitude: altitude,
|
||||
);
|
||||
|
||||
geoPositions.add(geoPosition);
|
||||
|
||||
//Vitesse max et altitude max
|
||||
if (speed > vitesseMax) {
|
||||
vitesseMax = speed;
|
||||
}
|
||||
|
||||
if (altitude > altitudeMax) {
|
||||
altitudeMax = altitude;
|
||||
}
|
||||
|
||||
targetTrackingPoint = GeoPoint(
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
);
|
||||
|
||||
//Draw the road if the option is enabled
|
||||
mapController.clearAllRoads();
|
||||
if (drawRoad) {
|
||||
List<GeoPoint> linedsPoints = [];
|
||||
|
||||
for (var geoPosition in geoPositions) {
|
||||
GeoPoint geoPoint = GeoPoint(
|
||||
latitude: geoPosition.latitude,
|
||||
longitude: geoPosition.longitude,
|
||||
);
|
||||
|
||||
if (!linedsPoints.contains(geoPoint)) {
|
||||
linedsPoints.add(geoPoint);
|
||||
}
|
||||
if (config.debug) {
|
||||
print(linedsPoints.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (linedsPoints.length > 1) {
|
||||
// Dessiner la route
|
||||
await mapController.drawRoadManually(
|
||||
linedsPoints,
|
||||
const RoadOption(roadColor: Colors.red, zoomInto: false),
|
||||
);
|
||||
}
|
||||
}
|
||||
mapController.removeMarker(targetTrackingPointHistory);
|
||||
mapController.addMarker(targetTrackingPoint,
|
||||
markerIcon: const MarkerIcon(
|
||||
icon: Icon(
|
||||
Icons.star_outlined,
|
||||
color: Colors.red,
|
||||
size: 48,
|
||||
),
|
||||
));
|
||||
targetTrackingPointHistory = targetTrackingPoint;
|
||||
if (targetTracking) {
|
||||
mapController.changeLocation(targetTrackingPoint);
|
||||
}
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -78,6 +183,16 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
final bleProvider = Provider.of<BLEProvider>(context);
|
||||
scanResults = bleProvider.scanResults;
|
||||
|
||||
for (var scanResult in scanResults) {
|
||||
if (scanResult.device.remoteId.toString() == widget.deviceAddress) {
|
||||
if (scanResult.advertisementData.manufacturerData[49406] != null) {
|
||||
advDataLastReception =
|
||||
scanResult.advertisementData.manufacturerData[49406]!;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title:
|
||||
|
|
@ -86,6 +201,10 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () {
|
||||
SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
mapController.dispose();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
|
|
@ -96,7 +215,7 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
controller: mapController,
|
||||
onMapIsReady: (bool value) async {
|
||||
if (value) {
|
||||
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
Future.delayed(const Duration(milliseconds: 750), () async {
|
||||
await mapController.currentLocation();
|
||||
});
|
||||
}
|
||||
|
|
@ -149,14 +268,28 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Altitude: ${geoPositions.last.altitude.toStringAsFixed(2)} m',
|
||||
'Altitude: ${altitude.toStringAsFixed(2)} m',
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Vitesse: ${geoPositions.last.speed.toStringAsFixed(2)} km/h',
|
||||
'Vitesse: ${speed.toStringAsFixed(2)} km/h',
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Alt. max: ${altitudeMax.toStringAsFixed(2)} m',
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Vit. max: ${vitesseMax.toStringAsFixed(2)} km/h',
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
|
|
@ -191,15 +324,17 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
floatingActionButton:
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||
FloatingActionButton(
|
||||
tooltip: 'Centrer la carte sur ma position actuelle',
|
||||
heroTag: 'actionFab1',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
mapController.currentLocation();
|
||||
},
|
||||
child: const Icon(Icons.map_outlined, color: Colors.white),
|
||||
child: const Icon(Icons.gps_not_fixed_sharp, color: Colors.white),
|
||||
),
|
||||
FloatingActionButton(
|
||||
heroTag: 'actionFab2',
|
||||
tooltip: 'Réinitialiser les points',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
|
|
@ -241,6 +376,29 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
child: const Icon(Icons.delete_sharp, color: Colors.white),
|
||||
),
|
||||
FloatingActionButton(
|
||||
heroTag: 'actionFab4',
|
||||
tooltip: 'Centrer la carte sur la cible',
|
||||
backgroundColor: targetTracking ? Colors.green : Colors.blue,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
targetTracking = !targetTracking;
|
||||
});
|
||||
},
|
||||
child: const Icon(Icons.gps_fixed, color: Colors.white),
|
||||
),
|
||||
FloatingActionButton(
|
||||
tooltip: 'Dessiner la route',
|
||||
heroTag: 'actionFab6',
|
||||
backgroundColor: drawRoad ? Colors.green : Colors.blue,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
drawRoad = !drawRoad;
|
||||
});
|
||||
},
|
||||
child: const Icon(Icons.roundabout_left, color: Colors.white),
|
||||
),
|
||||
FloatingActionButton(
|
||||
tooltip: 'Envoyer les positions par email',
|
||||
heroTag: 'actionFab3',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () async {
|
||||
|
|
@ -259,33 +417,6 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
},
|
||||
child: const Icon(Icons.mail, color: Colors.white),
|
||||
),
|
||||
FloatingActionButton(
|
||||
heroTag: 'actionFab4',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
List<GeoPoint> linedsPoints = [];
|
||||
|
||||
for (var geoPosition in geoPositions) {
|
||||
GeoPoint geoPoint = GeoPoint(
|
||||
latitude: geoPosition.latitude,
|
||||
longitude: geoPosition.longitude,
|
||||
);
|
||||
|
||||
linedsPoints.add(geoPoint);
|
||||
|
||||
mapController.clearAllRoads();
|
||||
|
||||
if (linedsPoints.length > 1 &&
|
||||
linedsPoints.toSet().length == linedsPoints.length) {
|
||||
mapController.drawRoadManually(
|
||||
linedsPoints,
|
||||
const RoadOption(roadColor: Colors.red),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: const Icon(Icons.draw, color: Colors.white),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:eagletracker/class/BLEProvider.dart';
|
||||
import 'package:eagletracker/class/devicesSaved.dart' as DevicesSaved;
|
||||
|
|
@ -7,6 +8,9 @@ import 'package:eagletracker/deviceAdvertizinScan.dart';
|
|||
import 'package:eagletracker/deviceFlowMap.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
/*
|
||||
* Class for the device selection screen
|
||||
*/
|
||||
class DeviceSelection extends StatefulWidget {
|
||||
const DeviceSelection({super.key});
|
||||
|
||||
|
|
@ -25,13 +29,17 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
|
||||
TextEditingController tecTimeTakingPointSecond = TextEditingController();
|
||||
|
||||
// Initialize Bluetooth scanning and subscription in initState
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Set the orientation to portrait
|
||||
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
||||
|
||||
// Scanning for BLE devices in the default options
|
||||
isScanning = true;
|
||||
|
||||
// Restore the saved preferences
|
||||
PreferenceSaved.restoreLocal().then((value) {
|
||||
setState(() {
|
||||
preferenceSaved = value;
|
||||
|
|
@ -354,6 +362,9 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to check if the scan is activated
|
||||
*/
|
||||
bool checkIsScanning(BuildContext context, bool isScanning) {
|
||||
if (!isScanning) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:csv/csv.dart';
|
||||
import 'package:flutter_email_sender/flutter_email_sender.dart';
|
||||
import 'package:eagletracker/class/geoPosition.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
/*
|
||||
* Function to generate a CSV file with the positions array
|
||||
*/
|
||||
Future<File> generateCsv(List<GeoPosition> positions) async {
|
||||
List<List<dynamic>> csvData = [
|
||||
['latitude', 'longitude', 'altitude', 'spped'] // Header
|
||||
|
|
@ -26,6 +30,9 @@ Future<File> generateCsv(List<GeoPosition> positions) async {
|
|||
return csvFile;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to send an email with the CSV file as an attachment
|
||||
*/
|
||||
void sendEmailWithAttachment(File csvFile) async {
|
||||
final Email email = Email(
|
||||
subject: 'Eagle Tr@cker - Positions',
|
||||
|
|
@ -40,3 +47,43 @@ void sendEmailWithAttachment(File csvFile) async {
|
|||
throw 'Failed to send email: $error';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to get the values from the manufacturer data according to the data structure
|
||||
*/
|
||||
List<double> getValueFromAdvData(List<int> data) {
|
||||
double latitude = 0;
|
||||
double longitude = 0;
|
||||
double altitude = 0;
|
||||
double speed = 0;
|
||||
|
||||
List<double> values = [];
|
||||
//Latitude
|
||||
List<int> dataLatitude = data.sublist(0, 4);
|
||||
ByteData byteDataLatitude =
|
||||
ByteData.sublistView(Uint8List.fromList(dataLatitude));
|
||||
latitude = byteDataLatitude.getFloat32(0, Endian.little);
|
||||
values.add(latitude);
|
||||
|
||||
//Longitude
|
||||
List<int> dataLongitude = data.sublist(4, 8);
|
||||
ByteData byteDataLongitude =
|
||||
ByteData.sublistView(Uint8List.fromList(dataLongitude));
|
||||
longitude = byteDataLongitude.getFloat32(0, Endian.little);
|
||||
values.add(longitude);
|
||||
|
||||
//Altitude
|
||||
List<int> dataAltitude = data.sublist(8, 12);
|
||||
ByteData byteDataAltitude =
|
||||
ByteData.sublistView(Uint8List.fromList(dataAltitude));
|
||||
altitude = byteDataAltitude.getFloat32(0, Endian.little);
|
||||
values.add(altitude);
|
||||
|
||||
//Speed
|
||||
List<int> dataSpeed = data.sublist(12, 16);
|
||||
ByteData byteDataSpeed = ByteData.sublistView(Uint8List.fromList(dataSpeed));
|
||||
speed = byteDataSpeed.getFloat32(0, Endian.little);
|
||||
values.add(speed);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:provider/provider.dart';
|
|||
|
||||
void main() {
|
||||
runApp(
|
||||
// Add the ChangeNotifierProvider to the root of the widget tree
|
||||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => BLEProvider()),
|
||||
|
|
@ -17,7 +18,6 @@ void main() {
|
|||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user