Background services running properly; New Bedscale Entity implemented
This commit is contained in:
parent
9aba0279d7
commit
5defaba45f
5 changed files with 106 additions and 51 deletions
|
@ -0,0 +1 @@
|
|||
from .bedscale_entity import BedscaleEntity
|
|
@ -17,20 +17,30 @@ class BedscaleWeightResult:
|
|||
|
||||
|
||||
class BedscaleEntity(Entity):
|
||||
def __init__(self, *, ip_address: str, id, name, room):
|
||||
|
||||
def __init__(self, *, ip_address: str, id: str, name: str, room: str):
|
||||
super().__init__(id=id, name=name, room=room, device_type="bedscale")
|
||||
self._ip_address = ip_address
|
||||
|
||||
async def poll_weights(self) -> BedscaleWeightResult:
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
tr_request = loop.run_in_executor(None, self.__poll_scale__, "tr")
|
||||
tl_request = loop.run_in_executor(None, self.__poll_scale__, "tl")
|
||||
br_request = loop.run_in_executor(None, self.__poll_scale__, "br")
|
||||
bl_request = loop.run_in_executor(None, self.__poll_scale__, "bl")
|
||||
|
||||
results = BedscaleWeightResult(
|
||||
tr=await asyncio.run_in_executor(None, self.__poll_scale__, "tr"),
|
||||
tl=await asyncio.run_in_executor(None, self.__poll_scale__, "tl"),
|
||||
br=await asyncio.run_in_executor(None, self.__poll_scale__, "br"),
|
||||
bl=await asyncio.run_in_executor(None, self.__poll_scale__, "bl"),
|
||||
tr=await tr_request,
|
||||
tl=await tl_request,
|
||||
br=await br_request,
|
||||
bl=await bl_request,
|
||||
)
|
||||
|
||||
# TODO: Sanity checks
|
||||
|
||||
# TODO: Keep track of empty-bed weight
|
||||
|
||||
return results
|
||||
|
||||
def __poll_scale__(self, leg: str) -> float | None:
|
||||
|
|
|
@ -5,7 +5,7 @@ import os
|
|||
from statistics import median
|
||||
from typing import Optional
|
||||
import requests as r
|
||||
from ..hue import hue
|
||||
from ...endpoints.hue import hue
|
||||
import logging
|
||||
|
||||
file_path: str = "bettwaage.csv"
|
|
@ -4,53 +4,79 @@ from fastapi import APIRouter
|
|||
|
||||
import os
|
||||
import csv
|
||||
from .handlers.bett import file_path, local_history, log_bed_weights
|
||||
|
||||
from bridges.bedscale import BedscaleEntity
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/file", tags=["file"])
|
||||
async def get_file():
|
||||
with open(file_path, "r", encoding="UTF-8") as fp:
|
||||
return HTMLResponse("\n".join(fp.readlines()))
|
||||
|
||||
|
||||
@router.get("/history")
|
||||
async def get_history(count: int = None) -> list[dict]:
|
||||
|
||||
points = []
|
||||
with open(file_path, "r", encoding="UTF-8") as fp:
|
||||
reader = csv.DictReader(fp, delimiter=";")
|
||||
for row in reader:
|
||||
if not row:
|
||||
continue
|
||||
|
||||
points.append(
|
||||
{
|
||||
"timestamp": row["timestamp"],
|
||||
"total": float(row["total"]),
|
||||
"tl": float(row["tl"]),
|
||||
"tr": float(row["tr"]),
|
||||
"bl": float(row["bl"]),
|
||||
"br": float(row["br"]),
|
||||
}
|
||||
bedscale = BedscaleEntity(
|
||||
ip_address="http://192.168.178.110:80",
|
||||
id="bedscale",
|
||||
name="Bettwaage",
|
||||
room="Max Zimmer",
|
||||
)
|
||||
|
||||
if count:
|
||||
return points[-count]
|
||||
else:
|
||||
return points
|
||||
history = []
|
||||
|
||||
measure_delay_secs = 1
|
||||
history_length_secs = 60 * 10
|
||||
|
||||
|
||||
async def bedscale_service():
|
||||
global history
|
||||
global bedscale
|
||||
history_max_num = int(history_length_secs / measure_delay_secs)
|
||||
while True:
|
||||
r = await bedscale.poll_weights()
|
||||
history.append(r)
|
||||
|
||||
if len(history) > history_max_num:
|
||||
history = history[-history_max_num:]
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
@router.get("/latest")
|
||||
async def get_latest():
|
||||
if len(local_history) == 0:
|
||||
if len(history) == 0:
|
||||
return HTMLResponse(status_code=200, content="No data given yet")
|
||||
return JSONResponse(local_history[-1])
|
||||
return history[-1]
|
||||
|
||||
|
||||
@router.delete("/delete", tags=["file"])
|
||||
async def delete_file():
|
||||
os.remove(file_path)
|
||||
return "Deleted file"
|
||||
# @router.get("/file", tags=["file"])
|
||||
# async def get_file():
|
||||
# with open(file_path, "r", encoding="UTF-8") as fp:
|
||||
# return HTMLResponse("\n".join(fp.readlines()))
|
||||
|
||||
|
||||
# @router.get("/history")
|
||||
# async def get_history(count: int = None) -> list[dict]:
|
||||
|
||||
# points = []
|
||||
# with open(file_path, "r", encoding="UTF-8") as fp:
|
||||
# reader = csv.DictReader(fp, delimiter=";")
|
||||
# for row in reader:
|
||||
# if not row:
|
||||
# continue
|
||||
|
||||
# points.append(
|
||||
# {
|
||||
# "timestamp": row["timestamp"],
|
||||
# "total": float(row["total"]),
|
||||
# "tl": float(row["tl"]),
|
||||
# "tr": float(row["tr"]),
|
||||
# "bl": float(row["bl"]),
|
||||
# "br": float(row["br"]),
|
||||
# }
|
||||
# )
|
||||
|
||||
# if count:
|
||||
# return points[-count]
|
||||
# else:
|
||||
# return points
|
||||
|
||||
|
||||
# @router.delete("/delete", tags=["file"])
|
||||
# async def delete_file():
|
||||
# os.remove(file_path)
|
||||
# return "Deleted file"
|
||||
|
|
36
src/main.py
36
src/main.py
|
@ -1,24 +1,42 @@
|
|||
import asyncio
|
||||
from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI
|
||||
import uvicorn
|
||||
from endpoints.handlers.bett import log_bed_weights
|
||||
from endpoints.hue import router as hue_router
|
||||
from endpoints.bettwaage import router as bettwaage_router
|
||||
from endpoints.bettwaage import bedscale_service, router as bettwaage_router
|
||||
from endpoints.handlers.fritz import track_network_devices
|
||||
|
||||
app = FastAPI()
|
||||
# Background task references
|
||||
background_tasks = []
|
||||
|
||||
### Background services
|
||||
loop = asyncio.new_event_loop()
|
||||
loop.create_task(track_network_devices(), name="Fritz!Box Connection Tracker")
|
||||
loop.create_task(log_bed_weights(), name="Polling bed-scale")
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""Start background services."""
|
||||
fritz_task = asyncio.create_task(track_network_devices(), name="Fritz!Box Tracker")
|
||||
bedscale_task = asyncio.create_task(bedscale_service(), name="Polling bed-scale")
|
||||
|
||||
# Store references to the tasks
|
||||
background_tasks.extend([fritz_task, bedscale_task])
|
||||
|
||||
yield
|
||||
|
||||
"""Stop background services."""
|
||||
for task in background_tasks:
|
||||
task.cancel()
|
||||
try:
|
||||
await task
|
||||
except asyncio.CancelledError:
|
||||
pass # Expected when cancelling tasks
|
||||
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
# API Routes
|
||||
app.include_router(hue_router, prefix="/hue", tags=["hue"])
|
||||
app.include_router(bettwaage_router, prefix="/bettwaage", tags=["bett"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run API server
|
||||
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
||||
|
||||
# TODO: Close background services properly
|
||||
|
|
Loading…
Reference in a new issue