# MicroPython ESP32 - Guardián Fénix
# Sensores: BME680 + ADXL345
# Servidor web para mostrar datos y registros

import machine, time, ujson, network, socket, math
from machine import Pin, I2C
import bme680  # Asegúrate de tener la librería BME680 para MicroPython
import adxl345

# -------------------
# CONFIGURACIÓN SENSORES
# -------------------
i2c = I2C(scl=Pin(5), sda=Pin(4))

# BME680
bme = bme680.BME680(i2c)

# ADXL345
acc = adxl345.ADXL345(i2c)

# -------------------
# CONFIGURACIÓN WIFI (HOTSPOT)
# -------------------
ssid = "GuardianFenix"
password = "12345678"

ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid=ssid, password=password)

print("Hotspot activo:", ssid)

# -------------------
# VARIABLES
# -------------------
registros = []  # Lista de registros
aceptar_vib = False
alerta_activa = False

# -------------------
# FUNCIONES DE SENSORES
# -------------------
def leer_bme680():
    bme.measure(gas=False)
    temp = bme.temperature()
    hum  = bme.humidity()
    pres = bme.pressure()
    return {"temp": round(temp,1), "hum": round(hum,1), "pres": round(pres,1)}

def leer_adxl345():
    x, y, z = acc.read_g()  # m/s²
    vib = abs((x*2 + y*2 + z*2) * 2)
    estado = "Estable"
    global alerta_activa
    if vib > 6:
        estado = "Inestable"
        alerta_activa = True
    else:
        alerta_activa = False
    return {"vib": round(vib,2), "estado": estado}

# -------------------
# REGISTRO AUTOMÁTICO
# -------------------
def registrar():
    datos = leer_bme680()
    vib = leer_adxl345()
    datos["vib"] = vib["vib"]
    datos["estado"] = vib["estado"]
    datos["hora"] = time.localtime()[3:6]  # HH:MM:SS
    registros.append(datos)
    # Mantener solo últimos 100 registros
    if len(registros) > 100:
        registros.pop(0)
    return datos

