Skip to content

Desarrollo

monitoreo-ugr edited this page Nov 6, 2026 · 18 revisions

English version

Desarrollo

Para quien cambia el código de MonitorEO o publica sus versiones. Para usar las herramientas, empieza por Primeros pasos.

Idiomas de los textos

Los textos de las herramientas (plugin de QGIS, asistente para gestores, app de Earth Engine, visor de resultados, informes, instaladores, línea de comandos, paquetes de R y de Python, servidor MCP) están en inglés; la documentación, en español e inglés. Cada página de la wiki tiene su página en inglés (y el README, los dos idiomas). Así, los textos nuevos de una herramienta se escriben en inglés y las secciones nuevas del manual, en los dos idiomas. El asistente para gestores sigue respondiendo en el idioma de cada pregunta.

Dónde está cada herramienta

Todas usan las mismas funciones (monitoreo.services), así que el mismo cálculo da el mismo resultado en todas; la app de Earth Engine es la traducción a JavaScript del núcleo del paquete.

Herramienta Carpeta del repositorio Manual
App de Earth Engine gee App de Earth Engine
Paquete de Python monitoreo y línea de comandos src/monitoreo (cli.py) Python, Línea de comandos
Plugin de QGIS MonitorEO qgis/monitoreo_qgis QGIS
Servidor MCP src/monitoreo/mcp_server.py MCP
Asistente para gestores src/monitoreo/assistant.py (servidor web, ventana y cliente del MCP), ui/assistant.html (la página, con Leaflet en ui/vendor), report.py (el informe y las vistas del mapa), engine.py (Ollama) y manual.py (búsqueda en esta wiki) Asistente
Paquete de R monitoreo r/monitoreo R
Visor de resultados src/monitoreo/viewer, monitoreo publish Visor de resultados

Todo se calcula en Google Earth Engine: con la cuenta y el proyecto de cada usuario o, sin proyecto, con la cuenta compartida de MonitorEO (la app, siempre con el proyecto de MonitorEO). El único servidor es el pequeño intermediario de la cuenta compartida, en Cloud Run.

Catálogo

src/monitoreo/catalog.json es el catálogo de variables y se mantiene a mano en este repositorio: colección, fórmula, escala y desplazamiento de las bandas, unidad, bandas de calidad y rampa de colores de cada una. catalog.EXTRA añade el NBR de Sentinel-2 y Landsat (incendios). La app de Earth Engine lleva una copia, que escribe gee/build.py.

Detalles del cálculo, en el código:

  • FIXES en catalog.py: la escala del LAI de MCD15A3H es 0.1, no 0.01.
  • La escala y el desplazamiento de las bandas se aplican antes de la fórmula (EVI, el albedo y la clorofila de Sentinel-2 necesitan reflectancias, no las bandas sin escalar).
  • Los nombres de banda de las fórmulas se comparan sin mayúsculas (LST_day_1km de las entradas 15 y 16).
  • Los valores de bandera de MODIS (p. ej. 250 = nube en NDSI_Snow_Cover) se descartan siempre.
  • Landsat 7 solo se usa hasta el 31-5-2003, como dice el catálogo.
  • WDPA cambió su esquema en Earth Engine: el ID es ahora SITE_ID (antes WDPAID).

Pruebas

pytest tests/test_offline.py tests/test_publish.py tests/test_assistant.py   # sin Earth Engine ni red
EE_PROJECT=mi-proyecto pytest -m ee                  # con Earth Engine (la app de gee, con npm install en gee)

Las pruebas usan el código de src/ del clon aunque el entorno tenga instalada la versión de GitHub. Si hay paquetes instalados con pip install --user, añade PYTHONNOUSERSITE=1 (ver Problemas frecuentes).

Para probar la línea de comandos o el servidor MCP con cambios sin publicar: PYTHONPATH=src python -m monitoreo.cli mcp --no-update (o pip install -e . en un entorno aparte, que ni monitoreo mcp ni eHabitat+ actualizan). El asistente, igual: PYTHONPATH=src python -m monitoreo.cli assistant --no-update.

En el asistente, el modelo solo ve las respuestas de list_variables, describe_variable y find_protected_areas (ADVICE en assistant.py) y las de las exportaciones a Google Drive y task_status (TASKS, sin valores: el identificador y el estado de la tarea); las de las herramientas de cálculo y de descarga (RESULTS) van a la página y al informe, y el modelo recibe un acuse sin valores. La herramienta manual no es del servidor MCP: la responde el asistente con manual.search, que busca en esta wiki (descargada de raw.githubusercontent.com/wiki/... a ~/MonitorEO/wiki); por eso lo que se escriba aquí es lo que el asistente sabe de MonitorEO. OTHER_TOOLS reconoce las peticiones para otras herramientas, y fix_links cambia los enlaces a la wiki que no existen. tests/test_assistant.py lo comprueba con un modelo de prueba. Las instrucciones del modelo (PROMPT, con la guía de sensores y la lista de variables del catálogo) están en el mismo fichero y se actualizan con el paquete.

