from machine import Pin, I2C
import utime
import network
import urequests
from bme280 import BME280

# ================= CONFIGURATION =================

WIFI_SSID = "IoT@UMT"
WIFI_PASS = "i00t@UMT"
THINGSPEAK_WRITE_KEY = "BHCMM84HWGX8X0C2"

PIN_INTERRUPT = 14
MILIMETER_PER_TIP = 0.40

I2C_ID = 0
SDA_PIN = 0
SCL_PIN = 1

KEEP_ALIVE_PIN = 15       # Keeps power bank alive
STATUS_LED = "LED"        # Pico W onboard LED

# ================= GLOBAL VARIABLES =================
jumlah_tip = 0
curah_hujan_accumulated = 0.0
curah_hujan_per_menit = 0.0

# Timers
last_tip_time = 0
last_report_time = 0      # For ThingSpeak
last_pulse_time = 0       # For Power Bank

# ================= HARDWARE SETUP =================
keep_alive = Pin(KEEP_ALIVE_PIN, Pin.OUT)
led = Pin(STATUS_LED, Pin.OUT)

# ================= WIFI FUNCTIONS =================
def init_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    
    # 1. Scan to see if the Pico can even SEE the network
    print(f"Scanning for {WIFI_SSID}...")
    networks = wlan.scan()
    found = False
    for n in networks:
        ssid_name = n[0].decode()
        if ssid_name == WIFI_SSID:
            print(f"Network found! RSSI: {n[3]} dBm (Signal Strength)")
            found = True
            break
            
    if not found:
        print(f"ERROR: Could not find network '{WIFI_SSID}'. Check if it is 5GHz only.")
        return None

    # 2. Attempt Connection
    wlan.connect(WIFI_SSID, WIFI_PASS)
    print("Connecting...")
    
    max_wait = 15
    while max_wait > 0:
        status = wlan.status()
        if status < 0 or status >= 3:
            break
        max_wait -= 1
        print(f"Waiting... Status Code: {status}")
        utime.sleep(1)

    # 3. Interpret Result
    status = wlan.status()
    if status == 3:
        print("Connected:", wlan.ifconfig())
        return wlan
    elif status == -3:
        print("LOGIN FAILED (Bad Auth): Check Password or MAC Address Whitelist.")
    elif status == -1:
        print("CONNECTION FAILED: Generic Failure.")
    elif status == -2:
        print("NO NETWORK: Network was found but disappeared.")
    else:
        print(f"Failed with Status Code: {status}")
        
    return None
# ================= I2C & SENSOR =================
i2c = I2C(I2C_ID, sda=Pin(SDA_PIN), scl=Pin(SCL_PIN), freq=400000)
try:
    bme = BME280(i2c=i2c)
except Exception as e:
    print("BME Error:", e)
    bme = None

# ================= RAIN GAUGE INTERRUPT =================
# We use a list for the flag so it is mutable inside the interrupt
rain_data = {'flag': False, 'count': 0} 

def rain_interrupt_handler(pin):
    # Just set the flag, do calculations in main loop to prevent blocking
    rain_data['flag'] = True

rain_pin = Pin(PIN_INTERRUPT, Pin.IN, Pin.PULL_UP)
rain_pin.irq(trigger=Pin.IRQ_FALLING, handler=rain_interrupt_handler)

# ================= HELPER FUNCTIONS =================
def powerbank_keep_alive():
    # Only pulse every 10 seconds to save processing time
    global last_pulse_time
    if utime.ticks_diff(utime.ticks_ms(), last_pulse_time) > 1800000: # 30min
        keep_alive.on()
        utime.sleep_ms(100)
        keep_alive.off()
        last_pulse_time = utime.ticks_ms()

def send_to_thingspeak(temp, hum, pres, rain):
    print(f"Sending: T={temp}, H={hum}, P={pres}, Rain={rain}")
    try:
        # BME library often returns strings like "25C". 
        # ThingSpeak needs numbers. We try to strip characters if needed.
        # If your library returns floats, this is fine.
        
        url = (
            "https://api.thingspeak.com/update?"
            f"api_key={THINGSPEAK_WRITE_KEY}"
            f"&field1={temp}"
            f"&field2={hum}"
            f"&field3={pres}"
            f"&field4={rain}"
        )
        r = urequests.get(url)
        print("ThingSpeak Response:", r.text)
        r.close()
    except Exception as e:
        print("Error sending data:", e)

# ================= MAIN LOOP =================
print("System Starting...")

# 1. Connect WiFi ONCE at the start
wlan = init_wifi()

while True:
    current_ms = utime.ticks_ms()

    # ----- POWER BANK KEEP ALIVE (Non-blocking) -----
    powerbank_keep_alive()

    # ----- STATUS LED LOGIC (Modified) -----
    # Check if wlan object exists AND is connected
    if wlan and wlan.isconnected():
        # WIFI CONNECTED: Blink every 1 second
        if (current_ms // 500) % 2 == 0:
            led.on()
        else:
            led.off()
    else:
        # WIFI DISCONNECTED: Force LED OFF
        led.off()

    # ----- PROCESS RAIN INTERRUPT -----
    if rain_data['flag']:
        # Debounce: Ensure 200ms has passed since last tip
        if utime.ticks_diff(current_ms, last_tip_time) > 200:
            jumlah_tip += 1
            curah_hujan_accumulated += MILIMETER_PER_TIP
            print(f"Rain Tipped! Total: {curah_hujan_accumulated} mm")
            last_tip_time = current_ms
        
        rain_data['flag'] = False

    # ----- REPORT TO THINGSPEAK (Every 30 Seconds) -----
    if utime.ticks_diff(current_ms, last_report_time) > 30000: # 30s
        
        # 1. Reconnect Logic (Updated for safety)
        # If wlan is None (init failed) OR not connected
        if wlan is None or not wlan.isconnected():
            print("WiFi lost/missing, attempting to reconnect...")
            # We must update the 'wlan' variable with the result of init_wifi
            wlan = init_wifi() 

        # 2. Only proceed if we actually have a connection now
        if wlan and wlan.isconnected():
            # Get Sensor Data
            temp, hum, pres = 0, 0, 0
            if bme:
                try:
                    t_raw = bme.values[0]
                    h_raw = bme.values[2]
                    p_raw = bme.values[1]
                    
                    temp = t_raw.replace("C", "")
                    hum = h_raw.replace("%", "")
                    pres = p_raw.replace("hPa", "")
                except:
                    try:
                        temp = bme.temperature
                        hum = bme.humidity
                        pres = bme.pressure
                    except:
                        pass
            
            # Send Data
            send_to_thingspeak(temp, hum, pres, curah_hujan_accumulated)
            
            # Reset Rain Counter
            curah_hujan_accumulated = 0.0
            
            last_report_time = current_ms
        else:
            print("Skipping report: No WiFi connection.")
            # Reset timer so we try again in 30s, or you can set it to retry sooner
            last_report_time = current_ms 

    utime.sleep_ms(50)


