La función fetch de DeviceScript permite realizar peticiones HTTP o HTTPS mediante una API asíncrona similar a la del navegador.
En el ecosistema Arduino/C++, realizar una petición web segura (HTTPS) suele ser una tarea titánica. Tienes que gestionar los certificados SSL, asegurarte de que la respuesta cabe en la RAM, y luego usar una librería como ArduinoJson para intentar descifrar esa sopa de letras que recibes.
Podemos descargar texto, procesar JSON y enviar datos sin incorporar una pila HTTP externa. Seguimos trabajando en un microcontrolador, por lo que el tamaño de las respuestas y el coste de TLS importan.
La función fetch
La API Fetch es el estándar moderno para realizar peticiones de red asíncronas. En DeviceScript, se importa desde @devicescript/net.
La estructura básica es:
Llamamos a fetch(url).
Esperamos (await) a que el servidor responda.
Convertimos la respuesta a texto o JSON.
Esperamos (await) a que se procese ese contenido.
Petición GET: leer un JSON
Vamos a empezar con lo más básico: consultar una API pública para obtener datos. Usaremos el clásico servicio de pruebas JSONPlaceholder.
Vamos a obtener la información de una tarea de prueba.
import { fetch } from "@devicescript/net"
// URL de prueba que devuelve un JSON simple
const URL = "https://jsonplaceholder.typicode.com/todos/1"
async function obtenerDatos() {
console.log("Iniciando petición GET...")
try {
// 1. Hacemos la petición
const respuesta = await fetch(URL)
// 2. Comprobamos si el servidor nos ha dado el OK (Código 200-299)
if (respuesta.status === 200) {
// 3. Parseamos el JSON
const datos = await respuesta.json()
// 4. Usamos los datos como un objeto normal de JS
console.log("Datos recibidos:")
console.log(`ID: ${datos.id}`)
console.log(`Título: ${datos.title}`)
console.log(`Completado: ${datos.completed}`)
} else {
console.error(`Error en el servidor: ${respuesta.status}`)
}
} catch (error) {
// Capturamos errores de red (ej: WiFi caído)
console.error("Error de red:", error)
}
}
// Ejecutamos
obtenerDatos()Analicemos las diferencias con C++
- Nada de
WiFiClientSecure: DeviceScript gestiona la conexión segura TLS por debajo. - Nada de
DeserializationError:.json()devuelve un objeto de JavaScript listo para usar. - Memoria: El sistema gestiona los búferes, pero la respuesta debe caber en la memoria disponible. Mantén los documentos pequeños.
El simulador puede usar la red del ordenador, lo que permite comprobar la respuesta de la API antes de probarla en la placa.
Petición POST: enviar datos
Leer es fácil, pero para el IoT solemos querer enviar datos (telemetría de sensores) a un servidor. Para eso usamos el método POST.
Supongamos que queremos enviar la temperatura actual a un servidor. Necesitamos configurar un poco más la llamada fetch:
import * as ds from "@devicescript/core"
import { fetch } from "@devicescript/net"
async function enviarTelemetria(temperatura: number) {
const URL_POST = "https://jsonplaceholder.typicode.com/posts"
console.log(`Enviando temperatura: ${temperatura}...`)
try {
const respuesta = await fetch(URL_POST, {
method: "POST", // Indicamos que vamos a escribir
headers: {
// Importante: Decirle al servidor que enviamos JSON
"Content-Type": "application/json"
},
// Convertimos nuestro objeto JS a texto para enviarlo
body: JSON.stringify({
sensor: "ESP32-Lab",
temp: temperatura,
uptime: ds.millis()
})
})
if (respuesta.status === 201) { // 201 = Created
console.log("¡Datos guardados correctamente!")
const confirmacion = await respuesta.json()
console.log(confirmacion)
} else {
console.error(`Fallo al enviar: ${respuesta.status}`)
}
} catch (e) {
console.error("Error de envío", e)
}
}
// Simulamos un envío
enviarTelemetria(24.5)JSON.stringify() convierte un objeto en texto JSON. DeviceScript incorpora esta función, de modo que no necesitamos construir la cadena manualmente.
Límites que conviene tener presentes
Seguimos trabajando en un microcontrolador, no en un servidor. Hay límites.
Memoria RAM
Al hacer await response.json(), todo el objeto debe caber en la memoria RAM del dispositivo.
- Si la API devuelve una lista de 5000 elementos, el ESP32 se quedará sin memoria (OOM) y se reiniciará.
- Solución: Si controlas la API, aplica paginación o filtrado para recibir solo los campos necesarios. DeviceScript no es adecuado para procesar megabytes de JSON.
HTTPS y TLS
DeviceScript soporta HTTPS, pero TLS consume CPU y una parte importante de la memoria. Además, solo puede mantener un socket abierto a la vez.
Tiempo de espera
Las peticiones pueden tardar. Si el servidor es lento, la función async permanecerá suspendida en await. Diseña un tiempo de espera y una estrategia de error acordes con la lógica de la aplicación.
Ejemplo: consultar una API meteorológica
Para cerrar, un reto habitual. ¿Qué tiempo hace? Podemos consultar una API meteorológica para decidir si encendemos un LED. Necesitarás una clave propia del proveedor.
Nota: Este es un esquema conceptual.
// Esquema lógico
const API_KEY = "TU_API_KEY"
const CIUDAD = "Madrid"
const URL = `https://api.openweathermap.org/data/2.5/weather?q=${CIUDAD}&appid=${API_KEY}`
async function consultarClima() {
const res = await fetch(URL)
const data = await res.json()
// Accedemos a la estructura profunda del JSON
const clima = data.weather[0].main // Ej: "Rain", "Clear"
if (clima === "Rain") {
console.log("Está lloviendo, cerrar toldo.")
// await motorToldo.start()
}
}