6 – Proyecto RaspyAlarma – Panel web local de lecturas

En la práctica anterior has preparado tu Raspberry Pi para que lea datos de un sensor con Python y los almacene automáticamente en una base de datos MariaDB llamada raspialarm.

Ahora toca construir la siguiente pieza del sistema: un visualizador web en PHP que permita consultar las lecturas almacenadas.

El objetivo es que tu Raspberry no solo capture y guarde información, sino que además pueda mostrarla en una página web accesible desde el navegador.

Este visualizador será la base para futuros paneles más avanzados del proyecto RaspyAlarma, donde más adelante podrás añadir filtros, alertas visuales, gráficas y conexión con un servidor central.


Objetivo de la práctica

En esta práctica vas a crear un pequeño panel web en PHP que:

  • se conecte a la base de datos raspialarm,
  • lea los registros de la tabla lecturas_sensores,
  • muestre los datos en una tabla HTML,
  • permita visualizar las lecturas más recientes,
  • muestre información útil como el estado de alerta y si el dato fue enviado al servidor central.

Qué vas a construir

Al finalizar la práctica tendrás:

  • una carpeta web del proyecto,
  • un archivo de conexión a MariaDB,
  • una página PHP que recupere datos de la tabla,
  • una tabla HTML con todas las lecturas,
  • una versión mejorada con formato visual,
  • y un pequeño panel base para seguir ampliando en el futuro.

Requisitos previos

Antes de empezar debes tener ya preparado lo siguiente:

  • una Raspberry Pi funcionando,
  • Apache y PHP instalados,
  • MariaDB instalada y operativa,
  • la base de datos raspialarm creada,
  • la tabla lecturas_sensores creada,
  • y varios registros insertados desde el script Python.

Si todavía no tienes registros en la base de datos, primero debes completar la práctica anterior.


Estructura esperada de la base de datos

La práctica parte de esta tabla:

  • id
  • raspberry_id
  • nombresensor
  • lectura1
  • lectura2
  • lectura3
  • fecha_hora
  • alumnoEncargado
  • descripcionSensor
  • estado_alerta
  • enviado_central

Qué debe hacer el visualizador

El visualizador deberá mostrar como mínimo:

  • el identificador del registro,
  • el identificador de la Raspberry,
  • el nombre del sensor,
  • las tres lecturas,
  • la fecha y hora,
  • el alumno encargado,
  • la descripción del sensor,
  • el estado de alerta,
  • y el estado de envío al servidor central.

Parte 1. Comprobar que Apache, PHP y MariaDB están funcionando

Paso 1. Comprobar Apache

Abre una terminal y ejecuta:

sudo systemctl status apache2

Si no estuviera arrancado:

sudo systemctl start apache2

Y para dejarlo activado al inicio:

sudo systemctl enable apache2

Paso 2. Comprobar MariaDB

sudo systemctl status mariadb

Si no estuviera arrancada:

sudo systemctl start mariadb

Paso 3. Comprobar PHP

Ejecuta:

php -v

Esto debe mostrarte la versión de PHP instalada.


Parte 2. Preparar la carpeta del proyecto web

Tu visualizador web se guardará dentro del directorio servido por Apache.

Paso 1. Ir al directorio web

cd /var/www/html

Paso 2. Crear la carpeta del proyecto

sudo mkdir -p /var/www/html/raspialarma

Paso 3. Cambiar propietario de la carpeta

sudo chown -R $USER:$USER /var/www/html/raspialarma

Paso 4. Entrar en la carpeta

cd /var/www/html/raspialarma

Parte 3. Crear el archivo de conexión a la base de datos

Lo primero que vas a hacer es crear un archivo reutilizable que conecte PHP con MariaDB.

Paso 1. Crear el archivo conexion.php

nano conexion.php

Pega este contenido:

<?php
$host = "localhost";
$usuario = "raspiuser";
$contrasena = "raspi1234";
$basedatos = "raspialarm";

