import machine, neopixel
from machine import Pin
import asyncio
import struct
import time
import network
import urequests
from micropython import const
import sys

def connect_wifi(ssid, password):
    connected = False
    try:
        wlan = network.WLAN(network.STA_IF)
    except Exception as e:
        print(e)
        return connected     
    wlan.active(True)
    wlan.config(txpower=8) #needed due to a hardware bug see: https://roryhay.es/blog/esp32-c3-super-mini-flaw
    try:
        wlan.connect(ssid, password)
    except Exception as e:
        if 'Wifi Internal Error' == str(e):
            print(e)
            pass
            
    while not wlan.isconnected():
        time.sleep(3) 
    print("Connected to Wi-Fi:", wlan.ifconfig())
    connected = True
    return connected

def fetch_weather_for_city(city, api_key):
    BASE_URL = "http://api.openweathermap.org/data/2.5/weather"
    url = f"{BASE_URL}?q={city}&appid={api_key}&units=metric"
    try:
        response = urequests.get(url)
        if response.status_code in (200, 202):
            data = response.json()
            response.close()
            return data
        else:
            print(f"Error fetching weather for {city}: {response.status_code}")
            response.close()
    except Exception as e:
        print("Weather fetch error:", e)
    return None

def parse_city_weather(data):
    if not data:
        return (20, 0)  # Default values
    temp = data["main"]["temp"]
    rain_chance = min(int(data.get("rain", {}).get("1h", 0) * 20), 100)
    return (temp, rain_chance)

def weather_to_color(temperature, precipitation_chance):
    BRIGHTNESS = 0.05
    precipitation_chance = min(precipitation_chance, 100)
    
    if precipitation_chance > 50:
        return (0, 0, int((precipitation_chance / 100) * 255 * BRIGHTNESS))
    elif temperature > 30:
        return (int(min((temperature / 50) * 255, 255) * BRIGHTNESS), 0, 0)
    elif 25 <= temperature <= 30 and precipitation_chance <= 20:
        return (int(255 * BRIGHTNESS), int(255 * BRIGHTNESS), 0)
    else:
        return (0, int(max((1 - (temperature / 30)) * 255, 0) * BRIGHTNESS), 0)    

async def update_weather(np, led_map, api_key):
    while True:
        weather_data = {}
        if connect_wifi("ssid (wifi name)", "password"):
            for province, led_index in led_map.items():
                weather_data = fetch_weather_for_city(urlencode(province), api_key)
                temp, rain = parse_city_weather(weather_data)
                print("[+] Province: "+str(province)+" Temperature: "+str(temp)+" Rain Chance: "+str(rain)+" %")
                np[led_index - 1] = weather_to_color(temp, rain)
                np.write()
            print("Weather updated!")
        else:
            print("Skipping update due to Wi-Fi failure")
        await asyncio.sleep(7200)  # Update every 2 hours
def urlencode(string):
    return string.replace(" ", "%20").replace("á", "%C3%A1").replace("é", "%C3%A9").replace("í", "%C3%AD").replace("ó", "%C3%B3").replace("ú", "%C3%BA").replace("ñ", "%C3%B1").replace(",", "%2C")


async def main():
    NUM_LEDS = 31
    LEDS_PIN = 2
    np = neopixel.NeoPixel(Pin(LEDS_PIN), NUM_LEDS)
    PROVINCE_TO_LED_MAP = {  "Santo Domingo,do": 1,
    "San Cristobal,do": 2,
    "Bani,do": 4,
    "Azua,do": 5,
    "San Jose de Ocoa,do": 3,
    "Barahona,do": 6,
    "Pedernales,do": 7,
    "Jimani": 8,
    "Neiba": 9,
    "San Juan de la Maguana,do": 10,
    "Comendador,do": 11,
    "Villa Vasquez,do": 12,
    "Dajabon,do": 13,
    "San Fernando de Monte Cristi,do": 14,
    "Mao,do": 15,
    "Puerto Plata,do": 16,
    "Santiago de los Caballeros": 17,
    "Moca,do": 18,
    "Salcedo,do": 19,
    "Nagua,do": 24,
    "Samana,do": 25,
    "Monte Plata,do": 26,
    "Hato Mayor,do": 27,
    "El Seibo,do": 29,
    "La Romana,do": 30,
    "La Altagracia,do": 31,
    "San Pedro de Macoris": 28,
    "La Vega,do": 20,
    "Bonao,do": 21,
    "Cotui,do": 22,
    "San Francisco de Macoris": 23}  # Add more
    API_KEY = "openweathermap-api-key"
    await update_weather(np, PROVINCE_TO_LED_MAP, API_KEY)

asyncio.run(main())