import serial
import json
import time
import math

# Record the start time of the script
start_time = time.time()

#get config
def load_config(config_file):
    try:
        with open(config_file, 'r') as file:
            config_data = json.load(file)
        return config_data
    except Exception as e:
        print(f"Error loading config file: {e}")
        return {}

# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables
need_to_log = config.get('loop_log', False)

# Initialize serial ports for the three sensors
ser3 = serial.Serial(
    port='/dev/ttyAMA3',
    baudrate=115200,
    parity=serial.PARITY_EVEN,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1
)

ser4 = serial.Serial(
    port='/dev/ttyAMA4',
    baudrate=115200,
    parity=serial.PARITY_EVEN,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1
)

ser5 = serial.Serial(
    port='/dev/ttyAMA5',
    baudrate=115200,
    parity=serial.PARITY_EVEN,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1
)

# Function to read and parse sensor data
def read_sensor_data(ser, sonde_id):
    try:
        # Send the command to request data (e.g., data for 60 seconds)
        ser.write(b'\x81\x12\x6D')

        # Read the response
        byte_data = ser.readline()

        # Extract the state byte and PM data from the response
        PM1 = int.from_bytes(byte_data[9:11], byteorder='big') / 10
        PM25 = int.from_bytes(byte_data[11:13], byteorder='big') / 10
        PM10 = int.from_bytes(byte_data[13:15], byteorder='big') / 10

        # Create a dictionary with the parsed data
        data = {
            'sondeID': sonde_id,
            'PM1': PM1,
            'PM25': PM25,
            'PM10': PM10
        }

        return data
    except Exception as e:
        print(f"Error reading from sensor {sonde_id}: {e}")
        return None

# Function to calculate the Euclidean distance between two sensor readings
def calculate_distance(sensor1, sensor2):
    PM1_diff = sensor1['PM1'] - sensor2['PM1']
    PM25_diff = sensor1['PM25'] - sensor2['PM25']
    PM10_diff = sensor1['PM10'] - sensor2['PM10']
    return math.sqrt(PM1_diff**2 + PM25_diff**2 + PM10_diff**2)

# Function to select the closest pair of sensors and average their data
def average_closest_pair(data):
    # List of sensor names and their data
    sensors = list(data.items())

    # Variable to keep track of the smallest distance and corresponding pair
    min_distance = float('inf')
    closest_pair = None

    # Compare each pair of sensors to find the closest one
    for i in range(len(sensors)):
        for j in range(i + 1, len(sensors)):
            sensor1 = sensors[i][1]
            sensor2 = sensors[j][1]

            # Calculate the distance between the two sensors
            distance = calculate_distance(sensor1, sensor2)

            # Update the closest pair if a smaller distance is found
            if distance < min_distance:
                min_distance = distance
                closest_pair = (sensor1, sensor2)

    # If a closest pair is found, average their values
    if closest_pair:
        sensor1, sensor2 = closest_pair
        averaged_data = {
            'sondeID': f"Average_{sensor1['sondeID']}_{sensor2['sondeID']}",
            'PM1': round((sensor1['PM1'] + sensor2['PM1']) / 2, 2),
            'PM25': round((sensor1['PM25'] + sensor2['PM25']) / 2, 2),
            'PM10': round((sensor1['PM10'] + sensor2['PM10']) / 2, 2)
        }
        return averaged_data
    else:
        return None

# Function to create a JSON object with all sensor data
def collect_all_sensor_data():
    all_data = {}

    # Read data from each sensor and add to the all_data dictionary
    sensor_data_3 = read_sensor_data(ser3, 'USB2')
    sensor_data_4 = read_sensor_data(ser4, 'USB3')
    sensor_data_5 = read_sensor_data(ser5, 'USB4')

    # Store the data for each sensor in the dictionary
    if sensor_data_3:
        all_data['sensor_3'] = sensor_data_3
    if sensor_data_4:
        all_data['sensor_4'] = sensor_data_4
    if sensor_data_5:
        all_data['sensor_5'] = sensor_data_5

    return all_data

# Main script to run once and average data for the closest sensors
if __name__ == "__main__":
    try:
        # Collect data from all sensors
        data = collect_all_sensor_data()
        if need_to_log:
            print("Getting Data from all sensors:")
            print(data)

        # Average the closest pair of sensors
        averaged_data = average_closest_pair(data)
        if need_to_log:
            print("Average the closest pair of sensors:")
            print(averaged_data)


        if averaged_data:
            # Convert the averaged data to JSON
            json_data = json.dumps(averaged_data, indent=4)

            # Define the output file path
            output_file = "/var/www/nebuleair_pro_4g/loop/data.json"  # Change this to your desired file path

            # Write the JSON data to the file
            with open(output_file, 'w') as file:
                file.write(json_data)
            
            if need_to_log:
                print(f"Data successfully written to {output_file}")
        else:
            print("No closest pair found to average.")

        # Calculate and print the elapsed time
        elapsed_time = time.time() - start_time
        if need_to_log:
            print(f"Elapsed time: {elapsed_time:.2f} seconds")
            print("-----------------")

    except Exception as e:
        print(f"Error: {e}")
