import network
import time
import machine
import dht
import urequests

# --- 1. INITIALIZE HARDWARE ---
LED = machine.Pin("LED", machine.Pin.OUT)

# --- 2. CONFIGURATION ---
SSID = 'YOUR_WIFI_SSID'  # Replace with your WiFi SSID
PASSWORD = 'YOUR_WIFI_PASSWORD'  # Replace with your WiFi password
THINGSPEAK_API_KEY = 'YOUR_API_KEY'  # Replace with your API key
THINGSPEAK_URL = 'http://api.thingspeak.com/update'

DHT_PIN = machine.Pin(15)
HALL_PIN = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)

MM_PER_TIP = 0.173  
UPLOAD_INTERVAL = 30 * 60 * 1000  
RAIN_IDLE_TIMEOUT = 20 * 1000     
KEEP_ALIVE_INTERVAL = 10 * 1000   

# --- 3. GLOBAL VARIABLES ---
tip_count = 0
last_tip_time = 0
next_upload_time = time.ticks_ms() + UPLOAD_INTERVAL
last_rain_activity_time = 0 

# This list will store data if WiFi fails
data_backlog = []

dht_sensor = dht.DHT11(DHT_PIN)
wlan = network.WLAN(network.STA_IF)

# --- 4. HELPER FUNCTIONS ---

def heartbeat(seconds):
    """Keep power bank alive with constant blinking."""
    end_time = time.ticks_add(time.ticks_ms(), int(seconds * 1000))
    while time.ticks_diff(end_time, time.ticks_ms()) > 0:
        LED.toggle()
        time.sleep_ms(100)

def send_to_thingspeak(t, h, rain):
    """Standard HTTP GET to ThingSpeak."""
    try:
        url = f"{THINGSPEAK_URL}?api_key={THINGSPEAK_API_KEY}&field1={t}&field2={h}&field3={rain}"
        res = urequests.get(url)
        print(f">> Success: {res.text}")
        res.close()
        return True
    except:
        return False

def connect_and_process_backlog(current_t, current_h, current_rain):
    """Try 5 times to connect. If success, send backlog + current data."""
    wlan.active(True)
    attempts = 0
    connected = False
    
    while attempts < 5 and not connected:
        attempts += 1
        print(f">> WiFi Attempt {attempts}/5...")
        wlan.connect(SSID, PASSWORD)
        
        # Wait 10 seconds for connection per attempt
        wait = 10
        while wait > 0 and not wlan.isconnected():
            LED.toggle()
            time.sleep_ms(200)
            wait -= 0.2
            
        if wlan.isconnected():
            connected = True
            print(">> WiFi Connected!")
        else:
            print(">> Attempt failed. Waiting to retry...")
            heartbeat(2) # Keep power bank alive between attempts

    if connected:
        # 1. Send all stored previous data first
        if len(data_backlog) > 0:
            print(f">> Sending {len(data_backlog)} stored readings...")
            for item in data_backlog[:]: # Iterate over a copy
                # ThingSpeak needs ~15s between uploads
                if send_to_thingspeak(item['t'], item['h'], item['r']):
                    data_backlog.remove(item)
                    heartbeat(16) # Mandatory delay for ThingSpeak
                
        # 2. Send the current data
        send_to_thingspeak(current_t, current_h, current_rain)
        wlan.active(False)
        return True
    else:
        print(">> All 5 attempts failed. Storing data for later.")
        data_backlog.append({'t': current_t, 'h': current_h, 'r': current_rain})
        wlan.active(False)
        return False

# --- 5. INTERRUPT HANDLER ---
def hall_interrupt_handler(pin):
    global tip_count, last_tip_time, last_rain_activity_time
    current_time = time.ticks_ms()
    if time.ticks_diff(current_time, last_tip_time) > 500:
        tip_count += 1
        last_tip_time = current_time
        last_rain_activity_time = current_time 

HALL_PIN.irq(trigger=machine.Pin.IRQ_RISING, handler=hall_interrupt_handler)

# --- 6. MAIN LOOP ---
print("--- DEPLOYMENT: STORE & FORWARD MODE ---")
heartbeat(2)

while True:
    now = time.ticks_ms()
    
    # 1. UPLOAD LOGIC
    if time.ticks_diff(next_upload_time, now) <= 0:
        try:
            dht_sensor.measure()
            t, h = dht_sensor.temperature(), dht_sensor.humidity()
        except:
            t, h = 0, 0
        
        rain_mm = (tip_count * 2) * MM_PER_TIP
        
        # Try to connect and send (this handles the 5 attempts)
        connect_and_process_backlog(t, h, rain_mm)
        
        # Always move the timer forward by 30 mins, even if it failed
        next_upload_time = time.ticks_add(time.ticks_ms(), UPLOAD_INTERVAL)

    # 2. KEEP ALIVE LOGIC (Always blinking)
    now = time.ticks_ms()
    time_since_rain = time.ticks_diff(now, last_rain_activity_time)
    
    if time_since_rain > RAIN_IDLE_TIMEOUT:
        LED.toggle()
        time.sleep_ms(500) # Constant slow heartbeat
        
        # Periodic pulse to reset power bank timer every 10s
        if time.ticks_diff(now, last_tip_time) > KEEP_ALIVE_INTERVAL:
            wlan.active(True)
            heartbeat(2)
            wlan.active(False)
            last_tip_time = now
    else:
        LED.toggle()
        time.sleep_ms(200) # Fast heartbeat during rain