$conexion = new mysqli($host, $usuario, $contrasena, $basedatos);

if ($conexion->connect_error) {
    die("Error de conexión: " . $conexion->connect_error);
}

$conexion->set_charset("utf8");
?>

Guarda el archivo.


Qué hace este archivo

Este archivo:

  • define los datos de conexión,
  • crea una conexión con MariaDB,
  • comprueba si la conexión ha fallado,
  • y deja el objeto $conexion listo para usar en otras páginas PHP.

Parte 4. Crear una prueba básica de conexión

Antes de hacer el visualizador completo, conviene comprobar que PHP puede conectarse correctamente a la base de datos.

Paso 1. Crear el archivo prueba_conexion.php

nano prueba_conexion.php

Pega este contenido:

<?php
include("conexion.php");

echo "Conexión con la base de datos realizada correctamente.";

$conexion->close();
?>

Guarda el archivo.


Paso 2. Probar desde el navegador

Abre en el navegador:

http://IP_DE_LA_RASPBERRY/raspialarma/prueba_conexion.php

Si todo ha ido bien, deberías ver:

Conexión con la base de datos realizada correctamente.

Parte 5. Crear la primera página que lea datos de la tabla

Ahora vas a crear una página PHP que recupere registros de lecturas_sensores.

Paso 1. Crear el archivo ver_lecturas.php

nano ver_lecturas.php

Pega este contenido:

<?php
include("conexion.php");

$sql = "SELECT * FROM lecturas_sensores ORDER BY fecha_hora DESC";
$resultado = $conexion->query($sql);

if ($resultado->num_rows > 0) {
    while ($fila = $resultado->fetch_assoc()) {
        echo "ID: " . $fila["id"] . "<br>";
        echo "Raspberry: " . $fila["raspberry_id"] . "<br>";
        echo "Sensor: " . $fila["nombresensor"] . "<br>";
        echo "Lectura 1: " . $fila["lectura1"] . "<br>";
        echo "Lectura 2: " . $fila["lectura2"] . "<br>";
        echo "Lectura 3: " . $fila["lectura3"] . "<br>";
        echo "Fecha y hora: " . $fila["fecha_hora"] . "<br>";
        echo "Alumno: " . $fila["alumnoEncargado"] . "<br>";
        echo "Descripción: " . $fila["descripcionSensor"] . "<br>";
        echo "Estado alerta: " . $fila["estado_alerta"] . "<br>";
        echo "Enviado central: " . $fila["enviado_central"] . "<br>";
        echo "<hr>";
    }
} else {
    echo "No hay registros en la base de datos.";
}

$conexion->close();
?>

Guarda el archivo.


Paso 2. Probar desde el navegador

Abre:

http://IP_DE_LA_RASPBERRY/raspialarma/ver_lecturas.php

Si tienes datos en la base, deberían mostrarse uno debajo de otro.


Parte 6. Transformar la salida en una tabla HTML

La salida anterior funciona, pero no es cómoda de leer.
Ahora vas a mostrar los datos en una tabla HTML.

Paso 1. Sustituir el contenido de ver_lecturas.php

Edita el archivo:

nano ver_lecturas.php

Y reemplázalo por este contenido:

<?php
include("conexion.php");

$sql = "SELECT * FROM lecturas_sensores ORDER BY fecha_hora DESC";
$resultado = $conexion->query($sql);
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Lecturas RaspyAlarma</title>
</head>
<body>

<h1>Lecturas almacenadas en RaspyAlarma</h1>

