Documentación técnica
Trama · Sirius
Red mesh LoRa con IA para capturar datos de campo en zonas sin cobertura celular. Esta guía cubre la arquitectura, la red, el gateway y las integraciones — para técnicos e integradores.
Introducción
Trama reparte un único enlace a internet (Starlink, satelital o celular) por una malla de radio LoRa de largo alcance. Con pocos nodos repetidores se cubren kilómetros de campo, montaña o selva donde no llega señal celular.
Sirius es la capa de captura agro: cada persona lleva un nodo y registra el trabajo del campo (cosecha, siembra, polinización, plagas, censo) desde cualquier parte de la finca. Los datos viajan por la mesh y llegan al gateway en segundos, aunque el punto de captura esté sin señal.
La idea central: una sola conexión a internet (en el gateway) conecta toda una región. Los nodos nunca necesitan datos móviles.
Tecnología propietaria. Trama™ es tecnología privada. La arquitectura, la configuración de radio y los parámetros de despliegue son confidenciales; cualquier uso, reproducción o despliegue requiere licencia. Esta documentación es solo de referencia y no autoriza su uso.
Arquitectura
El sistema tiene cuatro capas: captura, transporte, ingesta y presentación.
Campo (sin señal) Nube / internet
┌───────────────┐ LoRa mesh ┌────────────┐ HTTPS ┌──────────────┐
│ Nodos T1000-e │◀────────────▶│ Gateway │◀────────▶│ Supabase │
│ Inv1 … Inv7 │ (Meshtastic)│ (Raspberry │ │ (Postgres) │
└───────────────┘ │ Pi 4) │ └──────┬───────┘
│ radio CTRL │ │
└────────────┘ │
┌────────────┼────────────┐
▼ ▼ ▼
Webapp App Flutter WhatsApp
(Next.js) (offline) (relay + bot)| Capa | Qué hace |
|---|---|
| Captura | Nodos T1000-e en el campo. Registran datos y los emiten por LoRa. |
| Transporte | Malla LoRa: Meshtastic (los paquetes saltan de nodo en nodo) o MeshCore (relevan repetidores dedicados). Es una capa intercambiable: lo de arriba no cambia. |
| Ingesta | Gateway (Pi 4): recibe por radio, procesa y sincroniza a Supabase por el único enlace a internet. |
| Presentación | Webapp (Vercel), app Flutter offline, y WhatsApp (relay entre personas + bot Sirius con IA). |
Red mesh LoRa (Meshtastic)
Esta es una de las dos mallas soportadas. Corre firmware Meshtastic, y tres parámetros definen cómo y dónde transmite; deben ser idénticos en todos los nodos para que se escuchen. La alternativa —y lo que conviene para crecer— es MeshCore, en el capítulo siguiente.
Región, preset y slot
Sus valores dependen de la zona de operación (la banda legal de cada país) y del despliegue; Trama™ los configura en cada instalación y no se publican.
| Parámetro | Qué es |
|---|---|
region | Banda legal de uso libre de la zona/país. |
modem_preset | Compromiso entre alcance y velocidad, según la zona. |
channel_num | Slot de frecuencia dentro de la banda, asignado por Trama en el despliegue. |
Los valores exactos de región, slot y frecuencia son específicos de cada despliegue y no se documentan aquí. Su configuración la realiza Trama™ bajo licencia. Verifica siempre la frecuencia efectiva del sitio, no solo la región.
Canal y cifrado
El canal primario se llama Inverse y lleva una PSK (clave precompartida): todo el tráfico de la operación va cifrado en ese canal. Un nodo sin la PSK correcta no descifra los mensajes aunque esté en la misma frecuencia.
Difusión vs directo
Un mensaje puede ir a un nodo (DM) o a todos por difusión (dirección ^all, sin ACK). El gateway usa ambos: DM para relays 1-a-1, broadcast para avisos a toda la red.
Cambiar la región/preset/slot NO es reflashear el firmware. Es solo configuración — pero si un nodo queda en otra banda, desaparece de la malla hasta corregirlo.
Malla MeshCore (alternativa)
La malla de radio es intercambiable. Todo lo que está por encima —el gateway, la captura, WhatsApp, la IA, la app— habla contra una interfaz común (MeshTransport) y no sabe qué firmware corre debajo. Por eso hay dos opciones soportadas, y elegir una es una decisión de despliegue, no una reescritura.
No es teoría. Las dos estaciones se migraron de Meshtastic a MeshCore de punta a punta sin cambiar una línea por encima del transporte.
Cuál elegir
| Meshtastic | MeshCore | |
|---|---|---|
| Quién repite | Todos los nodos | Solo repetidores dedicados |
| Escala | Se congestiona al crecer | Crece mejor: el aire no se llena de ecos |
| Identidad | Número de nodo | Clave pública (32 bytes) |
| Directorio | NodeDB automática | No hay: los contactos se precargan |
| Foto → visión | ~82 s | ~56 s |
| Madurez en Trama | Años de operación | En producción desde 2026-09 |
Regla práctica: para un despliegue pequeño y cerrado, Meshtastic es más simple porque se autoconfigura. Para crecer —más nodos, más área, repetidores— MeshCore es el que aguanta, porque en Meshtastic cada nodo repite y el aire se llena de copias del mismo mensaje.
Los cuatro parámetros de radio
Deben ser idénticos en todos los nodos, igual que en Meshtastic. Pero aquí no hay «preset» que los fije de golpe: se ponen uno por uno.
frecuencia 922.375 MHz (la banda; separa mallas vecinas) ancho banda 250 kHz (BW) spreading 11 (SF — alcance contra velocidad) codificación 5 (CR)
Un SF distinto no es «mala señal»: es sordera total. Los spreading factors son formas de onda ortogonales — la radio ni registra que haya alguien transmitiendo. Poner solo la frecuencia deja a los nodos coherentes entre ellos y mudos frente al gateway, que es el síntoma más confuso posible: el chat entre nodos funciona y al gateway no llega nada en ninguno de los dos sentidos.
Para diagnosticarlo en un minuto: volcar los contactos del gateway y mirar su last_advert. Si sale «nunca oído» en todos, no es direccionamiento, es la radio.
Identidad y contactos
MeshCore identifica a cada nodo por su clave pública, que se genera al flashear. Los primeros 4 bytes son el id que se ve en los registros (!b3575a04). No hay NodeDB: para escribirle a alguien hay que tener su clave completa.
Consecuencia práctica: los contactos se precargan en el gateway (variable MESH_CONTACTS) y en la app. Y como un nodo companion no se anuncia solo —en MeshCore solo se anuncian los repetidores—, el gateway manda un anuncio al arrancar para que los nodos puedan dirigirse a él sin depender de la app.
Las claves solo existen después de flashear, y el borrado previo destruye la identidad anterior. El orden es siempre: flashear → leer claves → armar la configuración → compilar la app. Nunca al revés.
Firmware por rol
Hay un release distinto por papel, y no son intercambiables: companion (nodos de usuario y el del gateway), repeater (los que relevan) y room-server.
Al flashear hay que borrar del todo primero. Sin borrado completo, MeshCore no arranca y el nodo se queda parpadeando en el bootloader. Los borrados genéricos de Meshtastic no sirven.
Límites que fallan en silencio
Estos se midieron en banco antes de escribir código, y conviene respetarlos porque ninguno avisa cuando se pasa:
| Límite | Valor | Qué pasa al pasarse |
|---|---|---|
| Texto por paquete | 160 bytes | Devuelve error |
| Binario por paquete | 172 bytes | Se pierde en silencio |
| Ritmo de envío | ~1,6 s por paquete | La cola se desborda sin avisar |
| Reenvío idéntico | — | Se descarta: deduplica por hash |
Por eso los envíos largos se trocean y se entregan al ritmo de drenaje de la radio, y las fotos llevan un contador de intento en la cabecera: sin él, un reenvío idéntico se descartaría por deduplicación.
Nodos
Los nodos son Seeed T1000-e: trackers LoRa con GPS, batería y opción de panel solar. Cada uno tiene un short name (Inv1…Inv7, CTRL) y un ID hex (!40883c41).
| Señal | Significado |
|---|---|
last_heard | Cuándo el gateway oyó al nodo por última vez. Fresco = está en la malla ahora. |
SNR | Relación señal/ruido del último paquete. Cuanto mayor, mejor enlace. |
| Alcance | Varios km en línea de vista; los nodos repiten para extender la cobertura. |
La lista de nodos puede mostrar equipos viejos. Para confirmar que un nodo comunica de verdad, mira su last_heard fresco, no que aparezca en la lista.
El gateway
El gateway es una Raspberry Pi 4 con una radio Meshtastic por USB (el nodo CTRL) y servicios en Python. Es el puente entre la malla y la nube.
Servicios (systemd)
| Servicio | Rol |
|---|---|
mesh-portatil-gateway | Abre la radio y corre los módulos + el puente a Supabase. |
mesh-whatsapp-agent | El bot conversacional de WhatsApp (Sirius) con Claude. |
Módulos del gateway
| Módulo | Escucha | Función |
|---|---|---|
| Campo | @ag|… | Alta de fincas/lotes/operarios y catálogo. |
| Cosecha | @kg @cols | Registra producción por colaborador con GPS. |
| Relay | @wa @tels | Puente WhatsApp ↔ mesh (radioteléfono). |
| Claude | @claude | Consultas a la IA desde un nodo. |
Operación
# Estado y logs sudo systemctl status mesh-portatil-gateway journalctl -u mesh-portatil-gateway -f # Reiniciar (p. ej. tras tocar la radio) sudo systemctl restart mesh-portatil-gateway
La radio (puerto serie) la usa el servicio. Para configurarla con el CLI de meshtastic, primero detén el servicio; si no, el puerto está ocupado.
Captura de datos
Los nodos emiten tramas de texto por la mesh; el gateway las parsea y las guarda en Supabase. El flujo es nodo → mesh → gateway → Supabase.
Trama de cosecha
@kg|<id_colaborador>|<cantidad>|<lat>|<lng>|t<epoch> # ej. @kg|12|34.5|4.812|-75.71|t1786390000
Guarda la cantidad recogida por un colaborador, con su ubicación GPS (dónde se capturó) y la marca de tiempo. El jornal se calcula como cantidad × tarifa.
| Comando | Uso |
|---|---|
@cols | Lista los colaboradores de la app activa. |
@col|nombre | Da de alta un colaborador. |
@kg|… | Registra producción (arriba). |
La unidad se ajusta a la labor: cosecha→kg, siembra→plántulas, plaga→plantas, etc. Los registros marcados demo se excluyen de los totales y del dashboard.
Hay dos integraciones de WhatsApp, independientes:
1) Relay (radioteléfono)
Puente entre una persona en WhatsApp y los nodos de la mesh, por la WhatsApp Cloud API oficial. Desde WhatsApp se direcciona por prefijo:
| Escribes | Efecto |
|---|---|
Inv1: revisa el lote norte | Mensaje directo a Inv1 (queda como nodo activo). |
todos: nos vemos en la oficina | Difusión a todos los nodos (broadcast). |
Inv2 | Cambia el nodo activo sin enviar nada. |
nodos | Lista los short names disponibles. |
Del lado mesh, un nodo manda @wa|telefono|texto para escribir a WhatsApp (dentro de la ventana de servicio de 24 h).
2) Bot Sirius (IA)
Un agente conversacional con Claude que crea la app de la finca, responde preguntas de datos reales y genera dashboards:
| Pide | Herramienta |
|---|---|
| “Créame la app de la finca X” | crear_cliente |
| “¿Cuánto se recogió hoy?” | consultar_kilos |
| “Hazme un dashboard de esta semana” | generar_dashboard |
generar_dashboard devuelve un link meshtrama.net/d/<token> con token secreto que caduca en 7 días y muestra producción, pago y colaboradores en vivo.
Migración de región
Al desplegar en una zona nueva, los nodos deben migrarse a la banda legal de uso libre de esa zona. Es un cambio de configuración (región, preset y slot), no un reflasheo. Los valores concretos los define Trama™ para cada sitio, bajo licencia.
| Parámetro | Destino |
|---|---|
region | La región regulatoria de la zona. |
modem_preset | El preset de alcance del despliegue. |
channel_num | El slot asignado por Trama para el sitio. |
Procedimiento (runbook)
1. Inventario de todos los nodos (short name, ID, firmware).
2. Backup de la config de cada nodo ANTES de tocarlo.
3. Migrar uno por uno; verificar región + preset + slot en cada uno.
4. Verificar la FRECUENCIA efectiva, no solo la región.
5. El nodo del gateway (CTRL) se migra al FINAL:
- detener el servicio → aplicar → verificar → reiniciar.
6. Verificar de verdad: last_heard fresco + prueba extremo-a-extremo.# Cambiar la config de radio (con el servicio detenido si es el CTRL) meshtastic --port /dev/ttyACM0 \ --set lora.region <REGION> \ --set lora.modem_preset <PRESET> \ --set lora.channel_num <SLOT>
Migra todo el sitio en una sola ventana. Un nodo que quede en US no vuelve a aparecer en la malla hasta que se corrija — y la lista de nodos no lo delata; solo el last_heard fresco lo confirma.
Referencia
Tablas de Supabase
| Tabla | Contenido |
|---|---|
nodes | Nodos vistos por el gateway (short name, last_seen, batería…). |
campo_clientes | Fincas: nombre, zona, unidad, tarifa, labor. |
colaboradores | Personas de cada finca. |
registros | Capturas reales de producción (kg, GPS, colaborador). |
dashboards | Links firmados de dashboards (token, periodo, caducidad). |
wa_inbox / relay_* | Cola y conversaciones del relay de WhatsApp. |
leads | Solicitudes de contacto de la landing. |
Endpoints de la webapp
| Ruta | Uso |
|---|---|
/api/whatsapp/webhook | Recibe los mensajes de la Cloud API (crítico para el relay). |
/api/client/active | Config de marca de la finca activa (la app la lee al arrancar). |
/d/[token] | Dashboard de producción por token. |
CLI de Meshtastic
meshtastic --port <puerto> --info # ver config del nodo meshtastic --port <puerto> --export-config # backup meshtastic --port <puerto> --configure f.yaml # restaurar