#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import machine
import time
import uos
from machine import Pin, PWM
import sh1106
import neopixel

# -----------------------------------------------------------------------------
# 1. CONFIGURATION MATÉRIELLE (RP2040 / PICO ZERO)
# - R sur GP8 (Slice 4)
# - G sur GP9 (Slice 4)
# - B sur GP12 (Slice 6)
# - Modulation sur GP11 (Slice 5)
# - LED témoin externe sur GP29
# - NeoPixel sur GP16
# -----------------------------------------------------------------------------

# OLED 1.3" SH1106 en I2C matériel (SCL sur GP5, SDA sur GP4, 100kHz stable)
i2c = machine.I2C(0, scl=Pin(5), sda=Pin(4), freq=100000)
oled = sh1106.SH1106_I2C(128, 64, i2c, res=None, addr=0x3C, rotate=180)

# Écran de démarrage : Affichage "Gestion RGB" pendant 2 secondes
oled.fill(0)
oled.text("Gestion RGB", 24, 28, 1)
oled.show()
time.sleep(2)

# ENCODEUR ROTATIF (CLK=GP14, DT=GP15, SW=GP2)
pin_clk = Pin(14, Pin.IN, Pin.PULL_UP)
pin_dt = Pin(15, Pin.IN, Pin.PULL_UP)
pin_sw = Pin(2, Pin.IN, Pin.PULL_UP)

# PWM LEDS RGB (R sur GP8, G sur GP9, B sur GP12 - GP16 réservé NeoPixel)
pwm_r = PWM(Pin(8))
pwm_g = PWM(Pin(9))
pwm_b = PWM(Pin(12))

for p in (pwm_r, pwm_g, pwm_b):
    p.freq(1000)  # Fréquence PWM de base des LEDs (1kHz stable)

# BROCHE DE MODULATION SUR GP11 (Indépendant, Slice 5)
pwm_mod = PWM(Pin(11))
pwm_mod.duty_u16(32768)  # Duty cycle à 50% par défaut

# LED NEOPIXEL WS2812 SUR GP16
np = neopixel.NeoPixel(Pin(16), 1)

# LED TÉMOIN EXTERNE SUR GP29
pin_temoin = Pin(29, Pin.OUT)
pin_temoin.value(0)

# Dictionnaire élargi (couleurs pures + couleurs intermédiaires)
COLOR_NAMES = {
    "rouge": (255, 0, 0),
    "orange": (255, 128, 0),
    "ambre": (255, 191, 0),
    "jaune": (255, 255, 0),
    "lime": (128, 255, 0),
    "vert": (0, 255, 0),
    "turquoise": (64, 224, 208),
    "cyan": (0, 255, 255),
    "bleu": (0, 0, 255),
    "violet": (128, 0, 255),
    "magenta": (255, 0, 255),
    "rose": (255, 105, 180),
    "blanc": (255, 255, 255),
    "noir": (0, 0, 0)
}

# -----------------------------------------------------------------------------
# 2. GESTION DES MESSAGES SUR L'OLED (Max 16 caractères par ligne)
# -----------------------------------------------------------------------------
def show_message(title, msg, duration_sec=2.0):
    """Affiche un message ou une erreur sur l'écran OLED."""
    oled.fill(0)
    oled.text(f"[{title}]", 0, 0, 1)
    
    oled.text(msg[:16], 0, 20, 1)
    if len(msg) > 16:
        oled.text(msg[16:32], 0, 35, 1)
        
    oled.text("Appuyer...", 0, 52, 1)
    oled.show()
    
    start = time.time()
    while time.time() - start < duration_sec:
        if pin_sw.value() == 0:
            time.sleep_ms(50)
            while pin_sw.value() == 0:
                time.sleep_ms(10)
            break
        time.sleep_ms(10)

# -----------------------------------------------------------------------------
# 3. PARAMÈTRES ET EEPROM (MÉMOIRE FLASH INTERNE)
# -----------------------------------------------------------------------------
PARAM_FILE = "eeprom_config.dat"

config = {
    "r": 0,             
    "g": 0,             
    "b": 255,           
    "duration": 5,
    "freq_mod": 10.0,   
    "file_name": "config.txt",
    "intensity": 100.0,
    "r_coef": 100.0,    # Coefficient R en %
    "g_coef": 100.0,    # Coefficient G en %
    "b_coef": 100.0     # Coefficient B en %
}

leds_state = False  # État courant des LEDs (Allumées/Éteintes)