<?php
if ($resultado->num_rows > 0) {
    echo "<table border='1' cellpadding='5' cellspacing='0'>";
    echo "<tr>
            <th>ID</th>
            <th>Raspberry</th>
            <th>Sensor</th>
            <th>Lectura 1</th>
            <th>Lectura 2</th>
            <th>Lectura 3</th>
            <th>Fecha y hora</th>
            <th>Alumno</th>
            <th>Descripción</th>
            <th>Estado alerta</th>
            <th>Enviado central</th>
          </tr>";

    while ($fila = $resultado->fetch_assoc()) {
        echo "<tr>";
        echo "<td>" . $fila["id"] . "</td>";
        echo "<td>" . $fila["raspberry_id"] . "</td>";
        echo "<td>" . $fila["nombresensor"] . "</td>";
        echo "<td>" . $fila["lectura1"] . "</td>";
        echo "<td>" . $fila["lectura2"] . "</td>";
        echo "<td>" . $fila["lectura3"] . "</td>";
        echo "<td>" . $fila["fecha_hora"] . "</td>";
        echo "<td>" . $fila["alumnoEncargado"] . "</td>";
        echo "<td>" . $fila["descripcionSensor"] . "</td>";
        echo "<td>" . $fila["estado_alerta"] . "</td>";
        echo "<td>" . $fila["enviado_central"] . "</td>";
        echo "</tr>";
    }

    echo "</table>";
} else {
    echo "<p>No hay registros en la base de datos.</p>";
}

$conexion->close();
?>

</body>
</html>

Guarda el archivo.


Paso 2. Ver el resultado en el navegador

Recarga:

http://IP_DE_LA_RASPBERRY/raspialarma/ver_lecturas.php

Ahora los datos deberían verse en forma de tabla.


Parte 7. Mejorar la visualización del estado de alerta y del envío central

Mostrar 0 y 1 no es muy visual.
Vas a convertir esos valores en texto más claro.

Paso 1. Modificar la parte del while

Dentro del while, antes de imprimir la fila, añade esta lógica:

$enviado = ($fila["enviado_central"] == 1) ? "Sí" : "No";

Y en lugar de imprimir directamente enviado_central, muestra $enviado.

Además, puedes mejorar el campo estado_alerta manteniéndolo como texto.

La parte completa quedaría así:

while ($fila = $resultado->fetch_assoc()) {
    $enviado = ($fila["enviado_central"] == 1) ? "Sí" : "No";

    echo "<tr>";
    echo "<td>" . $fila["id"] . "</td>";
    echo "<td>" . $fila["raspberry_id"] . "</td>";
    echo "<td>" . $fila["nombresensor"] . "</td>";
    echo "<td>" . $fila["lectura1"] . "</td>";
    echo "<td>" . $fila["lectura2"] . "</td>";
    echo "<td>" . $fila["lectura3"] . "</td>";
    echo "<td>" . $fila["fecha_hora"] . "</td>";
    echo "<td>" . $fila["alumnoEncargado"] . "</td>";
    echo "<td>" . $fila["descripcionSensor"] . "</td>";
    echo "<td>" . $fila["estado_alerta"] . "</td>";
    echo "<td>" . $enviado . "</td>";
    echo "</tr>";
}

Parte 8. Añadir estilo visual básico con CSS

Ahora vas a mejorar un poco la apariencia de la página.

Paso 1. Añadir estilos dentro del <head>

Sustituye el <head> por este:

<head>
    <meta charset="UTF-8">
    <title>Lecturas RaspyAlarma</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f6f8;
            margin: 20px;
        }

        h1 {
            color: #1f3c88;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            background: white;
        }

        th {
            background-color: #1f3c88;
            color: white;
            padding: 10px;
        }

        td {
            padding: 8px;
            border: 1px solid #ccc;
            text-align: center;
        }

        tr:nth-child(even) {
            background-color: #f2f2f2;
        }
    </style>
</head>

Guarda y recarga la página.


Parte 9. Colorear visualmente el estado de alerta

Ahora vas a resaltar el estado de alerta.

Paso 1. Añadir una variable para el color

Dentro del while, añade esta lógica:

$enviado = ($fila["enviado_central"] == 1) ? "Sí" : "No";

