import time
import urequests
import machine
import ujson
import dht
from onewire import OneWire
from ds18x20 import DS18X20
import neopixel
import BME280 as bme280
from machine import ADC, Pin
import network

# ===========================
# Configuration and Constants
# ===========================

# WiFi Configuration
WIFI_SSID = "LAPTOP-K2GEAL20 6366"          # Replace with your WiFi SSID
WIFI_PASSWORD = "0}F6g981"  # Replace with your WiFi Password

# ThingSpeak settings
THINGSPEAK_API_KEY = "L8D704IJUKPH8IB5"
THINGSPEAK_URL = "http://api.thingspeak.com/update"

# Sensor Pins
DHT_PIN = 2        # GPIO4 for DHT22
DS18B20_PIN = 22    # GPIO5 for DS18B20
NEOPIXEL_PIN = 6   # GPIO2 for NeoPixel
I2C_SCL_PIN = 17   # GPIO15 for BME280 SCL
I2C_SDA_PIN = 16   # GPIO14 for BME280 SDA
UV_SENSOR_PIN = 26  # GPIO28 for UV Sensor (Analog)

# NeoPixel configuration
NEOPIXEL_COUNT = 12  # Total number of NeoPixels
UV_LED_RANGE = range(0, 6)      # LEDs 0-5 for UV
TEMP_LED_RANGE = range(6, 12)   # LEDs 6-11 for Temperature

# ThingSpeak rate limit (in seconds)
THINGSPEAK_DELAY = 30

# ===========================
# Initialization
# ===========================

def connect_wifi(ssid, password):
    """
    Connect to a WiFi network.
    """
    wlan = network.WLAN(network.STA_IF)  # Create a station interface
    wlan.active(True)                    
    if not wlan.isconnected():
        print(f"Connecting to WiFi SSID: {ssid}")
        wlan.connect(ssid, password)     
        timeout = 20                     
        while not wlan.isconnected() and timeout > 0:
            print("Waiting for connection...")
            time.sleep(1)
            timeout -= 1
    if wlan.isconnected():
        print("Connected to WiFi")
        print("Network Configuration:", wlan.ifconfig())
    else:
        raise RuntimeError("Failed to connect to WiFi")

connect_wifi(WIFI_SSID, WIFI_PASSWORD)

# Initialize sensors
dht_sensor = dht.DHT22(Pin(DHT_PIN))

ow = OneWire(Pin(DS18B20_PIN))
ds_sensor = DS18X20(ow)
ds_roms = ds_sensor.scan()
if not ds_roms:
    print("Warning: No DS18B20 devices found.")

np = neopixel.NeoPixel(Pin(NEOPIXEL_PIN), NEOPIXEL_COUNT)

try:
    i2c_2 = machine.I2C(0, scl=Pin(I2C_SCL_PIN), sda=Pin(I2C_SDA_PIN), freq=40000)
    bme = bme280.BME280(i2c=i2c_2)
except Exception as e:
    print("Error initializing BME280:", e)
    bme = None

try:
    uv_sensor = ADC(UV_SENSOR_PIN)
    print("UV sensor initialized.")
except Exception as e:
    print("Error initializing UV sensor:", e)
    uv_sensor = None

# ===========================
# Utility Functions
# ===========================

def set_neopixel_color_uv(uv_intensity):
    """
    Set NeoPixel colors for UV indicators based on UV intensity.
    """
    if uv_intensity is None:
        color = (0, 0, 0)
    elif uv_intensity > 75:
        color = (255, 0, 0)
    elif uv_intensity > 25:
        color = (255, 255, 0)
    else:
        color = (255, 0, 255)

    for i in UV_LED_RANGE:
        np[i] = color
    np.write()

def set_neopixel_color_temp(temperature):
    """
    Set NeoPixel colors for Temperature indicators based on temperature.
    """
    if temperature is None:
        color = (0, 0, 0)
    elif 0 <= temperature <= 9:
        color = (0, 255, 0)
    elif 10 <= temperature <= 19:
        color = (255, 255, 0)
    elif temperature >= 20:
        color = (255, 0, 0)
    else:
        color = (0, 0, 255)

    for i in TEMP_LED_RANGE:
        np[i] = color
    np.write()

def read_dht22():
    """
    Read temperature and humidity from DHT22 sensor.
    """
    try:
        dht_sensor.measure()
        return dht_sensor.temperature(), dht_sensor.humidity()
    except OSError as e:
        print("DHT22 read error:", e)
        return None, None

def read_ds18b20():
    """
    Read temperature from DS18B20 sensor.
    """
    if not ds_roms:
        return None
    try:
        ds_sensor.convert_temp()
        time.sleep(1)  # Wait for conversion
        return ds_sensor.read_temp(ds_roms[0])
    except Exception as e:
        print("DS18B20 read error:", e)
        return None

def read_bme280():
    """
    Read pressure from BME280 sensor.
    """
    if not bme:
        return None
    try:
        return bme.pressure
    except Exception as e:
        print("BME280 read error:", e)
        return None

def read_uv_sensor():
    """
    Read UV level from UV sensor.
    """
    if not uv_sensor:
        return None
    try:
        uv_value = uv_sensor.read_u16()
        return (uv_value / 65535) * 100
    except Exception as e:
        print("UV sensor read error:", e)
        return None

def send_thingspeak(temperature, humidity, soil_temp, pressure, uv_level):
    """
    Send sensor data to ThingSpeak.
    """
    try:
        data = {
            "api_key": THINGSPEAK_API_KEY,
            "field1": temperature,
            "field2": humidity,
            "field3": soil_temp,
            "field4": pressure,
            "field5": uv_level
        }
        encoded_data = "&".join([f"{key}={value}" for key, value in data.items() if value is not None])
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
        response = urequests.post(THINGSPEAK_URL, data=encoded_data, headers=headers)
        if response.status_code == 200:
            print("Data successfully sent to ThingSpeak.")
        else:
            print(f"ThingSpeak HTTP Error: {response.status_code}")
        response.close()
    except Exception as e:
        print("Error sending data to ThingSpeak:", e)

# ===========================
# Main Execution Loop
# ===========================

def main():
    data_counter = 0  # Initialize data sent counter

    try:
        while True:
            # Read sensor data
            temperature, humidity = read_dht22()
            soil_temp = read_ds18b20()
            pressure = read_bme280()
            uv_level = read_uv_sensor()

            # Display sensor readings
            print(f"Temperature: {temperature}°C" if temperature else "Temperature: N/A")
            print(f"Humidity: {humidity}%" if humidity else "Humidity: N/A")
            print(f"Soil Temperature: {soil_temp}°C" if soil_temp else "Soil Temperature: N/A")
            print(f"Pressure: {pressure} hPa" if pressure else "Pressure: N/A")
            print(f"UV Level: {uv_level}%" if uv_level else "UV Level: N/A")

            # Update NeoPixels based on UV intensity and Temperature
            set_neopixel_color_uv(uv_level)
            set_neopixel_color_temp(temperature)

            # Send data to ThingSpeak
            send_thingspeak(temperature, humidity, soil_temp, pressure, uv_level)
            data_counter += 1
            print(f"Data transmission count: {data_counter}")

            # Wait for the specified delay
            time.sleep(THINGSPEAK_DELAY)
    except KeyboardInterrupt:
        print("Program terminated by user.")
    except Exception as e:
        print("An unexpected error occurred:", e)

if __name__ == "__main__":
    main()

Make main execution loop Ui more interesting