1
0

Recovered from backup

This commit is contained in:
Jose
2025-02-26 19:42:35 +01:00
commit cf9d5e71fe
43 changed files with 5778 additions and 0 deletions

1
backend/.env Normal file
View File

@@ -0,0 +1 @@
DB_URL = "mysql+aiomysql://root:root@localhost:3306/DAD"

1
backend/config.py Normal file
View File

@@ -0,0 +1 @@
API_PREFIX = "/api/v1"

7
backend/db.py Normal file
View File

@@ -0,0 +1,7 @@
from databases import Database
import os
from dotenv import load_dotenv
load_dotenv()
DB_URL = os.getenv("DB_URL")
database = Database(DB_URL)

Binary file not shown.

View File

@@ -0,0 +1,67 @@
from fastapi import APIRouter, Body, HTTPException, Query
from fastapi import APIRouter, Body, HTTPException, Query
from typing import Optional
from pydantic import BaseModel
from sqlalchemy import select, insert
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from models.sql.Sensor import sensor_mq_data
from db import database
from models.schemas.SensorModel import SensorModel
router = APIRouter()
@router.get("")
async def get_all(
_sort: Optional[str] = Query(None, alias="_sort", description="Campo por el cual ordenar los resultados"),
_order: Optional[str] = Query("asc", description="Orden de los resultados, 'asc' o 'desc'"),
_limit: Optional[int] = Query(100, ge=1, description="Número máximo de resultados a mostrar"),
):
query = select(sensor_mq_data)
if _sort:
if _order == "desc":
query = query.order_by(getattr(sensor_mq_data.c, _sort).desc())
else:
query = query.order_by(getattr(sensor_mq_data.c, _sort))
if _limit:
query = query.limit(_limit)
async with database.transaction():
result = await database.fetch_all(query)
return result
@router.get("/sensor")
async def get_by_params(
id: Optional[int] = Query(None, alias="id", description="ID del sensor a buscar"),
sensor_type: Optional[str] = Query(None, alias="sensor_type", description="Tipo de sensor"),
min_value: Optional[float] = Query(None, alias="min_value", description="Valor mínimo del sensor"),
max_value: Optional[float] = Query(None, alias="max_value", description="Valor máximo del sensor"),
min_temp: Optional[float] = Query(None, alias="min_temp", description="Temperatura mínima"),
max_temp: Optional[float] = Query(None, alias="max_temp", description="Temperatura máxima"),
min_humidity: Optional[float] = Query(None, alias="min_humidity", description="Humedad mínima"),
max_humidity: Optional[float] = Query(None, alias="max_humidity", description="Humedad máxima"),
):
query = select(sensor_mq_data)
if id is not None:
query = query.where(sensor_mq_data.c.id == id)
if sensor_type is not None:
query = query.where(sensor_mq_data.c.sensor_type == sensor_type)
if min_value is not None:
query = query.where(sensor_mq_data.c.value >= min_value)
if max_value is not None:
query = query.where(sensor_mq_data.c.value <= max_value)
if min_temp is not None:
query = query.where(sensor_mq_data.c.temperature >= min_temp)
if max_temp is not None:
query = query.where(sensor_mq_data.c.temperature <= max_temp)
if min_humidity is not None:
query = query.where(sensor_mq_data.c.humidity >= min_humidity)
if max_humidity is not None:
query = query.where(sensor_mq_data.c.humidity <= max_humidity)
async with database.transaction():
result = await database.fetch_all(query)
return result

36
backend/main.py Normal file
View File

@@ -0,0 +1,36 @@
from fastapi import FastAPI
from contextlib import asynccontextmanager
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from config import API_PREFIX
from fastapi.openapi.utils import get_openapi
from endpoints import sensors
from db import database
@asynccontextmanager
async def lifespan(app: FastAPI):
await database.connect() # Conecta la base de datos al iniciar
yield
await database.disconnect() # Desconecta al finalizar
app = FastAPI(
title="Mi API de Calidad del Aire",
description="API para obtener mediciones de calidad del aire en Sevilla",
version="1.0.0",
docs_url=f"{API_PREFIX}/swagger", # Cambia la URL de Swagger UI
lifespan=lifespan,
openapi_url="/dad/openapi.json"
)
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
@app.get(f"{API_PREFIX}/")
async def root():
return {"message": "Has llegado a la raíz de la API"}
@app.get(f"{API_PREFIX}/openapi.json", include_in_schema=False)
async def get_openapi_json():
return JSONResponse(content=get_openapi(title="Mi API de Calidad del Aire", version="1.0.0", routes=app.routes))
app.include_router(sensors.router, prefix=f"{API_PREFIX}/sensors", tags=["sensors"])

View File

@@ -0,0 +1,12 @@
from pydantic import BaseModel
from datetime import datetime
from typing import Optional
class SensorModel(BaseModel):
id: Optional[int] # pq el modelo se usará también para INSERT
sensor_type: str
lat: float
lon: float
value: float
timestamp: Optional[datetime] = None

View File

@@ -0,0 +1,14 @@
from sqlalchemy import Column, Integer, String, Float, TIMESTAMP, Table, MetaData, func
metadata = MetaData()
sensor_mq_data = Table(
"sensor_mq_data",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("sensor_type", String(50), nullable=False), # Tipo de sensor (MQ-135, etc.)
Column("lat", Float, nullable=False), # Latitud
Column("lon", Float, nullable=False), # Longitud
Column("value", Float, nullable=False), # Valor leído del sensor
Column("timestamp", TIMESTAMP, server_default=func.current_timestamp()) # Fecha automática
)

Binary file not shown.

7
backend/requirements.txt Normal file
View File

@@ -0,0 +1,7 @@
uvicorn
fastapi
contextlib2
dotenv
pydantic
sqlalchemy
db

14
backend/run.py Normal file
View File

@@ -0,0 +1,14 @@
import subprocess
def run_api():
try:
subprocess.run(
['uvicorn', 'main:app', '--reload', '--port', '9091'],
check=True,
cwd='./'
)
except subprocess.CalledProcessError as e:
print(f"Error al iniciar API DAD: {e.stderr}")
if __name__ == "__main__":
run_api()