$colorAlerta = "black";

if ($fila["estado_alerta"] == "normal") {
    $colorAlerta = "green";
} elseif ($fila["estado_alerta"] == "aviso") {
    $colorAlerta = "orange";
} elseif ($fila["estado_alerta"] == "critico") {
    $colorAlerta = "red";
}

Paso 2. Mostrar el estado con color

Sustituye la celda de estado_alerta por esta:

echo "<td style='color:$colorAlerta; font-weight:bold;'>" . $fila["estado_alerta"] . "</td>";

Esto hará que:

  • normal aparezca en verde,
  • aviso en naranja,
  • critico en rojo.

Parte 10. Crear una versión que muestre solo las últimas lecturas

A veces no interesa ver todo, sino solo las más recientes.

Paso 1. Crear el archivo ultimas_lecturas.php

nano ultimas_lecturas.php

Pega este contenido:

<?php
include("conexion.php");

$sql = "SELECT * FROM lecturas_sensores ORDER BY fecha_hora DESC LIMIT 10";
$resultado = $conexion->query($sql);
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Últimas lecturas</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f6f8;
            margin: 20px;
        }

        h1 {
            color: #1f3c88;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            background: white;
        }

        th {
            background-color: #1f3c88;
            color: white;
            padding: 10px;
        }

        td {
            padding: 8px;
            border: 1px solid #ccc;
            text-align: center;
        }

        tr:nth-child(even) {
            background-color: #f2f2f2;
        }
    </style>
</head>
<body>

<h1>Últimas 10 lecturas registradas</h1>

<?php
if ($resultado->num_rows > 0) {
    echo "<table>";
    echo "<tr>
            <th>ID</th>
            <th>Raspberry</th>
            <th>Sensor</th>
            <th>Lectura 1</th>
            <th>Lectura 2</th>
            <th>Lectura 3</th>
            <th>Fecha y hora</th>
            <th>Estado alerta</th>
          </tr>";

    while ($fila = $resultado->fetch_assoc()) {
        $colorAlerta = "black";

        if ($fila["estado_alerta"] == "normal") {
            $colorAlerta = "green";
        } elseif ($fila["estado_alerta"] == "aviso") {
            $colorAlerta = "orange";
        } elseif ($fila["estado_alerta"] == "critico") {
            $colorAlerta = "red";
        }

        echo "<tr>";
        echo "<td>" . $fila["id"] . "</td>";
        echo "<td>" . $fila["raspberry_id"] . "</td>";
        echo "<td>" . $fila["nombresensor"] . "</td>";
        echo "<td>" . $fila["lectura1"] . "</td>";
        echo "<td>" . $fila["lectura2"] . "</td>";
        echo "<td>" . $fila["lectura3"] . "</td>";
        echo "<td>" . $fila["fecha_hora"] . "</td>";
        echo "<td style='color:$colorAlerta; font-weight:bold;'>" . $fila["estado_alerta"] . "</td>";
        echo "</tr>";
    }

    echo "</table>";
} else {
    echo "<p>No hay lecturas disponibles.</p>";
}

$conexion->close();
?>

</body>
</html>

Guarda y prueba en el navegador.


Parte 11. Crear una página con resumen rápido

Ahora vas a crear una página que muestre algunos datos resumidos:

  • número total de registros,
  • número de alertas críticas,
  • número de registros pendientes de enviar.

Paso 1. Crear el archivo resumen.php

nano resumen.php

Pega este contenido:

<?php
include("conexion.php");

$sqlTotal = "SELECT COUNT(*) AS total FROM lecturas_sensores";
$sqlCriticos = "SELECT COUNT(*) AS criticos FROM lecturas_sensores WHERE estado_alerta = 'critico'";
$sqlPendientes = "SELECT COUNT(*) AS pendientes FROM lecturas_sensores WHERE enviado_central = 0";