La página se abre en una ventana propia con pywebview (WebKit en macOS, WebView2 en Windows, Qt WebEngine o GTK en Linux): run arranca el servidor en un hilo y la ventana en el principal, y cerrarla para el servidor (si hay un cálculo en marcha, pywebview pregunta antes: el evento closing pone confirm_close, y WINDOW_TEXTS traduce la pregunta y el menú de macOS; la página no muestra entonces Close the assistant); sin pywebview, o si no puede abrirla, usa el navegador (--browser lo fuerza). La actualización al arrancar (_update_in_window en cli.py) muestra una ventanita mientras pip instala y después arranca el asistente en otro proceso, porque pywebview solo arranca una vez en cada uno. Los mapas de la página usan Leaflet 1.9.4, copiado en ui/vendor/leaflet (licencia BSD-2) para que funcione sin depender de un CDN, con las teselas de Earth Engine de map_layer, trend_map y compare_map; los resultados sobre regiones (PERIOD_MAP) traen además el mapa de la mediana de su periodo, o de su último año si es más largo (Assistant.period_map: map_layer con quick=True, solo las teselas, sin vista previa y con la rampa de color del catálogo, porque calcular los percentiles de la mediana de años de imágenes sobre un espacio grande tarda o agota la memoria de Earth Engine; quick está oculto al modelo como los argumentos de HIDDEN). Los mapas de cada paso (steps.map_steps, con las ventanas de composite.windows y composite.bins, las mismas de las series) se hacen al elegirlos en la página (/api/map/step, Assistant.step_map), con quick y el vmin y vmax del mapa del resultado. El plugin de QGIS ofrece los mismos pasos en las ventanas de sus series y tendencias (result_maps en dock.py), pero como GeoTIFF (download_image y download_trend), con la rampa del primer mapa del resultado aplicada en QGIS. Si los percentiles fallan en cualquier mapa, maps.vis_params usa también la rampa del catálogo. El valor y la serie de un píxel son region_stats y time_series con {"point": [lon, lat]}. Add this view to the report compone en el servidor (report.map_view, con Pillow) las teselas del fondo y las de Earth Engine del encuadre, con el píxel marcado y los créditos, en un PNG que va dentro del informe.

Los instaladores están en installer/: macos/instalar.sh, linux/instalar.sh y windows/instalar.bat (guardado con los finales de línea de Windows, -text en .gitattributes, y sin acentos). Instalan el environment.yml de main con micromamba en ~/MonitorEO/entorno, crean el acceso del Escritorio (en Windows, un acceso con el mismo nombre) y abren el asistente con python -s -m monitoreo.cli assistant, sin terminal: en macOS, la app MonitorEO Assistant.app (un Info.plist y un script; como la crea el propio ordenador, no está en cuarentena y no hace falta firmarla); en Windows, un acceso a pythonw.exe. Sin terminal, los mensajes van a ~/MonitorEO/assistant-output.log. Se descargan de raw.githubusercontent.com con las órdenes de una línea de Asistente (lo que descarga curl no queda en cuarentena en macOS ni con la marca de Internet en Windows, así que no los bloquean por no estar firmados) o en zip: el flujo .github/workflows/installers.yml los comprime (asistente-monitoreo-macos.zip, como Install the MonitorEO assistant.command con el permiso de ejecución, y asistente-monitoreo-windows.zip, con Install the MonitorEO assistant.bat) y los adjunta a cada release; la wiki los enlaza en releases/latest/download/. Para adjuntarlos a una release que ya existe: Actions > Assistant installers > Run workflow, con su etiqueta. Para que macOS y Windows abran los zips sin avisos habría que firmarlos (en macOS, con un certificado Developer ID de Apple y su notarización). Para probar el de macOS sin tocar tu carpeta: HOME=/tmp/prueba bash installer/macos/instalar.sh (la app que abre al final usa tu HOME de verdad, porque macOS no le pasa el de la orden: ciérrala).

El de Windows comprueba que micromamba.exe arranca: necesita el runtime de Visual C++ (MSVCP140.dll, VCRUNTIME140.dll...), que un Windows recién instalado no tiene (el error 0xC0000135). Si falta, copia junto a micromamba.exe las DLL del paquete vc14_runtime de conda-forge (un .conda: un zip con un .tar.zst, que abre el tar de Windows 11), solo si las firma Microsoft (Get-AuthenticodeSignature), sin instalar nada en el sistema. Instala con CONDA_PKGS_DIRS=%SystemDrive%\MonitorEO-pkgs, que borra al terminar: micromamba guarda los paquetes bajo la dirección de su canal (pkgs\https\conda.anaconda.org\conda-forge\win-64\...) y, en la carpeta del usuario, algunas rutas pasan de los 260 caracteres de MAX_PATH (las rutas largas de Windows necesitan un administrador); allí la más larga tiene 234 con cualquier nombre de usuario. Por lo mismo el entorno lleva matplotlib-base y no matplotlib, que en Windows trae PySide6 y Qt (qt6-main, con rutas de 261 caracteres para un usuario de 6 letras), que no usa. El acceso del Escritorio abre el asistente con pythonw.exe, sin consola: update._pip da a pip un stderr (su stdout), porque subprocess le daría si no una tubería cerrada, en la que escribir hace que acabe con el estado 120 aunque haya instalado el paquete. Se probó en un Windows 11 recién instalado en una máquina virtual (UTM en un Mac), con un usuario administrador.

El icono de la app, del acceso de Windows y del lanzador de Ubuntu es el logotipo del plugin de QGIS (qgis/monitoreo_qgis/icon.png, de 64 px) dibujado otra vez a más resolución, con su geometría y sus colores y las esquinas transparentes: installer/icons/make_icons.py (con Pillow; el .icns, solo en un Mac, con iconutil) escribe monitoreo-assistant.icns, .ico y .png en installer/icons, de donde los descargan los instaladores.

El de Ubuntu (linux/instalar.sh, para 22.04, 24.04 y 26.04 LTS, en x86_64 y aarch64) se baja con wget, que Ubuntu trae siempre (curl no), y no va en zip: el gestor de archivos de Ubuntu no ejecuta scripts. Añade al environment.yml pyqt6-webengine y qtpy, porque pywebview necesita en Linux Qt WebEngine (el entorno no lleva Qt: tiene matplotlib-base, matplotlib sin él), y escribe el lanzador entorno/bin/monitoreo-assistant, con el que se abren ~/.local/share/applications/monitoreo-assistant.desktop y su copia del Escritorio (de confianza con gio set ... metadata::trusted true, para que Ubuntu la abra). El lanzador elige PyQt6 (QT_API), X11 (XWayland en Wayland) y RESOURCE_NAME=monitoreo-assistant, que da a la ventana el WM_CLASS del .desktop (si no, es cli.py y el dock no la asocia a su icono), y quita el sandbox de Chromium (QTWEBENGINE_DISABLE_SANDBOX=1): su filtro seccomp mata el proceso de la página (SIGSYS) con kernels y glibc recientes, y Ubuntu 24.04 solo da los user namespaces a los programas con perfil de AppArmor; la ventana solo muestra la página local del asistente. El job linux de installers.yml lo prueba en Ubuntu 22.04 y 24.04 (también en cada push que cambie installer/, environment.yml o el flujo): lo instala, abre el asistente en una pantalla virtual (Xvfb) y comprueba que la captura no está en blanco. En local, con Docker y una imagen ubuntu:24.04 con wget, xvfb, x11-utils e imagemagick, como un usuario que no sea root.

