Skip to content
Snippets Groups Projects
get_measurements.py 6.12 KiB
Newer Older
from datetime import datetime

from server.consts import LAKE_RELATIONS_PATH
from server.ModelFromNVE.icemodellingscripts.getIceThicknessLakes import get_raw_dates, ice_prognosis_raw_data
def get_measurements(self, cursor, lake_name):
        sql_query = '''
            SELECT m.MeasurementID, m.SensorID, m.TimeMeasured, m.CenterLat, m.CenterLon,
                   s.SensorType, s.Active, 
                   b.Name,
                   d.SubDivisionID, d.GroupID, d.MinimumThickness, 
                   d.AverageThickness, d.CenterLatitude, d.CenterLongitude, 
                   d.Accuracy
            FROM Measurement m
            INNER JOIN Sensor s ON m.SensorID = s.SensorID
            INNER JOIN BodyOfWater b ON m.WaterBodyName = b.Name
            LEFT JOIN SubDivision d ON m.MeasurementID = d.MeasurementID
            WHERE b.Name = ?
        '''

        cursor.execute(sql_query, (lake_name,))

        rows = cursor.fetchall()

        # List of all fetched measurement objects
        measurement_data = {}
        sub_div_ids = []

        # Iterate over all fetched rows
        for row in rows:
            measurement_id = row[0]
            sub_div_id = row[8]
            center_lat = row[12]
            center_lng = row[13]

            # Create subdivision new object
            sub_division = {
                'SubdivID': sub_div_id,
                'GroupID': row[9],
                'MinThickness': row[10],
                'AvgThickness': row[11],
                'CenLatitude': center_lat,
                'CenLongitude': center_lng,
                'Accuracy': row[14],
                'Color': calculateColor(row[11]),  # NB color calculated based on average thickness, should be minimum
                'IceStats': get_raw_dates(ice_prognosis_raw_data(sub_div_id=sub_div_id, x=center_lat, y=center_lng))
            sub_div_ids.append(sub_div_id)
            # Check if measurement sub_div_id already exists in measurement_data
            if measurement_id in measurement_data:
                # Create new subdivision within measurement if it does not already exist
                if sub_division not in measurement_data[measurement_id]['Subdivisions']:
                    measurement_data[measurement_id]['Subdivisions'].append(sub_division)

            else:
                # Create a new entry for measurement_id if it does not already exist in the list
                measurement_data[measurement_id] = {
                    'MeasurementID': measurement_id,
                    'TimeMeasured': row[2],
                    'CenterLat': row[3],
                    'CenterLon': row[4],
                    'Sensor': {  # Each measurement only has one related sensor
                        'SensorID': row[1],
                        'SensorType': row[5],
                        'Active': bool(row[6])
                    },
                    'Subdivisions': [sub_division],  # Array of sub_division objects
                }

        # Populate remaining subdivisions and create "invalid" measurement to store them
        remaining_sub_divs = fill_remaining_subdivisions(lake_name, sub_div_ids)
        measurement_data[-1] = {
            'MeasurementID': -1,
            'TimeMeasured': str(datetime.now()),
            'CenterLat': None,
            'CenterLon': None,
            'Sensor': None,
            'Subdivisions': remaining_sub_divs
        }

        # Convert dictionary values to list of measurements
        data = list(measurement_data.values())

        # Write the newest measurements to file
        with open(LAKE_RELATIONS_PATH + lake_name.lower() + '_measurements.json', 'w') as f:
            json.dump(data, f)

        if len(data) == 0:
            marker_data = json.dumps(['no measurements'])
        else:
            # Convert list of dictionaries to JSON
            marker_data = json.dumps(data, indent=4)

    except Exception as e:
        print(f"Error in getting measurements: {e}")
        marker_data = '[]'

        # Set headers
        self.send_response(500)
        self.send_header("Content-type", "application/json")
        self.end_headers()

    # Set headers
    self.send_response(200)
    self.send_header("Content-type", "application/json")
    self.end_headers()

    # Write marker data to response object
    self.wfile.write(marker_data.encode('utf-8'))


# Get data for subdivisions that have not been measured by sensors, and thus are not in the database
def fill_remaining_subdivisions(lake_name: str, sub_div_ids: list):
    try:
        with open(LAKE_RELATIONS_PATH + lake_name + '_div.json', 'r') as file:
            data = json.load(file)

        relation = data
        sub_divisions = []

        for sub_div in relation['features']:
            sub_div_id = int(sub_div['properties']['sub_div_id'])
            if sub_div_id not in sub_div_ids:
                center_lat = sub_div['properties']['sub_div_center'][0]
                center_lng = sub_div['properties']['sub_div_center'][1]

                ice_stats = get_raw_dates(ice_prognosis_raw_data(sub_div_id=sub_div_id, x=center_lat, y=center_lng))

                sub_division = {
                    'SubdivID': sub_div_id,
                    'GroupID': None,
                    'MinThickness': -1.0,  # NB placeholders
                    'AvgThickness': -1.0,
                    'CenLatitude': center_lat,
                    'CenLongitude': center_lng,
                    'Accuracy': None,
                    'Color': 0xFF00d6ff,  # NB placeholder
                    'IceStats': ice_stats,
                }

                sub_divisions.append(sub_division)

        return sub_divisions

    except FileNotFoundError as e:
        print("Failed to find relation file: ", e)
    except Exception as e:
        print("Failed to add remaining subdivisions: ", e)


def calculateColor(thickness: float):  # NB neither final colors nor ranges
        return 0xFFff0000  # Red
        return 0xffff6a00  # Orange
        return 0xFFb1ff00  # Green
    elif thickness > 8:
        return 0xFF00d6ff  # Blue
    else:
        return 0xFF8C8C8C  # Grey