141 lines
3.7 KiB
Python
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")
|