from machine import Pin, I2C
import network, time
from umqtt.simple import MQTTClient

# ── WiFi ───────────────────────────────────────────────────────────
SSID     = "imayou"
PASSWORD = "_bazz38LOI$"

# ── MQTT ───────────────────────────────────────────────────────────
BROKER    = "broker.hivemq.com"
CLIENT_ID = b"c3-max30102"
TOPIC_BPM = b"berceau/135701/bpm_optique"
TOPIC_SPO = b"berceau/135701/spo2"

# ── MAX30102 ───────────────────────────────────────────────────────
i2c           = I2C(0, sda=Pin(8), scl=Pin(9), freq=400000)
MAX30102_ADDR = 0x57

def max30102_init():
    i2c.writeto_mem(MAX30102_ADDR, 0x09, b'\x40')  # Reset
    time.sleep_ms(100)
    i2c.writeto_mem(MAX30102_ADDR, 0x09, b'\x03')  # Mode SpO2
    i2c.writeto_mem(MAX30102_ADDR, 0x0A, b'\x27')  # Config SpO2
    i2c.writeto_mem(MAX30102_ADDR, 0x0C, b'\x1F')  # LED Rouge
    i2c.writeto_mem(MAX30102_ADDR, 0x0D, b'\x1F')  # LED IR
    i2c.writeto_mem(MAX30102_ADDR, 0x08, b'\x40')  # FIFO config
    i2c.writeto_mem(MAX30102_ADDR, 0x04, b'\x00')  # Reset FIFO
    i2c.writeto_mem(MAX30102_ADDR, 0x05, b'\x00')
    i2c.writeto_mem(MAX30102_ADDR, 0x06, b'\x00')
    print("MAX30102 initialise")

def max30102_lire():
    try:
        data  = i2c.readfrom_mem(MAX30102_ADDR, 0x07, 6)
        rouge = ((data[0] & 0x03) << 16) | (data[1] << 8) | data[2]
        ir    = ((data[3] & 0x03) << 16) | (data[4] << 8) | data[5]
        return rouge, ir
    except:
        return 0, 0

def calculer_bpm_spo2(nb_mesures=50):
    vals_rouge = []
    vals_ir    = []
    for _ in range(nb_mesures):
        r, i = max30102_lire()
        if r > 5000 and i > 5000:
            vals_rouge.append(r)
            vals_ir.append(i)
        time.sleep_ms(20)

    if len(vals_ir) < 10:
        return 0, 0  # Pas de signal

    # Calcul SpO2
    dc_r  = sum(vals_rouge) / len(vals_rouge)
    dc_i  = sum(vals_ir)    / len(vals_ir)
    ac_r  = max(vals_rouge) - min(vals_rouge)
    ac_i  = max(vals_ir)    - min(vals_ir)

    if dc_r == 0 or dc_i == 0 or ac_i == 0:
        return 0, 0

    ratio = (ac_r / dc_r) / (ac_i / dc_i)
    spo2  = max(0, min(100, 110 - 25 * ratio))

    # Calcul BPM
    moy    = dc_i
    pics   = 0
    en_pic = False
    for v in vals_ir:
        if v > moy * 1.01 and not en_pic:
            pics  += 1
            en_pic = True
        elif v < moy:
            en_pic = False

    duree_s = nb_mesures * 0.02
    bpm     = int((pics / duree_s) * 60) if duree_s > 0 else 0

    return round(bpm, 1), round(spo2, 1)

# ── WiFi ───────────────────────────────────────────────────────────
def connecter_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print("Connexion WiFi...")
        wlan.connect(SSID, PASSWORD)
        timeout = 15
        while not wlan.isconnected() and timeout > 0:
            time.sleep(1)
            timeout -= 1
    if wlan.isconnected():
        print("WiFi OK :", wlan.ifconfig()[0])
        return True
    print("WiFi ECHEC")
    return False

# ── MQTT ───────────────────────────────────────────────────────────
mqtt_client = None

def connecter_mqtt():
    global mqtt_client
    try:
        mqtt_client = MQTTClient(CLIENT_ID, BROKER, port=1883, keepalive=60)
        mqtt_client.connect()
        print("MQTT OK")
        return True
    except Exception as e:
        print("MQTT erreur :", e)
        return False

def publier(topic, valeur):
    global mqtt_client
    try:
        mqtt_client.publish(topic, str(valeur).encode())
    except:
        print("Reconnexion MQTT...")
        connecter_mqtt()

# ── Démarrage ──────────────────────────────────────────────────────
connecter_wifi()
connecter_mqtt()
max30102_init()

print("Surveillance démarrée...")

last_publish = 0
INTERVAL     = 5000  # toutes les 5 secondes

while True:
    now = time.ticks_ms()

    if time.ticks_diff(now, last_publish) >= INTERVAL:
        bpm, spo2 = calculer_bpm_spo2(nb_mesures=50)
        print(f"BPM: {bpm}  SpO2: {spo2}%")

        if bpm > 0 and spo2 > 0:
            publier(TOPIC_BPM, bpm)
            publier(TOPIC_SPO, spo2)
        else:
            print("Pas de signal")

        last_publish = now

    time.sleep_ms(100)