Skip to content
Snippets Groups Projects
Commit 0e01a33c authored by Sara Savanovic Djordjevic's avatar Sara Savanovic Djordjevic
Browse files

Merge branch 'clhp_map' into 'main'

Clhp map

See merge request !5
parents 19c84eaf ec169a02
Branches
No related tags found
1 merge request!5Clhp map
Showing
with 317 additions and 161607 deletions
This diff is collapsed.
This diff is collapsed.
......@@ -8,20 +8,21 @@ const String serverURI = "https://127.0.0.1:$port/";
const String mapEndpoint = "update_map";
const int fetchInterval = 60; // Fetch marker data every n minutes
// Map center
// Map variables
LatLng mapCenter = LatLng(60.7666, 10.8471);
DateTime ?lastUpdate; // Last time marker data was fetched from server
// Font variables
const textColor = Colors.white;
final appTitleStyle = GoogleFonts.dmSans(
fontSize: 35,
color: Colors.black,
fontWeight: FontWeight.bold, // Add this line to make the text bold
fontWeight: FontWeight.bold,
);
final titleStyle = GoogleFonts.dmSans(
fontSize: 35,
color: textColor,
fontWeight: FontWeight.bold, // Add this line to make the text bold
fontWeight: FontWeight.bold,
);
final regTextStyle = GoogleFonts.dmSans(fontSize: 19, color: textColor);
final chartTextStyle = GoogleFonts.dmSans(fontSize: 14, color: textColor);
......
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'widgets/map_widget.dart';
import 'marker_handler/marker_data.dart';
import 'consts.dart';
import 'marker_handler/get_markers.dart';
import 'marker_handler/get_relation.dart';
import 'dart:typed_data';
import 'dart:io';
import 'dart:convert';
class DefaultPage extends StatefulWidget {
const DefaultPage({super.key});
const DefaultPage({Key? key}) : super(key: key);
@override
_DefaultPageState createState() => _DefaultPageState();
......@@ -17,56 +20,36 @@ class DefaultPage extends StatefulWidget {
class _DefaultPageState extends State<DefaultPage> {
late Timer _timer;
bool showBar = false;
bool serverConnection = true;
List<Measurement> markerList = [];
Uint8List relation = Uint8List(0);
late Future<List<Measurement>> markerListFuture;
late Future<Uint8List> relationFuture;
// Call fetchMarkerTemplate and await its result before setting the state
Future<void> loadMarkerList() async {
try {
List<Measurement> fetchedMarkers = await fetchMarkerData();
Uint8List fetchedRelation = await fetchRelation();
setState(() { // Initialise markers and relations
markerList = fetchedMarkers;
relation = fetchedRelation;
});
} catch (e) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Error"),
content: Text(e.toString()),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text("OK"),
),
],
);
},
);
}
}
// State initializer
@override
void initState() {
super.initState();
// Load marker data from server
loadMarkerList();
markerListFuture = fetchMarkerData().then((fetchResult) {
List<Measurement> measurements = fetchResult.measurements;
serverConnection = fetchResult.connected;
// Return the measurements
return measurements;
}).catchError((error) {
throw Exception("Failed to fetch measurements: $error");
});
//relationFuture = fetchRelation();
relationFuture = Future.value(Uint8List(0));
// Schedule fetchMarkerData to run periodically based on fetchInterval from consts
const Duration interval = Duration(minutes: fetchInterval);
const Duration interval = Duration(minutes: fetchInterval); // NB fetchInterval value to be determined
_timer = Timer.periodic(interval, (timer) {
fetchMarkerData();
});
}
// Fetch timer
// Fetch-interval timer
@override
void dispose() {
// Cancel timer on widget termination
......@@ -77,34 +60,58 @@ class _DefaultPageState extends State<DefaultPage> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Container(
decoration: const BoxDecoration( // Set background color
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [darkBlue, darkestBlue],
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
home: Scaffold(
appBar: AppBar(
title: const Text('IceMap'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
setState(() {
showBar = !showBar;
});
},
),
],
),
body: ListView(
children: [ // Add main widget
body: FutureBuilder(
future: Future.wait([markerListFuture, relationFuture]),
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
// Display loading screen until data is fetched
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: Icon(
Icons.severe_cold,
color: Colors.blue,
size: 100,
));
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
if (!serverConnection) {
print("Failed to connect to server");
}
// Display default page once all data is loaded from server
List<Measurement> markerList = snapshot.data![0] as List<Measurement>;
Uint8List relation = snapshot.data![1] as Uint8List;
return Container( // Return container with list view and background color
decoration: const BoxDecoration( // Set background color
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [darkBlue, darkestBlue],
),
),
child: ListView(
children: [
MapContainerWidget(markerList: markerList, relation: relation),
],
),
);
}
},
),
),
);
}
}
......@@ -3,9 +3,19 @@ import 'dart:convert';
import 'dart:io';
import '../consts.dart';
import 'marker_data.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';
class FetchResult {
final List<Measurement> measurements;
final bool connected;
FetchResult(this.measurements, this.connected);
}
// fetchMarkerTemplate requests all marker data from the server
Future<List<Measurement>> fetchMarkerData() async {
Future<FetchResult> fetchMarkerData() async {
try {
// Custom HTTP client
HttpClient client = HttpClient()
......@@ -26,18 +36,42 @@ Future<List<Measurement>> fetchMarkerData() async {
// Attempt to parse response to Measurement object only if the body
// contains correctly formatted data
if (jsonData != null && jsonData is List) {
print(jsonData.map((data) => Measurement.fromJson(data)).toList());
return jsonData.map((data) => Measurement.fromJson(data)).toList();
} else {
throw Exception('Failed to parse marker data: Unexpected response format');
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
String filePath = '${appDocumentsDirectory.path}/last_data.json';
try { // Write most recent time of update to file
await File(filePath).writeAsString(responseBody, mode: FileMode.write);
print('Lake data written to file');
} catch (error) { print('Error in writing to file: $error');}
// Update local and persistent lastUpdate variable
lastUpdate = DateTime.now();
final prefs = await SharedPreferences.getInstance();
await prefs.setString('lastUpdate', '${DateTime.now()}');
return FetchResult(jsonData.map((data) => Measurement.fromJson(data)).toList(), true);
}
} else {
throw Exception('Failed to parse marker data: Empty response body');
}
} else {
throw Exception('Failed to fetch marker data: Status code ${response.statusCode}');
}
return loadSavedData();
} catch (e) {
throw Exception('Failed to fetch marker data: ${e.toString()}');
return loadSavedData();
}
}
Future<FetchResult> loadSavedData() async {
// Get latest saved data from file if the server does not respond
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
String filePath = '${appDocumentsDirectory.path}/last_data.json';
// Read file contents
File file = File(filePath);
if (await file.exists()) {
String contents = await file.readAsString();
List<dynamic> jsonData = json.decode(contents); // Parse JSON string from file
List<Measurement> measurements = jsonData.map((data) => Measurement.fromJson(data)).toList();
return FetchResult(measurements, false);
} else {
throw Exception('File does not exist');
}
}
......@@ -4,7 +4,6 @@ import 'dart:io';
import '../consts.dart';
import 'dart:typed_data';
/// Fetch relation data from server
Future<Uint8List> fetchRelation() async {
try {
......@@ -17,11 +16,12 @@ Future<Uint8List> fetchRelation() async {
var request = await client.getUrl(Uri.parse('${serverURI}get_relation'));
var response = await request.close(); // Close response body at end of function
// Parse body to JSON if request is ok
// Try to parse body to JSON if request is ok
if (response.statusCode == 200) {
var responseBody = await response.transform(utf8.decoder).join();
if (responseBody.isNotEmpty) {
// Return relation data from the response body
return Uint8List.fromList(utf8.encode(responseBody));
} else {
throw Exception('Response body is empty');
......
import 'dart:typed_data';
import 'package:app/pages/consts.dart';
import '../marker_handler/marker_data.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_maps/maps.dart';
import '../consts.dart';
import 'dart:typed_data';
import 'dart:math';
/// A class containing thickness for each subdivision of the map.
class IceThicknessModel {
IceThicknessModel(this.subDivID, this.thickness);
final int subDivID;
final double thickness;
final String subDivID;
final int thickness;
}
/// A stateful widget which contains a choropleth map.
/// The map data is fetched from the server, and the map is rendered
/// using the Syncfusion Flutter Maps library.
class ChoroplethMap extends StatefulWidget {
const ChoroplethMap({Key? key, required this.relation}) : super(key: key);
const ChoroplethMap({Key? key,
required this.relation,
required this.measurements
}) : super(key: key);
final Uint8List relation;
final List<Measurement> measurements;
@override
_ChoroplethMapState createState() => _ChoroplethMapState();
......@@ -27,11 +30,18 @@ class ChoroplethMap extends StatefulWidget {
class _ChoroplethMapState extends State<ChoroplethMap> {
late MapShapeSource mapShapeSource;
late final MapZoomPanBehavior _zoomPanBehavior = MapZoomPanBehavior();
List<IceThicknessModel> iceThicknessList = <IceThicknessModel>[];
@override
void initState() {
super.initState();
final Random random = Random();
for (int i = 0; i <= 60; i++) {
int randomNumber = random.nextInt(21); // 0 -> 20
iceThicknessList.add(IceThicknessModel(i.toString(), randomNumber));
}
}
@override
......@@ -41,9 +51,41 @@ class _ChoroplethMapState extends State<ChoroplethMap> {
MapShapeLayer(
source: MapShapeSource.memory(
widget.relation,
shapeDataField: 'name',
shapeDataField: 'properties.SubDivID',
dataCount: iceThicknessList.length,
primaryValueMapper: (int index) => iceThicknessList[index].subDivID,
shapeColorValueMapper: (int index) => iceThicknessList[index].thickness,
shapeColorMappers: const [
MapColorMapper(
from: null, // Default color
color: Colors.grey,
text: 'No value',
),
MapColorMapper(
from: 0,
to: 3,
color: Color.fromRGBO(223,169,254, 1),
text: '0-3'),
MapColorMapper(
from: 4,
to: 8,
color: Color.fromRGBO(190,78,253, 1),
text: '4-8'),
MapColorMapper(
from: 9,
to: 15,
color: Color.fromRGBO(167,17,252, 1),
text: '9-15'),
MapColorMapper(
from: 16,
to: 20,
color: Color.fromRGBO(170,20,250, 1),
text: '16-20'),
],
),
color: Colors.orange,
//color: Colors.lightBlueAccent,
zoomPanBehavior: _zoomPanBehavior,
strokeColor: Colors.orange,
),
],
);
......
......@@ -7,6 +7,8 @@ import 'sat_layer.dart';
import 'package:flutter_map/flutter_map.dart';
import 'cloropleth_map.dart';
import 'dart:typed_data';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// MapContainerWidget is the main widget that contains the map with all
/// its layers, polygons and markers.
......@@ -31,17 +33,33 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
bool isTapped = false; // Button tap state tracker
final MapController _mapController = MapController(); // Map controller to re-center map view
// recenterMap moves the map back to its initial view
void recenterMap() {
_mapController.move(mapCenter, 9.0);
}
// Initialise lastUpdate variable from persistent storage if server fetch fails
Future<void> checkAndSetLastUpdate() async {
if (lastUpdate == null) {
final prefs = await SharedPreferences.getInstance();
final updateString = prefs.getString('lastUpdate');
if (updateString != null && updateString.isNotEmpty) {
final updateData = DateTime.parse(updateString);
setState(() {
lastUpdate = updateData;
});
}
}
}
@override
Widget build(BuildContext context) {
// Initialise selectedMarker to first element in markerList
selectedMarker ??= widget.markerList[0];
checkAndSetLastUpdate();
const double contPadding = 30; // Container padding space
return LayoutBuilder(
......@@ -110,7 +128,25 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
width: screenWidth * boxWidth,
height: screenWidth * boxHeight,
child: Container(
color: const Color(0x883366ff)
color: const Color(0x883366ff),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 5),
Text( // Display time of most recent server fetch
'Last updated at ${lastUpdate != null ?
(lastUpdate?.day == DateTime.now().day &&
lastUpdate?.month == DateTime.now().month &&
lastUpdate?.year == DateTime.now().year ?
'${lastUpdate?.hour}:${lastUpdate?.minute}' :
'${lastUpdate?.day}-${lastUpdate?.month}-${lastUpdate?.year}') : ''}',
style: GoogleFonts.dmSans(
fontSize: 13,
color: Colors.black,
),
),
],
),
),
),
SizedBox( // Lake map
......@@ -118,7 +154,7 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
height: screenWidth * boxHeight,
child: Padding(
padding: const EdgeInsets.all(15.0), // Padding around map
child: ChoroplethMap(relation: widget.relation),
child: ChoroplethMap(relation: widget.relation, measurements: widget.markerList,),
),
),
Positioned( // Quick view box layered over map
......
......@@ -34,10 +34,10 @@ class StatCharts extends StatelessWidget {
],
),
),
const SizedBox(height: 20), // Add appropriate padding between charts
const SizedBox(height: 20),
SizedBox(
width: MediaQuery.of(context).size.width * 0.8, // Adjust width as needed
height: 160, // Adjust height as needed
width: MediaQuery.of(context).size.width * 0.8,
height: 160,
child: BarChart(
BarChartData(
alignment: BarChartAlignment.spaceAround,
......@@ -77,19 +77,19 @@ class StatCharts extends StatelessWidget {
BarChartGroupData(
x: 0,
barRods: [
BarChartRodData(y: 15, width: 10), // Example width
BarChartRodData(y: 15, width: 10),
],
),
BarChartGroupData(
x: 1,
barRods: [
BarChartRodData(y: 10, width: 10), // Example width
BarChartRodData(y: 10, width: 10),
],
),
BarChartGroupData(
x: 2,
barRods: [
BarChartRodData(y: 18, width: 10), // Example width
BarChartRodData(y: 18, width: 10),
],
),
],
......
......@@ -6,7 +6,9 @@ import FlutterMacOS
import Foundation
import path_provider_foundation
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}
......@@ -73,6 +73,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
fl_chart:
dependency: "direct main"
description:
......@@ -107,6 +115,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
google_fonts:
dependency: "direct main"
description:
......@@ -252,7 +265,7 @@ packages:
source: hosted
version: "0.2.1"
path_provider:
dependency: transitive
dependency: "direct main"
description:
name: path_provider
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
......@@ -347,6 +360,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.0.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
url: "https://pub.dev"
source: hosted
version: "2.3.5"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
sky_engine:
dependency: transitive
description: flutter
......@@ -456,6 +525,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "13.0.0"
web:
dependency: transitive
description:
name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
win32:
dependency: transitive
description:
......@@ -481,5 +558,5 @@ packages:
source: hosted
version: "1.0.4"
sdks:
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.10.0"
dart: ">=3.3.0 <4.0.0"
flutter: ">=3.19.0"
......@@ -16,6 +16,8 @@ dependencies:
fl_chart: ^0.20.0-nullsafety1
google_fonts: any
syncfusion_flutter_maps: ^20.4.41
path_provider: ^2.0.8
shared_preferences: any
dev_dependencies:
flutter_test:
......@@ -25,6 +27,4 @@ dev_dependencies:
flutter:
uses-material-design: true
assets:
- assets/icons/
- assets/mjosa.geojson
- assets/australia.json
- assets/
File deleted
-----BEGIN CERTIFICATE-----
MIIFCzCCAvOgAwIBAgIIJciHvv6Yi4gwDQYJKoZIhvcNAQELBQAwSTEhMB8GA1UE
AxMYNjViYjZkMjVjNWE2NzgxMWUxOWMyYjY3MQ4wDAYDVQQLEwVBdGxhczEUMBIG
A1UEChMLTW9uZ29EQiBJbmMwHhcNMjQwMjAxMDkyMDE0WhcNMjYwMjAxMTAyMDE0
WjAWMRQwEgYDVQQDDAtjZXJ0X2FjY2VzczCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBAMXNw9D4fe6IWhmOw1emqk5RETZXSCuyh0+uQNyXkQ0OVdl8j1TY
zXqpuvvilz/axIkSba9dMTx/ejKECPmaIlZC6vTgmzdHgftXsm8iBP1audnV36MG
6jvqM7qe1/lQdsDbi94mSLd13/l5hgrENpUgCzp76krcC5wusXLl3OizsYpwrRw6
uwiZm9DxoSIW87ClWJbklP3XLJHfg2lIPjEcdSHSJkLEcUNzmggYXt4OfiSx8zlr
C6X93zgbPMQZqfO3k3B9hrFzuKDqlIvIm4y3GVuZ0Xj6ncDq262nB4+V+YTAWDRK
5CkKZVJlig4ePd5zTsB2hzJnLBWRlor3L756kcdm/2YtkEijQrewOd4RCOcz5Jx6
aZdYQMzUPgVJXh0gtNzY/+wq2WBCcypM22WW8/3678iJoIG4hIXsWVtJOubqovB+
jsbyGMp+5fk1Kqgo7AkiDT7ld/8O60FeR4i7Pa7tiikKKyhg1SnqCwueTzIv43x4
DciEXKKJRFFwbhTKL2Ty3UkFqYtqD9drXT0p7c9XUs5tzO/Jsx1D+KUq0UosP/Cv
fwp5W31pwjeJyEKHrrVIMj3G/+x5wfmIcsKxj+q00NSerx6WYB5ds7BiMZWDqBWT
Oaj/1w5IY7BDkEslYgkpwosw/CGIYrvLqKpWk0l1L5OgaSjouMLbTAiBAgMBAAGj
KjAoMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAjANBgkq
hkiG9w0BAQsFAAOCAgEAeoAdO4BMhhqrfka11JHTggyEkBR742LpV4epKWVLFnru
b6+mZrWVCjKaYmOep1u/3f3imtz6Y9L0zFUBVLsE1scqWNK10gZyChrGJuVlOXRM
NXpoLtOvQUxdJmFPmbnBtP3N3GwdTlq7v8kkyoV0z0KoFxHvPIujlCuHPkY4iQc/
lJYpyzNSmrC3Nyk8jS5QksYaR3A1Ol2puJiqwZBDfl+0ECSS8ovScK4ccYqyo4ze
NT5Uwc0Hr2oHbY4CRViZm+VllwanKeYhFAR3zoLIk5MIh4YlwerZqYRadoKhmRty
1bIEOjeRXoZusF8lIF0/BSaYEnel3xCH5umQWyRUlOkAOnwbqtfY6EaW7xwNFHsS
D34sPvxRJHh9jnCv1127kb3S5aXO+uvqebhdBrP8SOq9pwMgVGhM9y6RsDfz6g78
Xj8ICrS7Ls+Rah4IX2cPkHkEd7CXuQ7Gsr8jY3RSTBoC1/u98mNIFrkaTYBWqGL4
X7m9rFWeI4zLwYHPsKO9hwI9+HwaKiVkE4L5tu1Ur0evougxg0T+Eu4VdC1Z6qbg
JJgbUz6oLtUU9Y4Wp2EHQGTzBTA2+1s7PBMQp/49SxpS0N6JILWtSXOqRQ3BQS6p
Zj0k4adusbJ82cMdImcpjjhUlt58kZ2Ms6F5nUU8Tw+XVDxaId2fZ+GhGTgse4I=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
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
RfOGEADT0A6yOPYYFn8dEALhBSz7
-----END PRIVATE KEY-----
File added
# Sensor contains data related to a single sensor
class Sensor:
def __init__(self, ID: int, type: str, active: bool):
self.ID = ID
self.type = type
self.active = active
def to_dict(self):
return {
'ID': self.ID,
'type': self.type,
'active': self.active
}
# DateTime contains the date and time for a measurement
class DateAndTime:
def __init__(self, year: int, month: int, day: int, hour: int, minute: int):
self.year = year
self.month = month
self.day = day
self.hour = hour
self.minute = minute
def to_dict(self):
return {
'year': self.year,
'month': self.month,
'day': self.day,
'hour': self.hour,
'minute': self.minute
}
# Measurement contains geo-data related to a single measurement point at a given time. It includes an instance
# of the class Sensor.
class Measurement:
def __init__(self, longitude: float, latitude: float, datetime: DateAndTime, sensor: Sensor, precipitation: float,
thickness: float,
max_weight: float, safety_level: float, accuracy: float):
self.longitude = longitude
self.latitude = latitude
self.datetime = datetime
self.sensor = sensor
self.precipitation = precipitation
self.thickness = thickness
self.max_weight = max_weight
self.safety_level = safety_level
self.accuracy = accuracy
def to_dict(self):
return {
'longitude': self.longitude,
'latitude': self.latitude,
'datetime': self.datetime.to_dict(),
'sensor': self.sensor.to_dict(),
'precipitation': self.precipitation,
'thickness': self.thickness,
'max_weight': self.max_weight,
'safety_level': self.safety_level,
'accuracy': self.accuracy
}
# MarkerTemplate is a template for map marker data. It includes an instance of the
# DataPoint type.
class MarkerTemplate:
def __init__(self, geoData: Measurement, size: float, color: str):
self.geoData = geoData
self.longitude = geoData.longitude
self.latitude = geoData.latitude
self.size = size
self.color = color
def to_dict(self):
return {
'geo_data': self.geoData.to_dict(),
'latitude': self.latitude,
'longitude': self.longitude,
'size': self.size,
'color': self.color,
}
File deleted
The following query
[out:json];
(
way["natural"="water"]["name"="lakeName"];
relation["natural"="water"]["name"="lakeName"];
);
/*added by auto repair*/
(._;>;);
/*end of auto repair*/
out body;
......@@ -2,8 +2,7 @@ from flask import Flask
from http.server import HTTPServer, BaseHTTPRequestHandler
from consts import SSL_CERT_PATH, SSL_KEY_PATH, HOST, PORT
from map.get_markers import get_all_markers
from map.input_new_data import input_new_Lidar_data
#from map.get_relation import get_relation
from map.get_relation import get_relation
from APIs.get_weather import get_weather
import ssl
import keyboard
......@@ -12,6 +11,7 @@ import sqlite3
app = Flask(__name__)
terminate_server = 0
class IceHTTPServer(HTTPServer):
def __init__(self, server_address, handler_class, cursor):
super().__init__(server_address, handler_class)
......@@ -35,7 +35,7 @@ class IceHTTP(BaseHTTPRequestHandler):
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Root path hit!")
self.wfile.write(b"The root path provides no functionality. Please use a valid endpoint")
elif self.path == '/update_map': # NB: should be POST?
get_all_markers(self, self.cursor, False, 'Mjosa') # Get all markers
......@@ -50,19 +50,6 @@ class IceHTTP(BaseHTTPRequestHandler):
if self.path == '/get_weather_data':
get_weather(self)
elif self.path == '/new_lidar_data':
input_new_Lidar_data(self,self.cursor, 1, 'Mjosa') # hardcoded body of water must change later
# Terminate server on key press q
def on_key_press(server, event, cursor, conn):
if event.name == 'q':
print('Terminating server...')
server.server_close()
cursor.close()
conn.close()
keyboard.unhook_all()
quit()
# Start a server on port 8443 using self defined HTTP class
if __name__ == "__main__":
......@@ -81,11 +68,6 @@ if __name__ == "__main__":
print("Server running on port ", PORT)
# Register key press event handler
keyboard.on_press(lambda event: on_key_press(server, event, cursor, conn))
print("Server running on port ", PORT)
# Run server indefinitely
server.serve_forever()
......
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment