This commit is contained in:
140
server-python/app.py
Normal file
140
server-python/app.py
Normal file
@@ -0,0 +1,140 @@
|
||||
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")
|
||||
Reference in New Issue
Block a user