Un compute script (mostrado como Transform en la configuración de la tarjeta) es una pequeña función JavaScript que deriva lo que dibuja una tarjeta a partir de los datos que ha cargado. Úsalo cuando ninguna fuente da exactamente la forma que necesitas: convertir unidades, emparejar dos series en una ruta, contar filas o elegir el peor estado. Un script solo calcula. No puede establecer un parámetro, ejecutar un comando, abrir una página ni acceder a la red.
Añadir un script
- Personaliza el tablero y abre la configuración de la tarjeta.
- En la pestaña Datos, abre Avanzado: calcular los valores con un script.
- Marca Ejecutar este script y escribe el Script.
- Selecciona Ejecutar ahora para ejecutar tu borrador con los datos actuales de la tarjeta. El Resultado muestra lo que se ha devuelto por cada slot, por ejemplo «series: table, 12 row(s)» y «ran in 3 ms».
- Define el Tiempo máximo (ms) y Cuando una ejecución falla.
- Selecciona Guardar.
Eliminar el script lo borra. El script se copia con la tarjeta, viaja en los archivos del tablero y permanece en la tarjeta cuando la guardas como widget.
El contrato
El script es un módulo ES cuya exportación por defecto es una función síncrona:
export default function transform({ slots, params, window, now }) {
// slots: the bound data by slot key, as the source returned it (shape table | scalar | series | record)
// params: the effective board parameters of the card's page (read-only)
// window: { from, to, interval? } (ms since the epoch) when the card's data ran with a window
// now: ms since the epoch, the host's clock (a script never reads Date)
return { slots: { /* the slots you replace */ } };
}
Devuelve { slots }. Cada slot devuelto sustituye al cargado; los slots que no devuelvas se mantienen como se cargaron. Un resultado vacío dibuja los datos tal como se cargaron.
| Forma | Forma |
|---|---|
| Escalar | { shape: 'scalar', value: 21.5, meta: { unit: '°C', decimals: 1 } } |
| Serie | { shape: 'series', series: [{ name: 'temperature', points: [{ t: '2026-11-09T10:00:00Z', v: 21.5 }] }] } |
| Tabla | { shape: 'table', columns: [{ key: 'id' }, { key: 'value', type: 'number' }], rows: [{ id: 'p1', value: 3 }] } |
| Registro | { shape: 'record', record: { level: 2.4, flow: 18 } } |
Una tarjeta de diagrama de proceso o de modelo 3D también puede devolver scene: elementos, sustituciones por objeto, conexiones y zonas adicionales, la vista y los problemas. Solo cambia el dibujo.
Dónde se ejecuta
El script se ejecuta en tu navegador, en un marco oculto sin acceso a Hermetry, a la red ni a tu sesión, dentro de su propio worker. Se vuelve a ejecutar cada vez que cambian los datos de la tarjeta (incluida una actualización en vivo) o un parámetro. Solo hay una ejecución en curso por tarjeta; gana la entrada más reciente, con un máximo de 20 ejecuciones por segundo. Una tarjeta que no se muestra no se ejecuta. Las pantallas de visualización ejecutan scripts de la misma forma.
Límites
| Límite | Valor |
|---|---|
| Longitud del script | 65,536 caracteres |
| Tiempo máximo | De 10 a 500 ms por ejecución, por defecto 50. Si se supera, la ejecución se detiene. |
| Slots devueltos | 16 |
| Filas por tabla | 5,000 |
| Columnas | 64 |
| Un valor de texto | 10 KiB |
| Resultado completo | 2 MiB |
| Elementos en una escena | 500 en un diagrama de proceso, 2,000 en un modelo 3D |
Cuando una ejecución falla
| Cuando una ejecución falla | La tarjeta |
|---|---|
| Mantener el resultado anterior | Mantiene la última salida correcta y muestra una insignia Transform failed |
| Mostrar la tarjeta vacía | Muestra el error en lugar de los datos |
Mensajes: «The script ran past its time budget: …», «The script could not be loaded: …», «Transform failed: …».
Ejemplos
De Celsius a Fahrenheit en una tarjeta de valor (slot value):
export default function transform({ slots }) {
const c = slots.value && typeof slots.value.value === 'number' ? slots.value.value : null;
if (c === null) return {};
return { slots: { value: { shape: 'scalar', value: c * 9 / 5 + 32, meta: { unit: '°F', decimals: 1 } } } };
}
Contar las alarmas abiertas de los dispositivos de un parámetro (una tarjeta de valor cuyo slot value está vinculado a Alarms (live), una tabla):
export default function transform({ slots }) {
const rows = slots.value && Array.isArray(slots.value.rows) ? slots.value.rows : [];
return { slots: { value: { shape: 'scalar', value: rows.length, meta: { decimals: 0 } } } };
}
Una ruta a partir de series de latitud y longitud (un mapa cuyo slot routes está vinculado a Device readings over time con las claves lat,lng):
export default function transform({ slots }) {
const series = slots.routes && Array.isArray(slots.routes.series) ? slots.routes.series : [];
const named = (k) => series.find((s) => s && s.name === k) || { points: [] };
const lng = new Map(named('lng').points.map((p) => [p.t, p.v]));
const track = named('lat').points
.filter((p) => lng.has(p.t))
.map((p) => [p.v, lng.get(p.t), Date.parse(p.t)])
.sort((a, b) => a[2] - b[2]);
return { slots: { routes: { shape: 'table',
columns: [{ key: 'name' }, { key: 'positions' }],
rows: track.length >= 2 ? [{ id: 'route', name: 'Route', positions: track.slice(-256) }] : [] } } };
}
Una lista dentro de una celda contiene como máximo 256 elementos, así que limita una ruta a 256 puntos. Consulta Tarjetas de mapa.
Buenas prácticas
- Devuelve solo los slots que cambies.
- Protégete contra datos ausentes: un slot puede estar vacío mientras el dispositivo no envía nada.
- Mantén los scripts pequeños y rápidos; un bucle largo sobre un año de lecturas brutas superará el tiempo máximo. Prefiere una fuente con agregado.
- Usa
now, nuncaDate.now(), para cualquier cosa basada en el tiempo.

