Files
sensor-web-v2/server-python/app.py
Marco Crapts cd3afa4d61
Some checks failed
continuous-integration/drone/push Build is failing
add Python server backend
2024-05-11 14:06:39 +02:00

141 lines
3.7 KiB
Python

import json
import os
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from typing import Literal
import motor.motor_asyncio
from bson import json_util
from bson.objectid import ObjectId
from dotenv import find_dotenv, load_dotenv
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from prettytable import PrettyTable
from pydantic import BaseModel
env_file = find_dotenv(".env")
load_dotenv("../.env")
IS_PROD = os.getenv("PRODUCTION", "") == "true"
class Config:
MONGO_SERVER: str = os.environ.get("MONGO_SERVER", "")
MONGO_DB: str = os.environ.get("MONGO_DB", "")
class Document(BaseModel):
date: int
value: float
@asynccontextmanager
async def lifespan(app: FastAPI):
table = PrettyTable()
table.field_names = ["VARIABLE", "VALUE"]
table.add_rows(
[
[env_variable, os.environ.get(env_variable)]
for env_variable in ["MONGO_SERVER", "MONGO_DB"]
]
)
print(table)
yield
app = FastAPI(openapi_url=("/openapi.json" if not IS_PROD else ""), lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
client = motor.motor_asyncio.AsyncIOMotorClient(Config.MONGO_SERVER, 27017)
db = client[Config.MONGO_DB]
def object_id_from_date(date: int) -> ObjectId:
timestamp = datetime.fromtimestamp(date, tz=timezone.utc)
object_id = ObjectId.from_datetime(timestamp)
return object_id
@app.get(
"/type/{type}/startDate/{start_date}/endDate/{end_date}/sample/{sample}",
tags=["Retrieve sensor data"],
)
async def get_sensor_data(
type: Literal["temperature", "humidity"],
start_date: int,
end_date: int,
sample: int,
) -> list[Document]:
collection = db["dht22"]
pipeline = [
{
"$match": {
"$and": [
{
"_id": {
"$gt": object_id_from_date(start_date),
"$lt": object_id_from_date(end_date),
}
},
{"type": type},
{"value": {"$ne": "NaN"}},
]
}
},
{
"$group": {
"_id": {
"$toDate": {
"$subtract": [
{"$toLong": {"$toDate": "$_id"}},
{
"$mod": [
{"$toLong": {"$toDate": "$_id"}},
1000 * 60 * sample,
]
},
]
}
},
"value": {"$avg": "$value"},
"date": {"$min": {"$toDate": "$_id"}},
}
},
{
"$project": {
"_id": 0,
"value": {"$round": ["$value", 1]},
"date": {"$toLong": "$date"},
}
},
{"$sort": {"date": 1}},
]
docs = [doc async for doc in collection.aggregate(pipeline)]
return json.loads(json_util.dumps(docs))
index = FileResponse(path="../dist/index.html", headers={"Cache-Control": "no-cache"})
@app.middleware("http")
async def add_default_404(request: Request, call_next):
response = await call_next(request)
if response.status_code == 404:
return index
else:
return response
app.mount("/", StaticFiles(directory="../dist", html=True), name="dist")