La versión de Ollama que instala el asistente es OLLAMA en engine.py, con el tamaño y el SHA-256 del fichero de cada sistema en ASSETS (el digest de cada fichero en https://api.github.com/repos/ollama/ollama/releases/tags/<versión>). Quien ya tiene instalada otra versión la sigue usando (Engine.installed); la nueva se descarga cuando no hay ninguna.

Plugin de QGIS

Generar el zip a mano: python qgis/build_plugin.py (descarga las dependencias, así que necesita internet; queda en dist/). El zip lleva dentro monitoreo y la librería de Earth Engine con sus dependencias (Python puro, válido en Windows, macOS y Linux). Con bandit y detect-secrets instalados, lo analiza como plugins.qgis.org y falla si el plugin o monitoreo tienen algún hallazgo.

Probarlo sin ventana con el Python de QGIS (calcula en Earth Engine):

PYTHONNOUSERSITE=1 EE_PROJECT=mi-proyecto /Applications/QGIS-final-4_0_3.app/Contents/MacOS/python qgis/test_plugin.py

Publicar una versión:

  1. Sube version= en qgis/monitoreo_qgis/metadata.txt, haz commit y push.
  2. Publica una release en GitHub (Releases > Draft a new release, etiqueta nueva con esa versión, p. ej. v0.3.7, Publish release). También vale subir la etiqueta desde GitHub Desktop (History, botón derecho sobre el commit, Create Tag…, Push origin): el flujo crea la release.
  3. Unos minutos después, el flujo .github/workflows/qgis-plugin.yml (pestaña Actions) genera el zip en GitHub, lo adjunta a la release y, si el repositorio tiene el secreto QGIS_PLUGINS_TOKEN, lo sube a plugins.qgis.org, donde pasa el análisis de seguridad y la aprobación antes de publicarse. Falla si la etiqueta no coincide con version= (0.2 y v0.2.0 valen para 0.2.0).

Para adjuntar el zip a una release que ya existe: Actions > QGIS plugin > Run workflow, con su etiqueta.

Paquetes de Python y R

La versión está en pyproject.toml, src/monitoreo/__init__.py y r/monitoreo/DESCRIPTION. Se instalan desde GitHub (rama main o una etiqueta), así que basta con subir el cambio; el servidor MCP se actualiza solo a la última versión de GitHub cada vez que arranca (MCP).

Cuenta compartida

Sin proyecto (init() sin EE_PROJECT, init(shared=True), el campo de proyecto vacío en QGIS y en el asistente, mo_init("") en R), las herramientas calculan con la cuenta de servicio monitoreo-public del proyecto ee-ugr-default-project. Su token, de una hora y solo para Earth Engine, lo da el intermediario de broker/ (main.py, solo con la biblioteca estándar de Python), desplegado en Cloud Run en https://monitoreo-broker-872770286973.europe-west1.run.app (GET /token; su dirección está en services.BROKER, y MONITOREO_BROKER la cambia). El paquete pide otro token cuando caduca y no deja exportar a Google Drive con esta cuenta.

No hay ninguna clave que pueda filtrarse: el servicio se ejecuta como monitoreo-broker, que solo puede crear tokens de monitoreo-public, y esta tiene el rol monitoreoCompute, que solo calcula (valores, píxeles, mapas, miniaturas y tablas del catálogo público de Earth Engine): no lee los assets del proyecto ni sus tareas, ni exporta. Por eso no se usa el rol earthengine.viewer, que dejaría a cualquiera con un token leer los assets del proyecto. El contenedor lo compila monitoreo-build (rol run.builder). Cada dirección puede pedir 60 tokens por hora; la cuota de Earth Engine es la del proyecto, compartida con la app.

Cada usuario de la cuenta compartida tiene sus research EECUs: USER_LIMIT EECU-h al mes (10 por defecto), para que nadie gaste la cuota del proyecto, que es de todos. El usuario es el identificador anónimo de cada instalación (services.user_id(): mo- y 16 cifras hexadecimales al azar, en ~/.config/monitoreo/user_id), que el paquete manda al pedir el token (/token?user=) y pone como workload tag de Earth Engine en todo lo que calcula. El intermediario (monitoreo-broker, con el rol Monitoring Viewer del proyecto) lee la métrica «Completed EECU-seconds» de Cloud Monitoring agrupada por workload tag desde el día 1 del mes (una consulta para todos, cada 5 minutos) y no da tokens a quien ha gastado los suyos hasta el mes siguiente (403 con code: spent; el token que ya tiene dura como mucho una hora más). GET /usage?user= dice lo gastado por el usuario y por el proyecto (EECU_LIMIT, la cuota del nivel del proyecto, 150 por defecto). Sin identificador (las versiones anteriores a la 0.3.21) no hay token, salvo con REQUIRE_USER=0; si Cloud Monitoring no responde, se dan tokens. Se cambian al desplegar: USER_LIMIT=20 broker/deploy.sh ee-ugr-default-project. El límite se basa en la buena fe: quien borre el fichero del identificador empieza con uno nuevo (el interruptor de abajo sigue ahí). Con su cuenta, las herramientas leen la métrica de su proyecto directamente (services.eecu_usage).

  • Desplegar o actualizar: broker/deploy.sh ee-ugr-default-project con gcloud iniciado con una cuenta propietaria del proyecto (everest@go.ugr.es). Se puede repetir: crea lo que falta y despliega una revisión nueva.
  • Pararla al momento (los tokens ya dados dejan de valer): gcloud iam service-accounts disable monitoreo-public@ee-ugr-default-project.iam.gserviceaccount.com --project ee-ugr-default-project, y enable para volver a abrirla.
  • Uso: los registros de Cloud Run (monitoreo-broker, región europe-west1) y la cuota de Earth Engine del proyecto en la consola de Google Cloud.

App de Earth Engine y visor de resultados

Licencia

Copyright (C) 2026 OBSNEV, Universidad de Granada.

GNU General Public License v3.0 o posterior (GPL-3.0-or-later; texto completo en LICENSE): se puede usar, copiar, modificar y redistribuir, también con fines comerciales, manteniendo los avisos de autoría (MonitorEO, OBSNEV, Universidad de Granada) y distribuyendo las versiones modificadas con la misma licencia y su código fuente. Es la licencia de los plugins de QGIS (QGIS es GPL v2 o posterior) y admite las librerías con licencia Apache 2.0 que lleva el plugin (earthengine-api y las de Google). Los datos y mapas del visor de resultados tienen su propia licencia (CC BY 4.0 por defecto).

Clone this wiki locally