# -------------------
# SERVIDOR WEB
# -------------------
def web_page():
    return """<!doctype html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Guardián Fénix</title>
  <style>
    body{font-family:Arial,sans-serif;background:#fdf2f2;color:#333;margin:16px}
    h1{margin:8px 0 16px 0}
    .card{background:#fff;padding:16px;margin:12px 0;border-radius:12px;box-shadow:0 4px 10px rgba(0,0,0,.12);}
    button{background:#c62828;color:#fff;border:none;padding:10px 14px;border-radius:8px;cursor:pointer;margin:6px 6px 0 0;}
    .row{display:flex;flex-wrap:wrap;gap:12px}
    .stat{min-width:160px}
    .big{font-size:28px;font-weight:700}
    table{width:100%;border-collapse:collapse;font-size:.9em;margin-top:10px}
    th,td{border:1px solid #ccc;padding:6px;text-align:center}
    th{background:#f3d6d6}
    .mono{font-family:ui-monospace,Menlo,Consolas,monospace}
  </style>
</head>
<body>
  <h1>🛡️ Guardián Fénix 🔥</h1>

  <div class="card">
    <h2>🌿 Sensor Ambiental (BME680)</h2>
    <div class="row">
      <div class="stat"><div>Temp</div><div class="big"><span id="temp">--</span> °C</div></div>
      <div class="stat"><div>Hum</div><div class="big"><span id="hum">--</span> %</div></div>
      <div class="stat"><div>Pres</div><div class="big"><span id="pres">--</span> hPa</div></div>
      <div class="stat"><div>Gas</div><div class="big"><span id="gas">--</span> Ω</div></div>
    </div>
  </div>

  <div class="card">
    <h2>📳 Vibración (ADXL345)</h2>
    <div class="row">
      <div class="stat"><div>Shake</div><div class="big"><span id="shake">--</span></div></div>
      <div class="stat mono">ax=<span id="ax">--</span>g</div>
      <div class="stat mono">ay=<span id="ay">--</span>g</div>
      <div class="stat mono">az=<span id="az">--</span>g</div>
    </div>
  </div>

  <div class="card">
    <h2>📝 Registros</h2>
    <button id="btnNow">Leer ahora</button>
    <button id="btnLog">Guardar registro</button>
    <button id="btnClear">Borrar último</button>

    <table>
      <thead>
        <tr>
          <th>#</th><th>Hora</th><th>Temp</th><th>Hum</th><th>Pres</th><th>Gas</th><th>Shake</th>
        </tr>
      </thead>
      <tbody id="tabla"></tbody>
    </table>
  </div>

<script>
  const el = (id)=>document.getElementById(id);

  function setText(id, v) {
    el(id).textContent = (v===null || v===undefined) ? "--" : v;
  }

  function drawTable(list) {
    const tb = el("tabla");
    tb.innerHTML = "";
    const last = list.slice(-20); // show last 20
    last.forEach((r, i) => {
      const hora = Array.isArray(r.hora) ? `${r.hora[0]}:${r.hora[1]}:${r.hora[2]}` : "--";
      tb.innerHTML += `
        <tr>
          <td>${list.length - last.length + i + 1}</td>
          <td>${hora}</td>
          <td>${r.temp ?? "--"}</td>
          <td>${r.hum ?? "--"}</td>
          <td>${r.pres ?? "--"}</td>
          <td>${r.gas ?? "--"}</td>
          <td>${r.shake ?? r.vib ?? "--"}</td>
        </tr>`;
    });
  }

  async function refresh() {
    try {
      const r = await fetch("/data");
      const d = await r.json();

      // If /data returns a single object:
      if (!Array.isArray(d)) {
        setText("temp", d.temp ?? d.t_c);
        setText("hum",  d.hum  ?? d.h_pct);
        setText("pres", d.pres ?? d.p_hpa);
        setText("gas",  d.gas  ?? d.gas_ohms);

        setText("ax", d.ax);
        setText("ay", d.ay);
        setText("az", d.az);
        setText("shake", d.shake ?? d.vib);

        return;
      }

      // If /data returns the whole registros list:
      drawTable(d);
      const last = d[d.length-1];
      if (last) {
        setText("temp", last.temp);
        setText("hum", last.hum);
        setText("pres", last.pres);
        setText("gas", last.gas);
        setText("shake", last.shake ?? last.vib);
      }
    } catch (e) {
      console.log("refresh error", e);
    }
  }

  // Buttons call your endpoints AND then refresh screen
  el("btnNow").onclick = async () => { await fetch("/leer"); await refresh(); };
  el("btnLog").onclick = async () => { await fetch("/guardar"); await refresh(); };
  el("btnClear").onclick = async () => { await fetch("/borrar"); await refresh(); };

  setInterval(refresh, 1000);
  refresh();
</script>
</body>
</html>"""

# -------------------
# SERVIDOR
# -------------------
addr = socket.getaddrinfo('192.168.4.1',80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(5)
print('Servidor escuchando en', addr)

def handle_client(cl):
    try:
        req = cl.recv(1024)
        req = str(req)
        if 'GET /data' in req:
            res = ujson.dumps(registros)
            cl.send('HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n')
            cl.send(res)
        elif 'GET /leer' in req:
            d = registrar()
            cl.send('HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n')
            cl.send(ujson.dumps(d))
        elif 'GET /guardar' in req:
            d = registrar()
            cl.send('HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n')
            cl.send(ujson.dumps(d))
        elif 'GET /borrar' in req:
            if registros:
                registros.pop()
            cl.send('HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n')
            cl.send(ujson.dumps(registros))
        elif 'GET /toggle' in req:
            global aceptar_vib
            aceptar_vib = not aceptar_vib
            cl.send('HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n')
            cl.send(ujson.dumps({"aceptar_vib":aceptar_vib}))
        else:
            cl.send('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n')
            cl.send(web_page())
    except Exception as e:
        print("Error:", e)
    cl.close()

# Loop principal
while True:
    registrar()
    cl, addr = s.accept()
    handle_client(cl)