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):
|
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")
|
super().__init__(id=id, name=name, room=room, device_type="bedscale")
|
||||||
self._ip_address = ip_address
|
self._ip_address = ip_address
|
||||||
|
|
||||||
async def poll_weights(self) -> BedscaleWeightResult:
|
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(
|
results = BedscaleWeightResult(
|
||||||
tr=await asyncio.run_in_executor(None, self.__poll_scale__, "tr"),
|
tr=await tr_request,
|
||||||
tl=await asyncio.run_in_executor(None, self.__poll_scale__, "tl"),
|
tl=await tl_request,
|
||||||
br=await asyncio.run_in_executor(None, self.__poll_scale__, "br"),
|
br=await br_request,
|
||||||
bl=await asyncio.run_in_executor(None, self.__poll_scale__, "bl"),
|
bl=await bl_request,
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: Sanity checks
|
# TODO: Sanity checks
|
||||||
|
|
||||||
|
# TODO: Keep track of empty-bed weight
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def __poll_scale__(self, leg: str) -> float | None:
|
def __poll_scale__(self, leg: str) -> float | None:
|
||||||
|
|
|
@ -5,7 +5,7 @@ import os
|
||||||
from statistics import median
|
from statistics import median
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import requests as r
|
import requests as r
|
||||||
from ..hue import hue
|
from ...endpoints.hue import hue
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
file_path: str = "bettwaage.csv"
|
file_path: str = "bettwaage.csv"
|
|
@ -4,53 +4,79 @@ from fastapi import APIRouter
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
from .handlers.bett import file_path, local_history, log_bed_weights
|
|
||||||
|
from bridges.bedscale import BedscaleEntity
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
bedscale = BedscaleEntity(
|
||||||
|
ip_address="http://192.168.178.110:80",
|
||||||
@router.get("/file", tags=["file"])
|
id="bedscale",
|
||||||
async def get_file():
|
name="Bettwaage",
|
||||||
with open(file_path, "r", encoding="UTF-8") as fp:
|
room="Max Zimmer",
|
||||||
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:
|
history = []
|
||||||
return points[-count]
|
|
||||||
else:
|
measure_delay_secs = 1
|
||||||
return points
|
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")
|
@router.get("/latest")
|
||||||
async def 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 HTMLResponse(status_code=200, content="No data given yet")
|
||||||
return JSONResponse(local_history[-1])
|
return history[-1]
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/delete", tags=["file"])
|
# @router.get("/file", tags=["file"])
|
||||||
async def delete_file():
|
# async def get_file():
|
||||||
os.remove(file_path)
|
# with open(file_path, "r", encoding="UTF-8") as fp:
|
||||||
return "Deleted file"
|
# 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
|
import asyncio
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from endpoints.handlers.bett import log_bed_weights
|
|
||||||
from endpoints.hue import router as hue_router
|
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
|
from endpoints.handlers.fritz import track_network_devices
|
||||||
|
|
||||||
app = FastAPI()
|
# Background task references
|
||||||
|
background_tasks = []
|
||||||
|
|
||||||
### Background services
|
|
||||||
loop = asyncio.new_event_loop()
|
@asynccontextmanager
|
||||||
loop.create_task(track_network_devices(), name="Fritz!Box Connection Tracker")
|
async def lifespan(app: FastAPI):
|
||||||
loop.create_task(log_bed_weights(), name="Polling bed-scale")
|
"""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
|
# API Routes
|
||||||
app.include_router(hue_router, prefix="/hue", tags=["hue"])
|
app.include_router(hue_router, prefix="/hue", tags=["hue"])
|
||||||
app.include_router(bettwaage_router, prefix="/bettwaage", tags=["bett"])
|
app.include_router(bettwaage_router, prefix="/bettwaage", tags=["bett"])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Run API server
|
# Run API server
|
||||||
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
||||||
|
|
||||||
# TODO: Close background services properly
|
|
||||||
|
|
Loading…
Reference in a new issue