devicescript-dashboard-web-integracion

Cómo crear un dashboard web para DeviceScript

  • 4 min

Un dashboard web permite consultar el estado del dispositivo y enviarle órdenes desde el navegador. En este ejemplo usaremos MQTT como intermediario entre la interfaz y la placa.

Ver datos en la consola de VS Code está bien para depurar, y usar un panel MQTT externo es práctico. Pero muchas veces queremos una página web propia, con nuestros botones, nuestras gráficas y nuestro pequeño caos visual organizado.

La idea tentadora sería meter un servidor web completo dentro del ESP32. Se puede hacer en otros entornos, sí. Pero en DeviceScript, a día de hoy, la vía más limpia y documentada es otra: usar un intermediario.

Arquitectura de la solución

Vamos a separar responsabilidades:

La placa DeviceScript: Lee sensores, controla actuadores y publica/recibe mensajes MQTT.

El broker MQTT: Hace de puente entre la placa y el mundo exterior.

El dashboard web: Se ejecuta en el navegador y manda órdenes por MQTT.

Esto es muy habitual en IoT. El microcontrolador no tiene que servir HTML, CSS, imágenes y JavaScript. Solo tiene que hacer lo que sabe hacer bien: medir, actuar y enviar mensajes pequeños.

Código de la placa

Vamos a crear un ejemplo muy sencillo. La placa publicará su estado y escuchará comandos para encender o apagar un LED.

import { deviceIdentifier } from "@devicescript/core"
import { startLightBulb } from "@devicescript/servers"
import { startMQTTClient } from "@devicescript/net"
import { pins } from "@dsboard/adafruit_qt_py_c3"

const led = startLightBulb({
    pin: pins.A0_D0,
})

const deviceId = deviceIdentifier("self")
const topicEstado = `devs/${deviceId}/state`
const topicComando = `devs/${deviceId}/cmd/led`

const mqtt = await startMQTTClient({
    host: "broker.hivemq.com",
    proto: "tcp",
    port: 1883,
})

await mqtt.subscribe(topicComando, async msg => {
    const comando = msg.content.toString("utf-8")

    if (comando === "on") {
        await led.on()
    } else if (comando === "off") {
        await led.off()
    } else if (comando === "toggle") {
        await led.toggle()
    }
})

setInterval(async () => {
    const brillo = await led.intensity.read()

    await mqtt.publish(topicEstado, JSON.stringify({
        id: deviceId,
        led: brillo,
        time: Date.now(),
    }))
}, 2000)
Copied!

El topic incluye el identificador del dispositivo. Así evitamos que dos placas que usan el mismo broker público se pisen los mensajes.

Un broker público está bien para pruebas y demostraciones. Para un proyecto real, usa un broker propio con autenticación y, si la placa lo soporta, TLS.

Dashboard web

En el navegador no podemos hablar MQTT “puro” por TCP. El navegador vive en su mundo de HTTP, WebSocket y sus normas de seguridad (que están para protegernos, aunque a veces den ganas de discutirles).

Por eso, el dashboard web normalmente se conecta al broker mediante MQTT sobre WebSocket.

<!doctype html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <title>Dashboard DeviceScript</title>
  <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
</head>
<body>
  <h1>DeviceScript Dashboard</h1>

  <button id="on">Encender</button>
  <button id="off">Apagar</button>
  <button id="toggle">Cambiar</button>

  <pre id="estado">Esperando datos...</pre>

  <script>
    const deviceId = "CAMBIA_ESTO_POR_TU_ID"
    const topicEstado = `devs/${deviceId}/state`
    const topicComando = `devs/${deviceId}/cmd/led`

    const client = mqtt.connect("wss://broker.hivemq.com:8884/mqtt")

    client.on("connect", () => {
      client.subscribe(topicEstado)
    })

    client.on("message", (topic, payload) => {
      document.querySelector("#estado").textContent = payload.toString()
    })

    document.querySelector("#on").onclick = () => client.publish(topicComando, "on")
    document.querySelector("#off").onclick = () => client.publish(topicComando, "off")
    document.querySelector("#toggle").onclick = () => client.publish(topicComando, "toggle")
  </script>
</body>
</html>
Copied!

No es el HTML más bonito del mundo (nadie lo va a exponer en un museo), pero demuestra la idea importante: el navegador y la placa no hablan directamente entre sí. Se coordinan a través del broker.

Llevarlo a un proyecto real

Para una demo, un broker público y un HTML suelto nos vale. Para un proyecto real, conviene subir un escalón:

  • Broker propio: Mosquitto, EMQX, HiveMQ u otra alternativa que encaje con el proyecto.
  • Autenticación: usuario y contraseña como mínimo.
  • Topics ordenados: casa/salon/temperatura, casa/salon/rele/cmd, etc.
  • Frontend real: React, Vue, Svelte o una página sencilla con JavaScript vanilla.
  • Backend opcional: Node-RED, Home Assistant o un servicio propio que guarde históricos.

DeviceScript también incluye un Development Gateway para comunicar dispositivos con servicios externos. Puede servir como capa adicional cuando necesitas mensajería o despliegue de scripts, aunque debes valorar su encaje teniendo en cuenta que el proyecto ya no recibe mantenimiento.