# Table de correction Gamma (2.8) pour un rendu visuel fidèle
GAMMA_TABLE = [int(((i / 255.0) ** 2.8) * 65535) for i in range(256)]

def save_to_eeprom():
    """Sauvegarde les paramètres courants et coefficients dans la mémoire Flash."""
    try:
        state_val = 1 if leds_state else 0
        with open(PARAM_FILE, "w") as f:
            f.write(f"{config['r']},{config['g']},{config['b']},{config['duration']},{config['freq_mod']},{config['file_name']},{config['intensity']},{state_val},{config['r_coef']},{config['g_coef']},{config['b_coef']}\n")
        show_message("EEPROM", "Sauvegarde OK!", 1.5)
    except Exception as e:
        show_message("Erreur EEP", str(e)[:16], 2.0)

def load_from_eeprom():
    global config, leds_state
    try:
        with open(PARAM_FILE, "r") as f:
            data = f.readline().strip().split(",")
            if len(data) >= 8:
                config["r"] = int(data[0])
                config["g"] = int(data[1])
                config["b"] = int(data[2])
                config["duration"] = int(data[3])
                config["freq_mod"] = max(0.0, float(data[4]))
                config["file_name"] = data[5]
                config["intensity"] = float(data[6])
                leds_state = True if int(data[7]) == 1 else False
            if len(data) >= 11:
                config["r_coef"] = float(data[8])
                config["g_coef"] = float(data[9])
                config["b_coef"] = float(data[10])
    except:
        pass

load_from_eeprom()

# Gestion de la fréquence PWM initiale de modulation
def apply_freq(freq):
    """Met à jour la fréquence ou positionne à 1 (duty 65535) si 0."""
    if freq > 0:
        safe_freq = max(10, int(freq))
        pwm_mod.freq(safe_freq)
        pwm_mod.duty_u16(32768)  # Signal carré à 50%
    else:
        pwm_mod.duty_u16(65535)

if config["freq_mod"] > 0:
    apply_freq(config["freq_mod"])
else:
    apply_freq(0)

# -----------------------------------------------------------------------------
# 4. GESTION DE L'ENCODEUR ROTATIF
# -----------------------------------------------------------------------------
encoder_ticks = 0
last_clk = pin_clk.value()

def encoder_isr(pin):
    global encoder_ticks, last_clk
    clk_val = pin_clk.value()
    if clk_val != last_clk and clk_val == 0:
        if pin_dt.value() != clk_val:
            encoder_ticks += 1
        else:
            encoder_ticks -= 1
    last_clk = clk_val

pin_clk.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=encoder_isr)

def get_button_click():
    if pin_sw.value() == 0:
        time.sleep_ms(50)
        if pin_sw.value() == 0:
            while pin_sw.value() == 0:
                time.sleep_ms(10)
            return True
    return False

# -----------------------------------------------------------------------------
# 5. FONCTIONS COULEURS, SPECTRE & NEOPIXEL
# -----------------------------------------------------------------------------
current_r, current_g, current_b = 0, 0, 0
last_np_color = (-1, -1, -1)

def wheel(pos):
    """Génère les couleurs du spectre solaire (0 à 255)."""
    pos = pos % 256
    if pos < 85:
        return (pos * 3, 255 - pos * 3, 0)
    elif pos < 170:
        pos -= 85
        return (255 - pos * 3, 0, pos * 3)
    else:
        pos -= 170
        return (0, pos * 3, 255 - pos * 3)

def get_hue_from_rgb(r, g, b):
    """Retrouve la position sur la roue chromatique (hue) la plus proche."""
    best_hue = 0
    min_diff = 999999
    for h in range(256):
        wr, wg, wb = wheel(h)
        diff = abs(wr - r) + abs(wg - g) + abs(wb - b)
        if diff < min_diff:
            min_diff = diff
            best_hue = h
    return best_hue

def apply_rgb(r, g, b, intensity=100.0):
    global current_r, current_g, current_b, last_np_color
    factor = max(0.0, min(100.0, intensity)) / 100.0
    
    rc = config.get("r_coef", 100.0) / 100.0
    gc = config.get("g_coef", 100.0) / 100.0
    bc = config.get("b_coef", 100.0) / 100.0
    
    scaled_r = int(r * factor * rc)
    scaled_g = int(g * factor * gc)
    scaled_b = int(b * factor * bc)
    
    current_r = max(0, min(255, scaled_r))
    current_g = max(0, min(255, scaled_g))
    current_b = max(0, min(255, scaled_b))
    
    pwm_r.duty_u16(GAMMA_TABLE[current_r])
    pwm_g.duty_u16(GAMMA_TABLE[current_g])
    pwm_b.duty_u16(GAMMA_TABLE[current_b])
    
    new_color = (current_r, current_g, current_b)
    if new_color != last_np_color:
        try:
            np[0] = new_color
            np.write()
            last_np_color = new_color
        except:
            pass

