Files
Marco Crapts 40da285b9f
All checks were successful
continuous-integration/drone/push Build is passing
update node and python
2025-11-13 14:52:34 +00:00

135 lines
3.6 KiB
Python

import json
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 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, Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file="../.env")
is_prod: bool = Field(default=False)
mongo_server: str = Field(default="")
mongo_db: str = Field(default="")
class Document(BaseModel):
date: int
value: float
@asynccontextmanager
async def lifespan(app: FastAPI):
table = PrettyTable()
table.field_names = ["VARIABLE", "VALUE"]
rows = [list(item) for item in Settings().__dict__.items()]
table.add_rows(rows)
print(table)
yield
app = FastAPI(
openapi_url=("/openapi.json" if not Settings().is_prod else ""), lifespan=lifespan
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
client = motor.motor_asyncio.AsyncIOMotorClient(Settings().mongo_server, 27017)
db = client[Settings().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": float("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")