diff --git a/server/APIs/get_weather.py b/server/APIs/get_weather.py index 69ffd7475ed5c9aa157906b574792ae9721ddbf5..14dc01cfae098b26a4b263f9a575883b9009f838 100644 --- a/server/APIs/get_weather.py +++ b/server/APIs/get_weather.py @@ -4,38 +4,57 @@ import datetime import json -# get_weather retrieves weather data for a given set of coordinates -def get_weather(): - # Extract url parameters - latitude = request.args.get('lat', '') - longitude = request.args.get('lon', '') +# get_weather retrieves weather data for a list of coordinate pairs +def get_weather(self): + # Extract coordinates form json data in POST request + content_length = int(self.headers['Content-Length']) + post_data = self.rfile.read(content_length) + request_data = json.loads(post_data.decode('utf-8')) + coordinates = request_data['coords'] # Form timestamp string with correct format current_time = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") - # Construct request string and execute get request to Yr API - url = f"https://api.met.no/weatherapi/locationforecast/2.0/compact?lat={latitude}&lon={longitude}" - response = requests.get(url) - - if response.status_code == 200: # Extract data from response - data = response.json() - timeseries = data['properties']['timeseries'] - - # Get data for current time - weather_data = None - for entry in timeseries: - if entry['time'] == current_time: - weather_data = entry['data'] - break - - if weather_data is not None: - resp_code = 200 - else: - resp_code = 404 # Data for current time not found - weather_data = {} - - else: # Write empty data object and return status code 500 - resp_code = 500 - weather_data = {} - - return json.dumps(weather_data), resp_code + # Empty list for weather data + weather_data = [] + resp_code = 500 + + # Request weather data for each coordinate pair + for coord in coordinates: + lat = coord.get('lat') + lng = coord.get('lng') + + # Construct request string and execute get request to Yr API + url = f"https://api.met.no/weatherapi/locationforecast/2.0/compact?lat={lat}&lon={lng}" + response = requests.get(url) + + if response.status_code == 200: # Extract data from response + data = response.json() + timeseries = data['properties']['timeseries'] + + # Get data for current time and append to weather_data + for entry in timeseries: + if entry['time'] == current_time: + weather_object = { + 'Latitude': lat, + 'Longitude': lng, + 'Temperature': entry['temperature'], + 'Humidity': entry['humidity'] + } + # Append weather_object to weather_data list + weather_data.append(weather_object) + break + + if resp_code == 500: + resp_code = 200 + + else: # Add error message if no weather data is found or the request fails + weather_data.append({'message': 'No data found', 'latitude': lat, 'longitude': lng}) + + # Set headers + self.send_response(resp_code) + self.send_header("Content-type", "application/json") + self.end_headers() + + # Write weather_data to the response object + self.wfile.write(json.dumps(weather_data).encode('utf-8')) diff --git a/server/data_structs.py b/server/data_structs.py index e35a41e4dc946067e27775f8fbc6f465a664910b..b5c4cd8d363936270e52277e9de3b903d22f8b56 100644 --- a/server/data_structs.py +++ b/server/data_structs.py @@ -1,4 +1,3 @@ - # Sensor contains data related to a single sensor class Sensor: def __init__(self, ID: int, type: str, active: bool): @@ -12,7 +11,8 @@ class Sensor: '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): @@ -31,11 +31,13 @@ class DateAndTime: '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): + 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 @@ -45,7 +47,7 @@ class Measurement: self.max_weight = max_weight self.safety_level = safety_level self.accuracy = accuracy - + def to_dict(self): return { 'longitude': self.longitude, @@ -58,12 +60,13 @@ class Measurement: '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.geoData = geoData self.longitude = geoData.longitude self.latitude = geoData.latitude self.size = size @@ -71,10 +74,9 @@ class MarkerTemplate: def to_dict(self): return { - 'geo_data': self.geoData.to_dict(), + 'geo_data': self.geoData.to_dict(), 'latitude': self.latitude, 'longitude': self.longitude, 'size': self.size, 'color': self.color, } - \ No newline at end of file diff --git a/server/main.py b/server/main.py index 84df1ed4c6a3d70a0cea5f0d22587de4a6cd6101..47d94aadead3156f2108379051b2eed001b05dab 100644 --- a/server/main.py +++ b/server/main.py @@ -2,6 +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 APIs.get_weather import get_weather import ssl import keyboard import sqlite3 @@ -40,6 +41,10 @@ class IceHTTP(BaseHTTPRequestHandler): elif self.path == '/get_valid_markers': # NB: should be POST? get_all_markers(self, self.cursor, True) # Get only valid markers + def do_POST(self): + if self.path == '/get_weather_data': + get_weather(self) + # Terminate server on key press q def on_key_press(server, event, cursor, conn): if event.name == 'q':