9.2 KiB
UniFi UDM Pro — skill de diagnóstico local
Qué es esto
Skill 100% local que consulta el UDM Pro del beneficio Rio Frio (192.168.87.5)
usando la Integration API oficial de UniFi Network (≥ v9.3.43, X-API-KEY stateless).
No hay servidor intermedio, no hay MCP server, no hay nada en el Swarm. Solo curl
desde tu PC contra el UDM Pro vía la LAN o a través del DNS interno.
- Base URL:
https://192.168.87.5/proxy/network/integration/v1 - Auth: header
X-API-KEY: $UNIFI_API_KEY - El API key vive en:
~/.claude/skills/unifi/.env(local, no versionado) - Scope: read-only (Integration API write está en preview, no lo tocamos)
Cómo invocarla correctamente
Antes de cualquier query:
- Verifica que
~/.claude/skills/unifi/.envexista. Si no, avísale al usuario y dale el comando para crearlo (ver "Setup inicial" más abajo). - Verifica conectividad básica con un
GET /sites. Si falla con 401/403 → API key inválida o caducada. Si falla con conexión rechazada/timeout → no estás en la LAN del beneficio (recordá que192.168.87.5no es ruteable desde fuera).
Dos APIs, dos scripts
| Script | API | Auth | Cuándo usar |
|---|---|---|---|
query.sh |
Integration API v1 | X-API-KEY (stateless) |
devices, clients (sin bytes/signal), networks, vouchers, statistics/latest |
query-classic.sh |
Classic API | session cookie + CSRF (login flow, cache 25 min) | health, eventos, alarmas, bytes por cliente, SSID/signal, configs (WLANs, firewall, port forwards) |
query.sh (Integration API)
~/.claude/skills/unifi/scripts/query.sh /sites
~/.claude/skills/unifi/scripts/query.sh "/sites/{site}/devices"
~/.claude/skills/unifi/scripts/query.sh "/sites/{site}/clients"
El placeholder
{site}se expande automáticamente al UUID del site ($UNIFI_SITEen.env). La Integration API exige UUID, NO el nombredefault. Siempre comillas dobles alrededor del path para que la shell no interprete las llaves.
query-classic.sh (Classic API — para todo lo que la Integration no expone)
~/.claude/skills/unifi/scripts/query-classic.sh /stat/health # WAN/WLAN/LAN/UDM stats
~/.claude/skills/unifi/scripts/query-classic.sh /stat/sta # clientes CON bytes/signal/SSID
~/.claude/skills/unifi/scripts/query-classic.sh /stat/event # eventos (login, roaming, etc)
~/.claude/skills/unifi/scripts/query-classic.sh /stat/alarm # alarmas
~/.claude/skills/unifi/scripts/query-classic.sh /list/wlanconf # WLANs / SSIDs
~/.claude/skills/unifi/scripts/query-classic.sh /rest/firewallrule
El path corto (/stat/...) se prefija a /proxy/network/api/s/$UNIFI_SITE_NAME automáticamente.
La sesión se cachea 25 min en .cache/cookies.txt + .cache/csrf (chmod 600).
Read-only por diseño — modelo de seguridad
Tres capas, en orden de fuerza:
- Server-side (la que importa): la cuenta
claudecode0tiene rol "Site View Only" en Network. El UDM responde 403 a cualquier POST/PUT/DELETE sin importar qué cliente intente, vía API key o via Classic. Esto es lo que te garantiza no romper nada. - Guard en los scripts:
query.shyquery-classic.shrechazan flags-X POST/PUT/DELETE/PATCHy-d/--datacon exit 3 antes de salir a la red. Defensa en profundidad — falla rápido con error claro. - Doc: esta sección. Si Claude (yo o cualquier futura sesión) lee esto y aún así intenta escribir, el server lo bloqueará igual.
⚠️ La API Key del
.envla generó el Owner del UDM (noclaudecode0, porque View Only no puede crear keys). Técnicamente esa key tiene scope completo — el guard del script y la convención son lo único que evitan que alguien la use para escribir vía Integration API. Si querés blindaje total ahí también, pedile al Owner que regenere una key suya y revoque la actual.
Si no tenés jq
Los ejemplos de endpoints.md usan jq por brevedad. Si no está instalado
(ej. git bash en Windows sin extras), tenés dos opciones:
- Instalar jq (recomendado, una vez):
winget install jqlang.jq # o: choco install jq - Usar Python como filtro (ya viene con la PC):
~/.claude/skills/unifi/scripts/query.sh "/sites/{site}/devices" \ | python -c "import json,sys; d=json.load(sys.stdin); [print(x['name'], x['state']) for x in d['data']]"
Flujos típicos de diagnóstico
"¿qué está conectado a la red?"
~/.claude/skills/unifi/scripts/query.sh /sites/{site}/clients | jq '.data | length'
~/.claude/skills/unifi/scripts/query.sh /sites/{site}/clients | jq '.data[] | {name, mac, ip, type, uplinkDeviceId, lastSeen}'
Filtra por type (WIRED vs WIRELESS) y por uplinkDeviceId para saber a qué AP/switch está pegado cada uno.
"¿están todos los APs online?"
~/.claude/skills/unifi/scripts/query.sh /sites/{site}/devices | jq '.data[] | {name, model, state, ip, mac, uptime}'
state: ONLINE | OFFLINE | PROVISIONING | UPGRADING | .... Reporta cualquier device con state ≠ ONLINE.
"¿la báscula sacos_bodega (o impresora patio, etc.) está conectada?"
- Busca el equipo en
topology.md(mapeo nombre → MAC). - Si no está mapeado todavía: lista clientes y proponé al usuario el match más probable basándote en el nombre o en la IP fija conocida (las impresoras del manifest tienen IP fija:
printerCentralcubre192.168.87.142, .147, .150, .220, .221). - Una vez tengas el MAC:
query.sh /sites/{site}/clients | jq '.data[] | select(.mac == "AA:BB:...")' - Si lo encontrás, agregá el mapeo a
topology.mdpara futuras queries.
"¿qué AP cubre tal facility?"
Combiná topology.md (zonas físicas → AP esperado) + el listado real de devices filtrado por nombre/ubicación que tengan configurado en el UDM.
"¿qué carga tiene cada AP / cuál está saturado?"
La Integration API NO devuelve bytes ni count de clientes en /clients ni en /devices.
Lo que SÍ tenés es statistics/latest por device, con CPU%, RAM%, uplink tx/rxBps y
% de retransmisiones por radio (indicador de saturación inalámbrica):
~/.claude/skills/unifi/scripts/query.sh "/sites/{site}/devices/<deviceId>/statistics/latest"
Para ranking de clientes por bytes consumidos NO hay endpoint — necesita Classic API.
"muéstrame el estado del WAN / uplink"
No está en la Integration API. Por device sí podés ver uplink.txRateBps/rxRateBps
en statistics/latest, pero el health agregado del WAN (latencia, drops, ISP status)
solo está en Classic API. Si el usuario insiste, avisale que toca extender la skill
con query-classic.sh (login flow). No lo improvises sin avisar.
Setup inicial (lo hace el usuario UNA vez)
- Generar API Key en el UDM Pro UI:
- Abrí
https://192.168.87.5en el navegador (o el dominio interno si lo tenés mapeado). - Loggéate con admin local (NO cuenta cloud).
- UniFi Network → Settings → Control Plane → Integrations.
- "Create API Key", copiá el valor (solo se muestra una vez).
- Abrí
- Crear el
.env:cp ~/.claude/skills/unifi/.env.example ~/.claude/skills/unifi/.env # Editar y pegar el API key: # UNIFI_API_KEY=<el valor que copiaste> - Probar:
Esperado: JSON con un array
~/.claude/skills/unifi/scripts/query.sh /sitesdataque contenga al menosdefault.
Notas sobre red
- El UDM Pro está SOLO accesible desde la LAN (192.168.87.0/24). Si vas a usar esta skill desde fuera del beneficio, necesitás VPN/Tailscale o un túnel.
- El cert TLS del UDM Pro es self-signed → el helper usa
curl -k. Es aceptable para tráfico en la LAN, pero no copies ese patrón a apps en producción. - DNS interno (
*.interno) lo sirve este mismo UDM. Si la skill empieza a fallar en resolución, probá apuntar a la IP cruda192.168.87.5.
Qué NO hace esta skill
- No escribe (no bloquea/desbloquea clientes, no provisiona VLANs, no reinicia APs). Read-only por diseño.
- No habla con UniFi Protect, Access ni Talk. Solo Network.
- No mantiene cache local. Cada query golpea el UDM Pro.
- No expone MCP — es Bash + curl. Si más adelante querés exponerla a Claude Desktop o a la
agentUI, ahí sí justifica un sidecar Bun en el Swarm.
Referencias
endpoints.md— cheat sheet de los 15 endpoints Integration API v1 + algunos Classic útilestopology.md— mapa de MACs/IPs → equipo del beneficio (jala del manifest, se llena con uso)- Doc oficial: https://developer.ui.com/ (Integration API)