Recovered from backup
This commit is contained in:
1
backend/.env
Normal file
1
backend/.env
Normal file
@@ -0,0 +1 @@
|
||||
DB_URL = "mysql+aiomysql://root:root@localhost:3306/DAD"
|
||||
1
backend/config.py
Normal file
1
backend/config.py
Normal file
@@ -0,0 +1 @@
|
||||
API_PREFIX = "/api/v1"
|
||||
7
backend/db.py
Normal file
7
backend/db.py
Normal 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)
|
||||
BIN
backend/endpoints/__pycache__/sensors.cpython-312.pyc
Normal file
BIN
backend/endpoints/__pycache__/sensors.cpython-312.pyc
Normal file
Binary file not shown.
67
backend/endpoints/sensors.py
Normal file
67
backend/endpoints/sensors.py
Normal 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
36
backend/main.py
Normal 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"])
|
||||
12
backend/models/schemas/SensorModel.py
Normal file
12
backend/models/schemas/SensorModel.py
Normal 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
|
||||
BIN
backend/models/schemas/__pycache__/SensorModel.cpython-312.pyc
Normal file
BIN
backend/models/schemas/__pycache__/SensorModel.cpython-312.pyc
Normal file
Binary file not shown.
14
backend/models/sql/Sensor.py
Normal file
14
backend/models/sql/Sensor.py
Normal 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
|
||||
)
|
||||
BIN
backend/models/sql/__pycache__/Sensor.cpython-312.pyc
Normal file
BIN
backend/models/sql/__pycache__/Sensor.cpython-312.pyc
Normal file
Binary file not shown.
7
backend/requirements.txt
Normal file
7
backend/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
uvicorn
|
||||
fastapi
|
||||
contextlib2
|
||||
dotenv
|
||||
pydantic
|
||||
sqlalchemy
|
||||
db
|
||||
14
backend/run.py
Normal file
14
backend/run.py
Normal 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()
|
||||
Reference in New Issue
Block a user