def fade_to_color(target_r, target_g, target_b, target_intensity, duration_ms=1000):
    """Fondu progressif vers la couleur et l'intensité cibles."""
    global current_r, current_g, current_b
    steps = 50
    delay = duration_ms // steps
    
    start_r, start_g, start_b = current_r, current_g, current_b
    
    factor = target_intensity / 100.0
    rc = config.get("r_coef", 100.0) / 100.0
    gc = config.get("g_coef", 100.0) / 100.0
    bc = config.get("b_coef", 100.0) / 100.0
    
    final_target_r = int(target_r * factor * rc)
    final_target_g = int(target_g * factor * gc)
    final_target_b = int(target_b * factor * bc)
    
    for i in range(1, steps + 1):
        if get_button_click():
            return False
            
        r = int(start_r + (final_target_r - start_r) * i / steps)
        g = int(start_g + (final_target_g - start_g) * i / steps)
        b = int(start_b + (final_target_b - start_b) * i / steps)
        
        pwm_r.duty_u16(GAMMA_TABLE[max(0, min(255, r))])
        pwm_g.duty_u16(GAMMA_TABLE[max(0, min(255, g))])
        pwm_b.duty_u16(GAMMA_TABLE[max(0, min(255, b))])
        
        try:
            np[0] = (max(0, min(255, r)), max(0, min(255, g)), max(0, min(255, b)))
            np.write()
        except:
            pass
            
        time.sleep_ms(delay)
        
    apply_rgb(target_r, target_g, target_b, target_intensity)
    return True

def toggle_leds_manual():
    """Allumage / Extinction manuelle des LEDs via appui long dans le menu."""
    global leds_state
    leds_state = not leds_state
    if leds_state:
        pin_temoin.value(1)
        apply_rgb(config["r"], config["g"], config["b"], config["intensity"])
        apply_freq(config["freq_mod"])
        show_message("LEDs", "Allumees", 1.0)
    else:
        pin_temoin.value(0)
        apply_rgb(0, 0, 0, 0)
        apply_freq(0)
        show_message("LEDs", "Eteintes", 1.0)

