"""
==========================================================
Visualization of Temperature and Humidity with DHT22
using Arduino and Python

Arduino Code: https://stefan.bracher.info/microcontrollers.php
==========================================================

Description:
This script reads temperature and humidity data from an Arduino connected
to a DHT22 sensor via a serial port. It then visualizes the data using a
simple thermometer and hygrometer gauge using Matplotlib.

Features:
- Reads real-time temperature and humidity data from an Arduino.
- Displays data on the command line with timestamp.
- Updates a graphical gauge representation in Matplotlib.
- Automatically handles invalid or corrupted serial data.

Requirements:
- Python 3.x
- Matplotlib for visualization
- PySerial for serial communication with Arduino
===========================================================
"""

import serial
import time
import datetime
import matplotlib.pyplot as plt
import matplotlib.patches as patches

# Set up the serial connection
serial_port = "/dev/cu.usbmodem14101"  # Change this to match your Arduino port
baud_rate = 9600  # Must match the baud rate set in the Arduino code

def read_arduino(ser):
    """Read temperature and humidity from Arduino over Serial."""
    try:
        if ser.in_waiting > 0:  # Check if data is available
            line = ser.readline().decode("utf-8").strip()  # Read and clean data
            if "," in line and line[0].isdigit():  # Validate format
                temp, humidity = line.split(",")
                temp = float(temp.strip())  # Convert string to float
                humidity = float(humidity.strip())
                current_time = datetime.datetime.now().time()
                formatted_time = current_time.strftime("%H:%M:%S")  # Format timestamp
                
                # Print formatted data to the command line
                print(f"Time: {formatted_time} | Temperature: {temp:.1f} °C | Humidity: {humidity:.1f} %")
                return temp, humidity
            else:
                print(f"Skipping invalid data: {line}")  # Debugging output
    except Exception as e:
        print(f"Error reading serial data: {e}")
    return None, None  # Return None if data is invalid

def draw_gauges(ax, temp, humidity):
    """Update the graphical thermometer and hygrometer visualization."""
    ax.clear()  # Clear previous drawings
    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)
    ax.axis("off")  # Hide axes

    # Draw the thermometer background
    thermometer = patches.Rectangle((0.4, 0.1), 0.2, 0.7, color="lightgray", lw=2)
    ax.add_patch(thermometer)

    # Draw the hygrometer background
    hygrometer = patches.Rectangle((0.1, 0.1), 0.2, 0.7, color="lightblue", lw=2)
    ax.add_patch(hygrometer)

    # Fill the thermometer based on temperature (max scale 50°C)
    temp_fill = patches.Rectangle((0.4, 0.1), 0.2, min(0.7, temp / 50 * 0.7), color="red")
    ax.add_patch(temp_fill)

    # Fill the hygrometer based on humidity (max scale 100%)
    hum_fill = patches.Rectangle((0.1, 0.1), 0.2, min(0.7, humidity / 100 * 0.7), color="blue")
    ax.add_patch(hum_fill)

    # Display numeric values for temperature and humidity
    ax.text(0.5, 0.85, f"{temp:.1f} °C", ha="center", fontsize=14, color="red")
    ax.text(0.2, 0.85, f"{humidity:.1f} %", ha="center", fontsize=14, color="blue")

    # Optional: Uncomment to add a thermometer bulb
    # bulb = patches.Circle((0.5, 0.05), 0.08, color="red")
    # ax.add_patch(bulb)

    plt.title("Temperature & Humidity Gauge")
    plt.pause(0.1)  # Pause to update the GUI

if __name__ == "__main__":
    # Initialize Serial Connection to Arduino
    try:
        ser = serial.Serial(serial_port, baud_rate, timeout=1)
        time.sleep(2)  # Give time for Arduino to initialize
        ser.flush()  # Clear any existing serial buffer
    except serial.SerialException:
        print("Error: Arduino not connected! Check the port and try again.")
        exit()

    # Initialize Matplotlib for live visualization
    plt.ion()  # Enable interactive mode
    fig, ax = plt.subplots(figsize=(6, 8))

    while True:
        temperature, humidity = read_arduino(ser)  # Get sensor data
        if temperature is not None and humidity is not None:
            draw_gauges(ax, temperature, humidity)  # Update visualization
        time.sleep(2)  # Adjust as needed (sampling interval)
