Plataforma web de monitoreo agrícola de precisión para la detección temprana del estrés hídrico en plantas de arándano (Vaccinium corymbosum) mediante el índice CWSI y termografía infrarroja.
Arquitectura · Características · Inicio Rápido · Despliegue · Estructura
AIRT (Arándano IRT) es el componente de software principal de un proyecto de grado de ingeniería cuyo objetivo es desarrollar un sistema de monitoreo agrícola de bajo costo que permita a los productores detectar de forma temprana y objetiva el estrés hídrico en cultivos de arándano, reemplazando los métodos visuales subjetivos por un análisis basado en datos de termografía infrarroja.
El sistema calcula el Índice de Estrés Hídrico del Cultivo (CWSI) a partir de lecturas de temperatura de canopia y datos ambientales capturados por dispositivos IoT de bajo costo basados en ESP32. La plataforma web centraliza la gestión de cultivos, dispositivos, plantas y el análisis automatizado de estrés, todo dentro de una interfaz de administración segura y multi-tenant.
Este repositorio contiene el código fuente de la aplicación web monolítica del sistema AIRT. El proyecto completo está compuesto por tres repositorios:
| Repositorio | Descripción |
|---|---|
ArandanoIRTSoftware (este) |
Aplicación web ASP.NET Core (monolito) |
ArandanoIRTOps |
Infraestructura de despliegue (Docker Compose, Nginx, configuraciones de VPS) |
| Firmware ESP32 | Firmware de los dispositivos de captura térmica e IoT |
- Cálculo automatizado del CWSI: Servicio en segundo plano que evalúa el estrés hídrico para cada planta monitorizada dentro de una ventana horaria configurable por cultivo.
- Clasificación de estado de planta: Clasificación automática del estado de las plantas (
Óptimo,Estrés Incipiente,Estrés Crítico) basada en umbrales CWSI parametrizables. - Detección de anomalías: Algoritmo de detección de anomalías en lecturas de temperatura (ΔT) con umbral y duración configurables.
- Predicción con modelo ONNX: Predictor de condición de planta basado en un modelo de árbol de decisión exportado al formato ONNX, ejecutado en tiempo real sobre el servidor mediante
Microsoft.ML.OnnxRuntime. - Captura térmica: Gestión y almacenamiento de imágenes térmicas por planta, con soporte para máscaras de región de interés (ROI).
- Panel de control (Dashboard): Resumen en tiempo real del estado de todos los cultivos y plantas activas.
- Gestión multi-entidad: Administración completa de Cultivos, Plantas, Dispositivos IoT, Usuarios y Observaciones de campo.
- Sistema de invitaciones: Control de acceso mediante códigos de invitación para incorporar nuevos usuarios sin registro público.
- Historiales y auditoría: Registro histórico de cambios de estado de plantas y actividad de usuario.
- Asistente agrícola con RAG: Módulo de inteligencia artificial conversacional basado en Retrieval-Augmented Generation (RAG), integrado como microservicio externo (FastAPI + Python). Permite a los usuarios consultar información técnica sobre arándano, estrés hídrico y prácticas agronómicas, con respuestas citadas.
- Sincronización de base de conocimiento: Servicio en segundo plano que ingiere automáticamente los registros de análisis en la base de conocimiento del asistente.
- API para dispositivos IoT: Endpoint seguro para la recepción de datos de sensores en tiempo real desde dispositivos ESP32 autenticados por token.
- Alertas por correo electrónico: Sistema de alertas automatizadas vía Brevo (SendinBlue) para notificaciones de estrés crítico, inactividad de dispositivos y recordatorios de calibración.
- Generación de reportes PDF: Generación de informes analíticos en formato PDF usando QuestPDF y Razor como motor de plantillas.
- Almacenamiento de objetos: Gestión de archivos estáticos (imágenes térmicas, etc.) mediante MinIO (compatible con S3).
- Datos meteorológicos: Integración con una API climática externa para enriquecer el análisis con datos ambientales del entorno del cultivo.
- Protección anti-bot: Integración con Cloudflare Turnstile en el formulario de inicio de sesión.
El proyecto sigue los principios de Arquitectura por Capas (Layered Architecture), con una separación explícita de responsabilidades que facilita la mantenibilidad y las pruebas.
┌────────────────────────────────────────────────────────────────┐
│ 3_Presentation Layer │
│ Controllers · ViewModels · ViewComponents │
│ (ASP.NET Core MVC) │
├────────────────────────────────────────────────────────────────┤
│ 1_Application Layer │
│ Services (Contracts + Implementation) │
│ DTOs · Helpers │
├────────────────────────────────────────────────────────────────┤
│ 2_Infrastructure Layer │
│ EF Core (PostgreSQL) · MinIO · Brevo · RAG Client │
│ Background Services · Auth Handlers · Middleware │
├────────────────────────────────────────────────────────────────┤
│ 0_Domain Layer │
│ Entities · Enums · Common Abstractions │
└────────────────────────────────────────────────────────────────┘
| Categoría | Tecnología |
|---|---|
| Framework | ASP.NET Core 8.0 (MVC + Razor Views) |
| ORM | Entity Framework Core 8 + Npgsql |
| Base de datos | PostgreSQL 15 |
| Almacenamiento | MinIO (S3-compatible) |
| Autenticación | ASP.NET Core Identity + Cookie Auth + Esquema de dispositivos personalizado |
| Inferencia ML | Microsoft.ML.OnnxRuntime (modelo ONNX) |
| Logging | Serilog (JSON structured logging) |
Brevo SDK (brevo_csharp) |
|
| QuestPDF + SkiaSharp | |
| HTTP Policies | Polly (Circuit Breaker) |
| Contenerización | Docker (multi-stage build) |
| CI/CD | GitHub Actions (Build · Lint · CodeQL · Deploy) |
| Registro de imágenes | GitHub Container Registry (GHCR) |
ArandanoIRTSoftware/
│
├── 0_Domain/ # Capa de Dominio: Núcleo de negocio puro
│ ├── Entities/ # Entidades de base de datos (Plant, Crop, Device, etc.)
│ ├── Enums/ # Enumeraciones del dominio (PlantStatus, DeviceStatus...)
│ └── Common/ # Abstracciones compartidas (Result pattern, etc.)
│
├── 1_Application/ # Capa de Aplicación: Casos de uso y contratos
│ ├── Services/
│ │ ├── Contracts/ # Interfaces de servicios (IPlantService, ICropService...)
│ │ └── Implementation/ # Implementaciones de la lógica de negocio
│ ├── DTOs/ # Objetos de transferencia de datos
│ └── Helper/ # Utilidades de la capa de aplicación
│
├── 2_Infrastructure/ # Capa de Infraestructura: Implementaciones técnicas
│ ├── Data/ # DbContext (EF Core) y configuraciones de entidades
│ ├── Services/ # Servicios externos (MinIO, Brevo, RAG, ONNX...)
│ ├── Authentication/ # Handlers de autenticación de dispositivos IoT
│ ├── Middleware/ # Middleware personalizado (auditoría de usuario)
│ ├── Settings/ # POCOs para configuración (IOptions<T>)
│ └── DependencyInjection.cs # Registro centralizado de todos los servicios
│
├── 3_Presentation/ # Capa de Presentación: Controladores y ViewModels
│ ├── Controllers/
│ │ ├── Admin/ # Controladores del panel de administración (MVC)
│ │ └── Api/ # Controladores de la API REST para dispositivos IoT
│ ├── ViewModels/ # ViewModels tipados para cada vista
│ ├── ViewComponents/ # Componentes de vista reutilizables
│ └── Attributes/ # Atributos de validación personalizados
│
├── Views/ # Vistas Razor (.cshtml) — organizadas por controlador
├── Assets/ # Activos del servidor (modelo ONNX)
├── Migrations/ # Migraciones de EF Core
├── ArandanoIRT.Tests/ # Proyecto de pruebas unitarias (xUnit)
│
├── .github/workflows/
│ ├── ci.yml # Pipeline CI: Build + Lint + CodeQL
│ └── deploy.yml # Pipeline CD: Docker Build + Push + Deploy VPS
│
├── Dockerfile # Build multi-etapa optimizado para producción
├── Program.cs # Punto de entrada y bootstrap de la aplicación
└── ArandanoIRT.Web.csproj # Definición del proyecto y dependencias NuGet
El entorno de desarrollo utiliza un enfoque híbrido: la aplicación .NET se ejecuta de forma nativa para un ciclo de depuración rápido, mientras que las dependencias de infraestructura (PostgreSQL, MinIO) corren en contenedores Docker.
- Git
- .NET 8 SDK
- Docker Desktop (o Docker Engine + Compose)
- Un IDE: Visual Studio 2022+, JetBrains Rider, o VS Code
Ambos repositorios deben estar en la misma carpeta raíz:
mkdir ArandanoProject && cd ArandanoProject
git clone https://github.com/RFGRONA/ArandanoIRTSoftware.git
git clone https://github.com/RFGRONA/ArandanoIRTOps.gitLa estructura resultante debe ser:
ArandanoProject/
├── ArandanoIRTSoftware/ ← Estás en el README de este repositorio
└── ArandanoIRTOps/
Navega al repositorio de operaciones y crea el archivo de override para desarrollo local. Este archivo no debe ser subido a Git (ya está en .gitignore).
cd ArandanoIRTOpsCrea el archivo docker-compose.override.yml con el siguiente contenido:
# docker-compose.override.yml
# Configuración exclusiva para desarrollo local. NO subir a Git.
version: '3.8'
services:
postgres:
ports:
- "5433:5432" # Expone PostgreSQL al host en el puerto 5433
volumes:
- postgres-data:/var/lib/postgresql/data
minio:
ports:
- "9000:9000" # API S3 de MinIO
- "9001:9001" # Consola web de MinIO
volumes:
- minio-data:/data
volumes:
postgres-data:
minio-data:Levanta los servicios:
docker-compose up -dTip
Puedes verificar el estado de los contenedores con docker-compose ps. La consola web de MinIO estará disponible en http://localhost:9001 (usuario: minioadmin, contraseña: minioadmin).
Regresa al directorio de la aplicación:
cd ../ArandanoIRTSoftwareCrea el archivo appsettings.Development.json en la raíz del proyecto. Este archivo no debe ser subido a Git (ya está en .gitignore), ya que contiene secretos locales.
{
"ConnectionStrings": {
"PostgresConnection": "Host=localhost;Port=5433;Database=arandano_db;Username=user;Password=pass"
},
"Minio": {
"Endpoint": "localhost:9000",
"AccessKey": "minioadmin",
"SecretKey": "minioadmin",
"BucketName": "arandano-dev",
"UseSSL": false
},
"Rag": {
"BaseUrl": "",
"ApiKey": ""
}
}dotnet ef database updateAbre la solución en tu IDE y ejecuta el proyecto (F5), o desde la terminal:
dotnet runLa aplicación estará disponible en https://localhost:7XXX (el puerto se muestra en la consola).
Note
En el primer arranque, si no existe un usuario administrador, el sistema ejecuta un flujo de bootstrap accesible en la ruta /Bootstrap para crear las credenciales iniciales.
El despliegue en producción es completamente automatizado mediante GitHub Actions. Al hacer push a la rama main:
ci.yml(en ramas de feature): Compila el proyecto, verifica el formato del código condotnet formaty realiza análisis estático de seguridad con GitHub CodeQL.deploy.yml(enmain): Construye la imagen Docker con un multi-stage build optimizado, la publica en el GitHub Container Registry (GHCR) y despliega en el servidor VPS de producción vía SSH.
Para que el pipeline funcione, deben configurarse los siguientes secretos en el repositorio (Settings > Secrets and variables > Actions):
| Secreto | Descripción |
|---|---|
GHCR_TOKEN |
Personal Access Token con permisos write:packages para publicar en GHCR |
SSH_HOST |
Dirección IP o hostname del servidor VPS de producción |
SSH_USERNAME |
Usuario SSH del servidor |
SSH_PRIVATE_KEY |
Clave privada SSH (formato PEM) para autenticación sin contraseña |
SSH_FINGERPRINT |
Fingerprint del host SSH para verificación de identidad |
La imagen se construye mediante un Dockerfile multi-etapa que separa las fases de compilación y ejecución, produciendo una imagen final ligera basada únicamente en el runtime de ASP.NET:
# Etapa 1: Build (SDK completo)
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
# Etapa 2: Final (solo runtime)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS finalPara construir y ejecutar la imagen manualmente:
# Construir la imagen
docker build -t arandano-irt-app .
# Ejecutar el contenedor
docker run -d -p 8080:8080 \
-e ConnectionStrings__PostgresConnection="..." \
arandano-irt-appEl proyecto incluye un proyecto de pruebas unitarias (ArandanoIRT.Tests) basado en xUnit.
# Ejecutar todas las pruebas
dotnet test ArandanoIRT.Tests/ArandanoIRT.Tests.csproj --verbosity normalLa aplicación se configura mediante el sistema estándar de appsettings.json de ASP.NET Core con soporte para múltiples entornos.
| Sección | Descripción |
|---|---|
ConnectionStrings:PostgresConnection |
Cadena de conexión a la base de datos PostgreSQL |
Minio |
Configuración del servicio de almacenamiento de objetos (endpoint, credenciales, bucket) |
Brevo |
Credenciales de la API de Brevo para el envío de correos electrónicos |
Rag |
URL base y API key del microservicio de IA (RAG) |
BackgroundJobs |
Intervalos de los servicios en segundo plano (análisis, inactividad) |
AnalysisParameters |
Parámetros globales por defecto para el cálculo del CWSI |
AnomalyParameters |
Parámetros globales por defecto para la detección de anomalías (ΔT) |
Turnstile |
Claves de Cloudflare Turnstile para protección anti-bot en el login |
AdminCredentials |
Credenciales del administrador raíz del sistema |
Este repositorio corresponde a un proyecto académico de grado. Las contribuciones externas no están abiertas en este momento, pero el código se publica con fines educativos bajo la licencia GPLv3.
| Rama | Propósito |
|---|---|
main |
Rama de producción. Los pushes aquí disparan el despliegue automático. |
feature/* |
Ramas de desarrollo de nuevas funcionalidades. Los pushes disparan el pipeline de CI. |
Este proyecto está distribuido bajo la licencia GNU General Public License v3.0. Consulta el archivo LICENSE para más detalles.