$total = $conexion->query($sqlTotal)->fetch_assoc()["total"];
$criticos = $conexion->query($sqlCriticos)->fetch_assoc()["criticos"];
$pendientes = $conexion->query($sqlPendientes)->fetch_assoc()["pendientes"];
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Resumen RaspyAlarma</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f6f8;
            margin: 20px;
        }

        h1 {
            color: #1f3c88;
        }

        .caja {
            background: white;
            border: 1px solid #ccc;
            padding: 20px;
            margin-bottom: 15px;
            font-size: 20px;
        }
    </style>
</head>
<body>

<h1>Resumen del sistema RaspyAlarma</h1>

<div class="caja">Total de registros: <?php echo $total; ?></div>
<div class="caja">Alertas críticas: <?php echo $criticos; ?></div>
<div class="caja">Pendientes de enviar al servidor central: <?php echo $pendientes; ?></div>

</body>
</html>

Guarda y pruébalo en el navegador.


Parte 12. Qué debe comprobar el alumno

Debes verificar que:

  • PHP conecta con la base de datos,
  • la consulta SQL recupera datos,
  • la tabla HTML se genera correctamente,
  • los campos se muestran completos,
  • el estado de alerta aparece bien,
  • el campo enviado_central se interpreta correctamente,
  • y las páginas son accesibles desde el navegador.

Parte 13. Errores frecuentes

Error 1. Página en blanco

Suele ocurrir por:

  • un error de sintaxis en PHP,
  • una etiqueta mal cerrada,
  • o un problema en la conexión.

Error 2. Error de conexión a la base de datos

Comprueba:

  • usuario,
  • contraseña,
  • nombre de la base,
  • y que MariaDB esté arrancada.

Error 3. No aparecen datos

Comprueba:

  • que existan registros en lecturas_sensores,
  • que el SELECT esté bien escrito,
  • y que el script Python haya insertado correctamente.

Error 4. Apache no muestra la página

Comprueba:

  • que Apache esté arrancado,
  • que el archivo esté en /var/www/html/raspialarma,
  • y que la URL sea correcta.

Parte 14. Orden recomendado de trabajo

Debes seguir este orden:

Fase 1

Crear conexion.php.

Fase 2

Probar la conexión con prueba_conexion.php.

Fase 3

Crear ver_lecturas.php con salida simple.

Fase 4

Transformar la salida en tabla HTML.

Fase 5

Añadir estilos CSS.

Fase 6

Resaltar el estado de alerta y el envío central.

Fase 7

Crear páginas adicionales como ultimas_lecturas.php y resumen.php.


Parte 15. Qué debes entregar

La práctica deberá incluir:

  • archivo conexion.php,
  • archivo prueba_conexion.php,
  • archivo ver_lecturas.php,
  • archivo ultimas_lecturas.php,
  • archivo resumen.php,
  • capturas de funcionamiento en el navegador,
  • explicación de qué muestra cada página,
  • y evidencia de que los datos provienen realmente de MariaDB.

Parte 16. Resultado esperado

Al finalizar la práctica deberás tener un pequeño sistema web local capaz de consultar y mostrar los datos recogidos por tu Raspberry.

Tu Raspberry ya no solo capturará y almacenará datos, sino que además ofrecerá un primer panel web para visualizarlos.

Ese será el punto de partida para futuras mejoras como:

  • filtros por sensor,
  • búsquedas por Raspberry,
  • páginas de alertas,
  • gráficas,
  • exportación de datos,
  • y sincronización con el servidor central.

Resumen rápido de archivos

conexion.php

Se encarga de conectar PHP con MariaDB.

prueba_conexion.php

Comprueba que la conexión funciona.

ver_lecturas.php

Muestra todos los registros de la tabla.

ultimas_lecturas.php

Muestra solo las últimas lecturas.

resumen.php

Muestra indicadores rápidos del sistema.