def run_txt_program():
    """Activation et lecture du fichier .TXT avec f.seek(0) pour LOOP et résolution 100ms."""
    file_path = config["file_name"]
    try:
        pin_temoin.value(1)
        with open(file_path, "r") as f:
            while True:
                line = f.readline()
                if not line:
                    break
                
                line = line.strip()
                if not line or line.startswith("#"):
                    continue
                
                if "#" in line:
                    clean_line = line.split("#")[0].strip()
                else:
                    clean_line = line
                    
                if not clean_line:
                    continue
                
                if clean_line.upper() == "LOOP" or clean_line.upper().startswith("LOOP"):
                    f.seek(0)
                    continue
                
                parts = [p.strip() for p in clean_line.split(",") if p.strip() != ""]
                if not parts:
                    continue
                
                token = parts[0].lower()
                target_r, target_g, target_b = 0, 0, 0
                dur = 5.0
                freq = config["freq_mod"]
                file_intensity = config["intensity"]
                
                if token in COLOR_NAMES:
                    target_r, target_g, target_b = COLOR_NAMES[token]
                    if len(parts) > 1:
                        try: dur = float(parts[1])
                        except: pass
                    if len(parts) > 2:
                        try: freq = float(parts[2])
                        except: pass
                    if len(parts) > 3:
                        try: file_intensity = float(parts[3])
                        except: pass
                else:
                    if len(parts) >= 3:
                        try:
                            target_r = max(0, min(255, int(parts[0])))
                            target_g = max(0, min(255, int(parts[1])))
                            target_b = max(0, min(255, int(parts[2])))
                            if len(parts) > 3: dur = max(0.0, float(parts[3]))
                            if len(parts) > 4: freq = float(parts[4])
                            if len(parts) > 5: file_intensity = float(parts[5])
                        except:
                            continue
                    else:
                        continue
                
                apply_freq(freq)
                if freq >= 0:
                    config["freq_mod"] = freq

                if not fade_to_color(target_r, target_g, target_b, file_intensity, 1000):
                    apply_rgb(0, 0, 0, 0)
                    apply_freq(0)
                    pin_temoin.value(0)
                    return
                
                dur_ms = int(dur * 1000)
                start_tick = time.ticks_ms()
                last_remaining_ds = -1
                
                while dur_ms == 0 or time.ticks_diff(time.ticks_ms(), start_tick) < dur_ms:
                    if get_button_click():
                        apply_rgb(0, 0, 0, 0)
                        apply_freq(0)
                        pin_temoin.value(0)
                        return
                    
                    elapsed_ms = time.ticks_diff(time.ticks_ms(), start_tick)
                    remaining_ms = max(0, dur_ms - elapsed_ms) if dur_ms > 0 else elapsed_ms
                    remaining_ds = remaining_ms // 100
                    
                    if remaining_ds != last_remaining_ds or last_remaining_ds == -1:
                        last_remaining_ds = remaining_ds
                        
                        oled.fill(0)
                        oled.text("== EXECUTION ==", 10, 0, 1)
                        if dur_ms > 0:
                            sec_disp = remaining_ms / 1000.0
                            oled.text(f"Temps : {sec_disp:.1f}s", 0, 13, 1)
                        else:
                            sec_disp = elapsed_ms / 1000.0
                            oled.text(f"Temps : {sec_disp:.1f}s", 0, 13, 1)
                            
                        oled.text(f"RGB: {target_r},{target_g},{target_b}", 0, 26, 1)
                        freq_str = "Off" if freq <= 0 else f"{int(freq)}Hz"
                        oled.text(f"{file_intensity:.0f}% {freq_str}", 0, 39, 1)
                        oled.text("Clic: Arreter", 0, 52, 1)
                        oled.show()
                        
                    time.sleep_ms(100)
                
                if dur_ms > 0:
                    oled.fill(0)
                    oled.text("== EXECUTION ==", 10, 0, 1)
                    oled.text("Temps : 0.0s", 0, 13, 1)
                    oled.text(f"RGB: {target_r},{target_g},{target_b}", 0, 26, 1)
                    freq_str = "Off" if freq <= 0 else f"{int(freq)}Hz"
                    oled.text(f"Int:{file_intensity:.0f}% F:{freq_str}", 0, 39, 1)
                    oled.text("Clic: Arreter", 0, 52, 1)
                    oled.show()
                    time.sleep_ms(50)

        fade_to_color(0, 0, 0, 0, 1000)
        apply_freq(0)
        pin_temoin.value(0)
        show_message("Prog Flash", "Fin execution", 1.5)
    except Exception as e:
        apply_rgb(0, 0, 0, 0)
        apply_freq(0)
        pin_temoin.value(0)
        show_message("Erreur Fichier", "Introuvable/Inval", 2.0)

# Application de l'état initial des LEDs au démarrage
if leds_state:
    pin_temoin.value(1)
    apply_rgb(config["r"], config["g"], config["b"], config["intensity"])
    apply_freq(config["freq_mod"])
else:
    pin_temoin.value(0)
    apply_rgb(0, 0, 0, 0)
    apply_freq(0)

# -----------------------------------------------------------------------------
# 6. INTERFACE MENU & CALIBRAGE RVB
# -----------------------------------------------------------------------------
def adjust_frequency():
    """Modifie et applique en temps réel la fréquence de modulation."""
    global encoder_ticks, config
    freq = int(config["freq_mod"])
    encoder_ticks = 0
    apply_freq(freq)
    
    while True:
        ticks = encoder_ticks
        if ticks != 0:
            encoder_ticks = 0
            abs_ticks = abs(ticks)
            if abs_ticks >= 3:
                step = 1000
            elif abs_ticks >= 2:
                step = 100
            else:
                step = 1
                
            if ticks > 0:
                freq = 10 if freq == 0 else freq + step
            else:
                freq -= step
                if freq < 10:
                    freq = 0
                
            freq = max(0, min(200000, freq))
            apply_freq(freq)
            
        oled.fill(0)
        oled.text("< Freq Modulation >", 0, 2, 1)
        freq_str = "Off" if freq == 0 else f"{freq} Hz"
        oled.text(f"Freq: {freq_str}", 0, 18, 1)
        oled.text("Long:>2s (-> Off)", 0, 34, 1)
        oled.text("Clic: Valider", 0, 50, 1)
        oled.show()
        
        if pin_sw.value() == 0:
            time.sleep_ms(50)
            if pin_sw.value() == 0:
                start_time = time.ticks_ms()
                long_pressed = False
                while pin_sw.value() == 0:
                    if time.ticks_diff(time.ticks_ms(), start_time) > 2000:
                        long_pressed = True
                        break
                    time.sleep_ms(10)
                
                if long_pressed:
                    freq = 0
                    apply_freq(freq)
                    while pin_sw.value() == 0:
                        time.sleep_ms(10)
                    config["freq_mod"] = float(freq)
                    show_message("Frequence", "Off (0 Hz)", 1.2)
                    return
                else:
                    config["freq_mod"] = float(freq)
                    show_message("Frequence", f"{freq_str} OK", 1.2)
                    return
                    
        time.sleep_ms(20)

