Repository navigation
Development
For those who change the code of MonitorEO or publish its versions. To use the tools, start with Getting started.
The texts of the tools (QGIS plugin, assistant for managers, Earth Engine app, results viewer, reports, installers, command line, R and Python packages, MCP server) are in English; the documentation is in Spanish and English. Each wiki page has its English page (and the README has both languages). So the new texts of a tool are written in English, and the new sections of the manual are written in both languages. The assistant for managers keeps answering in the language of each question.
They all use the same functions (monitoreo.services), so the same computation gives the same result in all of
them; the Earth Engine app is the JavaScript translation of the core of the package.
| Tool | Folder of the repository | Manual |
|---|---|---|
| Earth Engine app | gee |
Earth Engine app |
Python package monitoreo and command line |
src/monitoreo (cli.py) |
Python package, Command line |
| QGIS plugin MonitorEO | qgis/monitoreo_qgis |
QGIS plugin |
| MCP server | src/monitoreo/mcp_server.py |
MCP server |
| Assistant for managers |
src/monitoreo/assistant.py (web server, window and MCP client), ui/assistant.html (the page, with Leaflet in ui/vendor), report.py (the report and the map views), engine.py (Ollama) and manual.py (search in this wiki) |
Assistant |
R package monitoreo
|
r/monitoreo |
R package |
| Results viewer |
src/monitoreo/viewer, monitoreo publish
|
Results viewer |
Everything is computed in Google Earth Engine: with the account and project of each user or, without a project, with the shared account of MonitorEO (the app, always with the project of MonitorEO). The only server is the small broker of the shared account, in Cloud Run.
src/monitoreo/catalog.json is the catalog of variables and is maintained by hand in this repository: collection,
formula, scale and offset of the bands, unit, quality bands and colour ramp of each one. catalog.EXTRA adds the NBR
of Sentinel-2 and Landsat (fires). The Earth Engine app carries a copy, written by gee/build.py.
Details of the computation, in the code:
-
FIXESincatalog.py: the scale of the LAI of MCD15A3H is 0.1, not 0.01. - The scale and offset of the bands are applied before the formula (EVI, the albedo and the chlorophyll of Sentinel-2 need reflectances, not the unscaled bands).
- The band names of the formulas are compared case-insensitively (
LST_day_1kmof entries 15 and 16). - The MODIS flag values (e.g. 250 = cloud in
NDSI_Snow_Cover) are always discarded. - Landsat 7 is only used until 31-5-2003, as the catalog says.
- WDPA changed its schema in Earth Engine: the ID is now
SITE_ID(before,WDPAID).
pytest tests/test_offline.py tests/test_publish.py tests/test_assistant.py # without Earth Engine or network
EE_PROJECT=my-project pytest -m ee # with Earth Engine (the gee app, with npm install in gee)The tests use the code of src/ of the clone even if the environment has the GitHub version installed. If there are
packages installed with pip install --user, add PYTHONNOUSERSITE=1 (see Troubleshooting).
To test the command line or the MCP server with unpublished changes:
PYTHONPATH=src python -m monitoreo.cli mcp --no-update (or pip install -e . in a separate environment, which
neither monitoreo mcp nor eHabitat+ update). The assistant, the same way: PYTHONPATH=src python -m monitoreo.cli assistant --no-update.
In the assistant, the model only sees the answers of list_variables, describe_variable and
find_protected_areas (ADVICE in assistant.py) and those of the exports to Google Drive and task_status
(TASKS, without values: the identifier and the state of the task); those of the computation and download tools
(RESULTS) go to the page and the report, and the model receives an acknowledgement without values. The manual tool
is not of the MCP server: the assistant answers it with manual.search, which searches this wiki (downloaded from
raw.githubusercontent.com/wiki/... to ~/MonitorEO/wiki); so what is written here is what the assistant knows about
MonitorEO. OTHER_TOOLS recognizes the requests for other tools, and fix_links changes the links to the wiki that do
not exist. tests/test_assistant.py checks it with a test model. The instructions of the model (PROMPT, with the
guide of sensors and the list of variables of the catalog) are in the same file and are updated with the package.
The page opens in its own window with pywebview (WebKit on macOS, WebView2 on Windows,
Qt WebEngine or GTK on Linux): run starts the server in a thread and the window in the main one, and closing it stops the
server (if a computation is running, pywebview asks first: the closing event sets confirm_close, and
WINDOW_TEXTS translates the question and the macOS menu; the page then does not show Close the assistant);
without pywebview, or if it cannot open it, it uses the browser (--browser forces it). The update at startup
(_update_in_window in cli.py) shows a small window while pip installs and then starts the assistant in another
process, because pywebview only starts once in each. The maps of the page use Leaflet 1.9.4,
copied in ui/vendor/leaflet (BSD-2 license) so that it works without depending on a CDN, with the Earth Engine tiles
of map_layer, trend_map and compare_map; the results over regions (PERIOD_MAP) also bring the map of the median
of their period, or of their last year if it is longer (Assistant.period_map: map_layer with quick=True, only the
tiles, without preview and with the colour ramp of the catalog, because computing the percentiles of the median of
years of images over a large space is slow or exhausts the memory of Earth Engine; quick is hidden from the model
like the arguments of HIDDEN). The maps of each step (steps.map_steps, with the windows of composite.windows and
composite.bins, the same ones as the series) are made when they are chosen in the page (/api/map/step,
Assistant.step_map), with quick and the vmin and vmax of the map of the result. The QGIS plugin offers the same
steps in the windows of its series and trends (result_maps in dock.py), but as GeoTIFF (download_image and
download_trend), with the ramp of the first map of the result applied in QGIS. If the percentiles fail in any map,
maps.vis_params also uses the ramp of the catalog. The value and the series of a pixel are region_stats and
time_series with {"point": [lon, lat]}. Add this view to the report composes on the server (report.map_view,
with Pillow) the background tiles and the Earth Engine ones of the frame, with the pixel marked and the credits, in a
PNG that goes inside the report.
The installers are in installer/: macos/instalar.sh, linux/instalar.sh and windows/instalar.bat (saved with Windows line endings,
-text in .gitattributes, and without accents). They install the environment.yml of main with micromamba in
~/MonitorEO/entorno, create the Desktop shortcut and open the assistant with python -s -m monitoreo.cli assistant,
without a terminal: on macOS, the app MonitorEO Assistant.app (an Info.plist and a script; since the computer
itself creates it, it is not quarantined and does not need to be signed); on Windows, a shortcut to pythonw.exe.
Without a terminal, the messages go to ~/MonitorEO/assistant-output.log. They are downloaded from
raw.githubusercontent.com with the one-line commands of Assistant (what curl downloads is
not quarantined on macOS nor given the Internet mark on Windows, so they are not blocked for being unsigned) or as a
zip: the workflow .github/workflows/installers.yml compresses them (asistente-monitoreo-macos.zip, with
Install the MonitorEO assistant.command with the execute permission, and asistente-monitoreo-windows.zip, with
Install the MonitorEO assistant.bat) and attaches them to each release; the wiki links
them at releases/latest/download/. To attach them to a release that already exists: Actions > Assistant installers >
Run workflow, with its tag. For macOS and Windows to open the zips without warnings they would have to be signed (on
macOS, with an Apple Developer ID certificate and its notarization). To test the macOS one without touching your
folder: HOME=/tmp/test bash installer/macos/instalar.sh (the app it opens at the end uses your real HOME, because
macOS does not pass it the one of the command: close it).
The Windows one checks that micromamba.exe starts: it needs the Visual C++ runtime (MSVCP140.dll,
VCRUNTIME140.dll...), which a newly installed Windows does not have (the error 0xC0000135). If it is missing, it
copies next to micromamba.exe the DLLs of the package vc14_runtime of conda-forge (a .conda: a zip with a
.tar.zst, which the tar of Windows 11 opens), only if Microsoft signs them (Get-AuthenticodeSignature), without
installing anything in the system. It installs with CONDA_PKGS_DIRS=%SystemDrive%\MonitorEO-pkgs, which it deletes
at the end: micromamba keeps the packages under the address of their channel
(pkgs\https\conda.anaconda.org\conda-forge\win-64\...) and, in the folder of the user, some paths pass the 260
characters of MAX_PATH (the long paths of Windows need an administrator); there the longest has 234 with any user
name. For the same reason the environment has matplotlib-base and not matplotlib, which on Windows brings PySide6
and Qt (qt6-main, with paths of 261 characters for a user name of 6 letters), which it does not use. The Desktop
shortcut opens the assistant with pythonw.exe, without a console: update._pip gives pip a stderr (its stdout),
because otherwise subprocess would give it a closed pipe, where writing makes it end with the status 120 even when
it has installed the package. It was tested in a newly installed Windows 11 in a virtual machine (UTM on a Mac), with
an administrator user.
The icon of the app, of the Windows shortcut and of the Ubuntu launcher is the logo of the QGIS plugin
(qgis/monitoreo_qgis/icon.png, of 64 px) drawn again at a larger size, with its geometry and its colours and
transparent corners: installer/icons/make_icons.py (with Pillow; the .icns, only on a Mac, with iconutil)
writes monitoreo-assistant.icns, .ico and .png in installer/icons, from where the installers download them.
The Ubuntu one (linux/instalar.sh, for 22.04, 24.04 and 26.04 LTS, on x86_64 and aarch64) is downloaded with
wget, which Ubuntu always has (curl not), and is not zipped: the file manager of Ubuntu does not run scripts. It
adds pyqt6-webengine and qtpy to the environment.yml, because pywebview needs Qt WebEngine on Linux (the environment has
no Qt: it has matplotlib-base, matplotlib without it), and writes the launcher entorno/bin/monitoreo-assistant,
which ~/.local/share/applications/monitoreo-assistant.desktop and its copy on the Desktop open (trusted with
gio set ... metadata::trusted true, so that Ubuntu opens it). The launcher chooses PyQt6 (QT_API), X11 (XWayland
on Wayland) and RESOURCE_NAME=monitoreo-assistant, which gives the window the WM_CLASS of the .desktop (else it
is cli.py and the dock does not match it to its icon), and removes the sandbox of Chromium
(QTWEBENGINE_DISABLE_SANDBOX=1): its seccomp filter kills the process of the page (SIGSYS) with recent kernels and
glibc, and Ubuntu 24.04 only gives user namespaces to the programs with an AppArmor profile; the window only shows the
local page of the assistant. The job linux of installers.yml tests it on Ubuntu 22.04 and 24.04 (also on each
push that changes installer/, environment.yml or the workflow): it installs it, opens the assistant in a virtual
screen (Xvfb) and checks that the screenshot is not blank. Locally, with Docker and an ubuntu:24.04 image with
wget, xvfb, x11-utils and imagemagick, as a user that is not root.
The version of Ollama that the assistant installs is OLLAMA in engine.py, with the size and the SHA-256 of the
file of each system in ASSETS (the digest of each file in
https://api.github.com/repos/ollama/ollama/releases/tags/<version>). Whoever already has another version installed
keeps using it (Engine.installed); the new one is downloaded when there is none.
Build the zip by hand: python qgis/build_plugin.py (it downloads the dependencies, so it needs internet; the
result is in dist/). The zip contains monitoreo and the Earth Engine library with its dependencies (pure Python,
valid on Windows, macOS and Linux). With bandit and detect-secrets installed, it analyzes it like plugins.qgis.org
and fails if the plugin or monitoreo have any finding.
Test it without a window with the Python of QGIS (it computes in Earth Engine):
PYTHONNOUSERSITE=1 EE_PROJECT=my-project /Applications/QGIS-final-4_0_3.app/Contents/MacOS/python qgis/test_plugin.pyPublish a version:
- Raise
version=inqgis/monitoreo_qgis/metadata.txt, commit and push. - Publish a release on GitHub (Releases > Draft a new release, new tag with that version, e.g.
v0.3.7, Publish release). It is also valid to push the tag from GitHub Desktop (History, right-click on the commit, Create Tag…, Push origin): the workflow creates the release. - A few minutes later, the workflow
.github/workflows/qgis-plugin.yml(Actions tab) builds the zip on GitHub, attaches it to the release and, if the repository has the secretQGIS_PLUGINS_TOKEN, uploads it to plugins.qgis.org, where it goes through the security analysis and the approval before being published. It fails if the tag does not matchversion=(0.2andv0.2.0are valid for0.2.0).
To attach the zip to a release that already exists: Actions > QGIS plugin > Run workflow, with its tag.
The version is in pyproject.toml, src/monitoreo/__init__.py and r/monitoreo/DESCRIPTION. They are installed from
GitHub (branch main or a tag), so it is enough to push the change; the MCP server updates itself to the latest
version of GitHub every time it starts (MCP server).
Without a project (init() without EE_PROJECT, init(shared=True), the project field empty in QGIS and in the
assistant, mo_init("") in R), the tools compute with the service account monitoreo-public of the project
ee-ugr-default-project. Its token, valid for one hour and only for Earth Engine, is given by the broker in broker/
(main.py, only with the Python standard library), deployed in Cloud Run at
https://monitoreo-broker-872770286973.europe-west1.run.app (GET /token; its address is in services.BROKER, and
MONITOREO_BROKER changes it). The package asks for another token when it expires and does not allow exporting to
Google Drive with this account.
There is no key that can leak: the service runs as monitoreo-broker, which can only create tokens of
monitoreo-public, and this one has the role monitoreoCompute, which only computes (values, pixels, maps, thumbnails
and tables of the public Earth Engine catalog): it does not read the assets of the project nor its tasks, nor export.
That is why the role earthengine.viewer is not used, as it would let anyone with a token read the assets of the
project. The container is built by monitoreo-build (role run.builder). Each address can ask for 60 tokens per hour;
the Earth Engine quota is that of the project, shared with the app.
Each user of the shared account has their research EECUs: USER_LIMIT EECU-h per month (10 by default), so that
nobody spends the quota of the project, which belongs to everyone. The user is the anonymous identifier of each
installation (services.user_id(): mo- and 16 random hexadecimal digits, in ~/.config/monitoreo/user_id), which
the package sends when asking for the token (/token?user=) and sets as the Earth Engine workload tag of everything
it computes. The broker (monitoreo-broker, with the Monitoring Viewer role of the project) reads the metric
«Completed EECU-seconds» of Cloud Monitoring grouped by workload tag since the 1st of the month (one query for
everybody, every 5 minutes) and gives no tokens to whoever has spent theirs until the next month (403 with
code: spent; the token they already have lasts one hour more at most). GET /usage?user= tells what the user and
the project have spent (EECU_LIMIT, the quota of the tier of the project, 150 by default). Without an identifier
(versions before 0.3.21) there is no token, except with REQUIRE_USER=0; if Cloud Monitoring does not answer, tokens
are given. They are changed when deploying: USER_LIMIT=20 broker/deploy.sh ee-ugr-default-project. The limit relies
on good faith: whoever deletes the identifier file starts with a new one (the switch below is still there). With their
own account, the tools read the metric of their project directly (services.eecu_usage).
-
Deploy or update:
broker/deploy.sh ee-ugr-default-projectwithgcloudlogged in with an account that owns the project (everest@go.ugr.es). It can be repeated: it creates what is missing and deploys a new revision. -
Stop it at once (the tokens already given stop being valid):
gcloud iam service-accounts disable monitoreo-public@ee-ugr-default-project.iam.gserviceaccount.com --project ee-ugr-default-project, andenableto open it again. -
Usage: the Cloud Run logs (
monitoreo-broker, region europe-west1) and the Earth Engine quota of the project in the Google Cloud console.
- The app is generated with
gee/build.pyand published from the Code Editor: see Earth Engine app. - The viewer is a static folder written by
monitoreo publish: see Results viewer.
Copyright (C) 2026 OBSNEV, Universidad de Granada.
GNU General Public License v3.0 or later (GPL-3.0-or-later; full text in
LICENSE): it can be used, copied, modified and
redistributed, also for commercial purposes, keeping the authorship notices (MonitorEO, OBSNEV, Universidad de
Granada) and distributing the modified versions with the same license and their source code. It is the license of the
QGIS plugins (QGIS is GPL v2 or later) and it admits the Apache 2.0 licensed libraries that the plugin carries
(earthengine-api and Google's). The data and maps of the results viewer have their own license
(CC BY 4.0 by default).
MonitorEO es un resultado del Proyecto EVEREST (PID2023-151939OB-I00), financiado por MICIU/AEI 10.13039/501100011033 y cofinanciado por FEDER – Unión Europea, y del Proyecto NevadEO (C-EXP-074-UGR23), cofinanciado por el Programa FEDER 2014-2020 y la Consejería de Economía, Conocimiento, Empresa y Universidades de la Junta de Andalucía. Es también un resultado del Proyecto PRESINMED (Preserving the singularity of Mediterranean high-mountain biodiversity hotspots: a NBS approach, PCI 2025-163175) de la convocatoria Biodiversa+ NBS 2023.
MonitorEO is an output of the EVEREST Project (PID2023-151939OB-I00), funded by MICIU/AEI 10.13039/501100011033, and co-funded by ERDF – European Union, as well as of the NevadEO Project (C-EXP-074-UGR23), co-funded by the ERDF 2014-2020 Program and the Regional Ministry of Economy, Knowledge, Enterprise, and Universities of the Regional Government of Andalusia. It is also an output of the PRESINMED Project (Preserving the singularity of Mediterranean high-mountain biodiversity hotspots: a NBS approach, PCI 2025-163175) of the Biodiversa+ NBS 2023 call.
OBSNEV, Universidad de Granada · GPL-3.0-or-later



Empezar
Herramientas
Ayuda
Start
Tools
- Earth Engine app
- QGIS plugin
- MCP: Claude and other assistants
- Python package
- R package
- Results viewer
Help