def adjust_rgb_balance():
    """Menu Calibrage RGB (max 100%)."""
    global encoder_ticks, config
    
    color_keys = list(COLOR_NAMES.keys())
    color_idx = 0
    
    r_c = config["r_coef"]
    g_c = config["g_coef"]
    b_c = config["b_coef"]
    
    field_idx = 0
    encoder_ticks = 0
    pin_temoin.value(1)
    
    while True:
        if encoder_ticks != 0:
            if field_idx == 0:
                color_idx = (color_idx + encoder_ticks) % len(color_keys)
            elif field_idx == 1:
                r_c = max(0.0, min(100.0, r_c + encoder_ticks * 5.0))
            elif field_idx == 2:
                g_c = max(0.0, min(100.0, g_c + encoder_ticks * 5.0))
            elif field_idx == 3:
                b_c = max(0.0, min(100.0, b_c + encoder_ticks * 5.0))
            encoder_ticks = 0
        
        config["r_coef"] = r_c
        config["g_coef"] = g_c
        config["b_coef"] = b_c
        
        curr_color_name = color_keys[color_idx]
        cr, cg, cb = COLOR_NAMES[curr_color_name]
        apply_rgb(cr, cg, cb, config["intensity"])
        
        oled.fill(0)
        oled.text("< Calibrage RGB >", 0, 0, 1)
        
        c_sel = ">" if field_idx == 0 else " "
        r_sel = ">" if field_idx == 1 else " "
        g_sel = ">" if field_idx == 2 else " "
        b_sel = ">" if field_idx == 3 else " "
        
        oled.text(f"{c_sel}Col: {curr_color_name[:10]}", 0, 13, 1)
        oled.text(f"{r_sel}Coef R: {r_c:.0f}%", 0, 26, 1)
        oled.text(f"{g_sel}Coef G: {g_c:.0f}%", 0, 39, 1)
        oled.text(f"{b_sel}Coef B: {b_c:.0f}%", 0, 52, 1)
        oled.show()
        
        if pin_sw.value() == 0:
            time.sleep_ms(50)
            if pin_sw.value() == 0:
                start_time = time.ticks_ms()
                long_pressed = False
                while pin_sw.value() == 0:
                    if time.ticks_diff(time.ticks_ms(), start_time) > 500:  # Modifié à 500ms
                        long_pressed = True
                        break
                    time.sleep_ms(10)
                
                if long_pressed:
                    while pin_sw.value() == 0:
                        time.sleep_ms(10)
                    config["r_coef"] = r_c
                    config["g_coef"] = g_c
                    config["b_coef"] = b_c
                    show_message("Calibrage", "Coefs Appliques", 1.2)
                    return
                else:
                    field_idx = (field_idx + 1) % 4
                    while pin_sw.value() == 0:
                        time.sleep_ms(10)
                        
        time.sleep_ms(20)

def adjust_spectrum_and_intensity():
    """Parcours du spectre solaire et choix de l'intensité."""
    global encoder_ticks, config, leds_state
    
    hue = get_hue_from_rgb(config["r"], config["g"], config["b"])
    intensity = config["intensity"]
    focus = 0
    encoder_ticks = 0
    
    pin_temoin.value(1)

    while True:
        if encoder_ticks != 0:
            if focus == 0:
                hue = (hue + encoder_ticks * 4) % 256
            elif focus == 1:
                intensity = max(0.0, min(100.0, intensity + encoder_ticks * 5.0))
            elif focus == 2:
                focus = (focus + encoder_ticks) % 3
            encoder_ticks = 0

        raw_r, raw_g, raw_b = wheel(hue)
        apply_rgb(raw_r, raw_g, raw_b, intensity)

        oled.fill(0)
        oled.text("< Spectre Solaire >", 0, 0, 1)
        oled.text(f"TXT: {raw_r},{raw_g},{raw_b}", 0, 13, 1)
        
        h_sel = ">" if focus == 0 else " "
        i_sel = ">" if focus == 1 else " "
        
        oled.text(f"{h_sel} Hue: {hue}", 0, 27, 1)
        oled.text(f"{i_sel} Int: {intensity:.1f}%", 0, 39, 1)
        
        if focus == 2:
            oled.fill_rect(0, 52, 128, 12, 1)
            oled.text("> Valider", 4, 53, 0)
        else:
            oled.text("  Valider", 4, 53, 1)
            
        oled.show()

        if get_button_click():
            if focus < 2:
                focus += 1
            else:
                config["r"] = raw_r
                config["g"] = raw_g
                config["b"] = raw_b
                config["intensity"] = intensity
                leds_state = True
                apply_freq(config["freq_mod"])
                show_message("Spectre RGB", f"RGB:{raw_r},{raw_g},{raw_b}", 1.5)
                return
        time.sleep_ms(20)

def choose_txt_file():
    """Recherche dynamique des fichiers .txt présents."""
    try:
        all_files = uos.listdir()
        files = [f for f in all_files if f.endswith(".txt")]
    except:
        files = []
    
    if not files:
        show_message("Fichiers TXT", "Aucun trouve !", 2.0)
        return

    idx = 0
    global encoder_ticks
    encoder_ticks = 0
    
    while True:
        if encoder_ticks != 0:
            idx = (idx + encoder_ticks) % len(files)
            encoder_ticks = 0
            
        oled.fill(0)
        oled.text("< Fichier Flash >", 0, 5, 1)
        oled.text("Selectionnez :", 0, 20, 1)
        
        oled.fill_rect(0, 38, 128, 14, 1)
        oled.text("> " + files[idx], 4, 41, 0)
        oled.show()
        
        if get_button_click():
            config["file_name"] = files[idx]
            show_message("Fichier", "Selectionne!", 1.2)
            return
        time.sleep_ms(20)

def main_menu():
    global encoder_ticks, config
    
    menu_items = [
        "Choix fichier",
        "Spectre RGB",
        "Calibrage RGB",
        "Activer prog",
        "Freq modulation",
        "Sauver EEP"
    ]
    
    current_idx = 0
    encoder_ticks = 0

    while True:
        if encoder_ticks != 0:
            current_idx = (current_idx + encoder_ticks) % len(menu_items)
            encoder_ticks = 0

        oled.fill(0)
        
        for i in range(6):
            y_pos = i * 9
            text_line = menu_items[i]
            
            if i == current_idx:
                oled.fill_rect(0, y_pos, 128, 9, 1)
                oled.text("> " + text_line, 2, y_pos + 1, 0)
            else:
                oled.text("  " + text_line, 2, y_pos + 1, 1)

        oled.fill_rect(0, 55, 128, 9, 0)
        oled.hline(0, 54, 128, 1)
        
        f_val = int(config['freq_mod'])
        f_str = "Off" if f_val == 0 else f"{f_val}Hz"
        info_text = f"{f_str} {config['intensity']:.0f}%"
        oled.text(info_text[:16], 2, 55, 1)
        
        oled.show()

        # Gestion du bouton dans le menu principal :
        # - Appui long (> 500ms) : Allume / Éteint les LEDs (On/Off)
        # - Appui court : Valide l'option de menu sélectionnée
        if pin_sw.value() == 0:
            time.sleep_ms(50)
            if pin_sw.value() == 0:
                start_time = time.ticks_ms()
                long_pressed = False
                while pin_sw.value() == 0:
                    if time.ticks_diff(time.ticks_ms(), start_time) > 500:  # Modifié à 500ms
                        long_pressed = True
                        break
                    time.sleep_ms(10)
                
                if long_pressed:
                    while pin_sw.value() == 0:
                        time.sleep_ms(10)
                    toggle_leds_manual()
                else:
                    selected = menu_items[current_idx]
                    
                    if "Choix" in selected:
                        choose_txt_file()
                    elif "Spectre" in selected:
                        adjust_spectrum_and_intensity()
                    elif "Calibrage" in selected:
                        adjust_rgb_balance()
                    elif "Activer" in selected:
                        run_txt_program()
                    elif "Freq" in selected:
                        adjust_frequency()
                    elif "Sauver" in selected:
                        save_to_eeprom()

        time.sleep_ms(30)

if __name__ == "__main__":
    main_menu()