Created all the basic routes. Still requires some testing and cleaning
This commit is contained in:
parent
33715cb34e
commit
2ae520f6b3
3 changed files with 293 additions and 53 deletions
245
app.py
245
app.py
|
@ -7,12 +7,15 @@ from sqlmodel import SQLModel, Session, create_engine, delete, select
|
|||
import netbrite as nb
|
||||
from db import (
|
||||
MessageDB,
|
||||
MessagePublic,
|
||||
NetBriteBase,
|
||||
NetBriteDB,
|
||||
NetBritePublic,
|
||||
NetBriteUpdate,
|
||||
ZoneBase,
|
||||
ZoneDB,
|
||||
ZonePublic,
|
||||
ZoneUpdate,
|
||||
)
|
||||
|
||||
DB_URL = "sqlite:///devices.db"
|
||||
|
@ -37,24 +40,22 @@ async def lifespan(_: FastAPI):
|
|||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
active_devices: dict[int, nb.NetBrite] = {}
|
||||
device_status: dict[int, bool] = {}
|
||||
|
||||
|
||||
# ---------- helper ----------
|
||||
def load_devices_from_db() -> None:
|
||||
with Session(engine) as session:
|
||||
for device in session.exec(select(NetBriteDB)).all():
|
||||
load_device(device, session)
|
||||
load_device(device)
|
||||
|
||||
|
||||
def load_device(device: NetBriteDB, session: SessionDep):
|
||||
def load_device(device: NetBriteDB):
|
||||
id = device.id or 0
|
||||
try:
|
||||
active_devices[id] = nb.NetBrite(device.address, device.port)
|
||||
device_status[id] = True
|
||||
load_zones_id(session, id, active_devices[id])
|
||||
|
||||
load_zones(device.zones, active_devices[id])
|
||||
except nb.NetbriteConnectionException as exc:
|
||||
device_status[id] = False
|
||||
print(f"Could not connect to {device.address}:{device.port} — {exc}")
|
||||
|
||||
|
||||
|
@ -64,8 +65,19 @@ def load_zones_id(session: Session, device_id: int, net_dev: nb.NetBrite):
|
|||
load_zones(zones, net_dev)
|
||||
|
||||
|
||||
def load_empty(net_dev: nb.NetBrite):
|
||||
message = nb.Message("clearing...")
|
||||
zone = nb.Zone(0, 0, 150, 7)
|
||||
|
||||
net_dev.zones({"empty": zone})
|
||||
net_dev.message(message, "empty")
|
||||
|
||||
|
||||
def load_zones(zones_in: list[ZoneDB], net_dev: nb.NetBrite) -> None:
|
||||
load_empty(net_dev)
|
||||
|
||||
zones: dict[str, nb.Zone] = {}
|
||||
messages: dict[str, nb.Message] = {}
|
||||
|
||||
for zone in zones_in:
|
||||
msg = zone.default_message
|
||||
|
@ -94,18 +106,18 @@ def load_zones(zones_in: list[ZoneDB], net_dev: nb.NetBrite) -> None:
|
|||
default_color=zone.default_color,
|
||||
initial_text=default_msg,
|
||||
)
|
||||
messages[zone.name] = default_msg
|
||||
|
||||
if zones:
|
||||
net_dev.zones(zones)
|
||||
|
||||
for zone, message in messages.items():
|
||||
net_dev.message(message, zone)
|
||||
|
||||
|
||||
def create_default_zone(session: Session, device_id: int) -> None:
|
||||
zone = ZoneDB(
|
||||
name="0",
|
||||
x=0,
|
||||
y=0,
|
||||
width=120,
|
||||
height=7,
|
||||
netbrite_id=device_id,
|
||||
)
|
||||
msg = MessageDB(
|
||||
|
@ -135,7 +147,9 @@ def create_device(device: NetBriteBase, session: SessionDep):
|
|||
session.commit()
|
||||
session.refresh(db_device)
|
||||
|
||||
load_device(db_device, session)
|
||||
create_default_zone(session, db_device.id or 0)
|
||||
|
||||
load_device(db_device)
|
||||
return db_device
|
||||
|
||||
|
||||
|
@ -145,40 +159,27 @@ def get_devices(session: SessionDep):
|
|||
|
||||
for device in session.exec(select(NetBriteDB)).all():
|
||||
device = NetBritePublic.model_validate(
|
||||
device, update={"active": device_status.get(device.id or 0) or False}
|
||||
device, update={"active": (device.id or 0) in active_devices}
|
||||
)
|
||||
devices.append(device)
|
||||
|
||||
return devices # FIXME: implement active
|
||||
return devices
|
||||
|
||||
|
||||
@app.post("/api/devices/{device_id}", response_model=NetBritePublic)
|
||||
def update_device(device_id: int, updated_device: NetBriteBase, session: SessionDep):
|
||||
def edit_device(device_id: int, updated_device: NetBriteUpdate, session: SessionDep):
|
||||
db_dev = session.get(NetBriteDB, device_id)
|
||||
if not db_dev:
|
||||
raise HTTPException(404, "Device not found")
|
||||
|
||||
db_dev.port = updated_device.port
|
||||
db_dev.address = updated_device.address
|
||||
dev_data = updated_device.model_dump(exclude_unset=True)
|
||||
_ = db_dev.sqlmodel_update(dev_data)
|
||||
|
||||
return 200
|
||||
session.add(db_dev)
|
||||
session.commit()
|
||||
session.refresh(db_dev)
|
||||
|
||||
|
||||
# TODO: implement me
|
||||
@app.post("/api/devices/{device_id}/reconnect")
|
||||
def reconnect_device(device_id: int, session: SessionDep):
|
||||
db_dev = session.get(NetBriteDB, device_id)
|
||||
if not db_dev:
|
||||
raise HTTPException(404, "Device not found")
|
||||
|
||||
try:
|
||||
active_devices[device_id] = nb.NetBrite(db_dev.address, db_dev.port)
|
||||
device_status[device_id] = True
|
||||
load_zones_id(session, device_id, active_devices[device_id])
|
||||
return 200
|
||||
except nb.NetbriteConnectionException as exc:
|
||||
device_status[device_id] = False
|
||||
raise HTTPException(400, str(exc))
|
||||
return db_dev # TODO: update device
|
||||
|
||||
|
||||
@app.delete("/api/devices/{device_id}")
|
||||
|
@ -204,13 +205,93 @@ def delete_device(device_id: int, session: SessionDep):
|
|||
return 200
|
||||
|
||||
|
||||
@app.post("/api/devices/{device_id}/zones", response_model=ZonePublic)
|
||||
def create_zone(device_id: int, body: ZoneBase, session: SessionDep):
|
||||
@app.post("/api/devices/{device_id}/reconnect")
|
||||
def reconnect_device(device_id: int, session: SessionDep):
|
||||
db_dev = session.get(NetBriteDB, device_id)
|
||||
if not db_dev:
|
||||
raise HTTPException(404, "Device not found")
|
||||
|
||||
try:
|
||||
active_devices[device_id] = nb.NetBrite(db_dev.address, db_dev.port)
|
||||
load_zones_id(session, device_id, active_devices[device_id])
|
||||
return 200
|
||||
except nb.NetbriteConnectionException as exc:
|
||||
raise HTTPException(400, str(exc))
|
||||
|
||||
|
||||
@app.post(
|
||||
"/api/devices/{device_id}/sync",
|
||||
description="**NOTE**: This will recreate the zones on the device.",
|
||||
)
|
||||
def sync_device(
|
||||
device_id: int,
|
||||
session: SessionDep,
|
||||
):
|
||||
if device_id not in active_devices:
|
||||
raise HTTPException(500, "Device not active, try reconnecting")
|
||||
|
||||
db_dev = session.get(NetBriteDB, device_id)
|
||||
if not db_dev:
|
||||
raise HTTPException(404, "Device not found")
|
||||
|
||||
try:
|
||||
load_zones(db_dev.zones, active_devices[device_id])
|
||||
except nb.NetbriteTransferException:
|
||||
del active_devices[device_id]
|
||||
raise HTTPException(500, "Failed to send zones. Device inactive now.")
|
||||
|
||||
return 200
|
||||
|
||||
|
||||
@app.post(
|
||||
"/api/devices/{device_id}/restart",
|
||||
)
|
||||
def restart_device(
|
||||
device_id: int,
|
||||
session: SessionDep,
|
||||
):
|
||||
if device_id not in active_devices:
|
||||
raise HTTPException(500, "Device not active, try reconnecting")
|
||||
|
||||
try:
|
||||
active_devices[device_id].reboot()
|
||||
del active_devices[device_id]
|
||||
except nb.NetbriteTransferException:
|
||||
raise HTTPException(500, "Failed to send zones. Device inactive now.")
|
||||
|
||||
return 200
|
||||
|
||||
|
||||
@app.post(
|
||||
"/api/devices/{device_id}/reload",
|
||||
description="**NOTE**: Will remove all zones and reload them with **default** messages",
|
||||
)
|
||||
def reload_device(device_id: int, session: SessionDep):
|
||||
if device_id not in active_devices:
|
||||
raise HTTPException(500, "Device not active, try reconnecting")
|
||||
|
||||
try:
|
||||
load_zones_id(session, device_id, active_devices[device_id])
|
||||
except nb.NetbriteTransferException:
|
||||
raise HTTPException(500, "Failed to send zones. Device inactive now.")
|
||||
|
||||
return 200
|
||||
|
||||
|
||||
@app.post(
|
||||
"/api/devices/{device_id}/zones",
|
||||
response_model=ZonePublic,
|
||||
description="**NOTE**: this does not update the device.",
|
||||
)
|
||||
def create_zone(device_id: int, new_zone: ZoneBase, session: SessionDep):
|
||||
device = session.get(NetBriteDB, device_id)
|
||||
if not device:
|
||||
raise HTTPException(404, "Device not found")
|
||||
|
||||
zone = ZoneDB.model_validate(body)
|
||||
new_zone_data = new_zone.model_dump(exclude_unset=True)
|
||||
extra_data = {"netbrite_id": device_id}
|
||||
zone = ZoneDB.model_validate(new_zone_data, update=extra_data)
|
||||
|
||||
msg = MessageDB(
|
||||
text="{erase}Welcome",
|
||||
)
|
||||
|
@ -224,13 +305,7 @@ def create_zone(device_id: int, body: ZoneBase, session: SessionDep):
|
|||
zone.default_message_id = msg.id
|
||||
session.commit()
|
||||
|
||||
if not device.id in active_devices:
|
||||
raise HTTPException(503, "Device not active")
|
||||
|
||||
try:
|
||||
load_zones(device.zones, active_devices[device.id])
|
||||
except nb.NetbriteTransferException:
|
||||
raise HTTPException(503, "Device not active")
|
||||
return zone
|
||||
|
||||
|
||||
@app.get("/api/devices/{device_id}/zones", response_model=list[ZonePublic])
|
||||
|
@ -244,8 +319,12 @@ def get_zones(device_id: int, session: SessionDep):
|
|||
|
||||
@app.delete(
|
||||
"/api/zone/{zone_id}",
|
||||
description="**NOTE**: this does not update the device.",
|
||||
)
|
||||
def delete_zone(zone_id: int, session: SessionDep):
|
||||
def delete_zone(
|
||||
zone_id: int,
|
||||
session: SessionDep,
|
||||
):
|
||||
zone = session.get(ZoneDB, zone_id)
|
||||
if not zone:
|
||||
raise HTTPException(404, "Zone not found")
|
||||
|
@ -258,3 +337,81 @@ def delete_zone(zone_id: int, session: SessionDep):
|
|||
session.commit()
|
||||
|
||||
return 200
|
||||
|
||||
|
||||
@app.post(
|
||||
"/api/zone/{zone_id}",
|
||||
response_model=ZonePublic,
|
||||
description="**NOTE**: this does not update the device.",
|
||||
)
|
||||
def edit_zone(zone_id: int, zone: ZoneUpdate, session: SessionDep):
|
||||
zone_db = session.get(ZoneDB, zone_id)
|
||||
|
||||
if not zone_db:
|
||||
raise HTTPException(404, "Zone not found")
|
||||
|
||||
zone_update_data = zone.model_dump(exclude_unset=True)
|
||||
print(zone_update_data)
|
||||
_ = zone_db.sqlmodel_update(zone_update_data)
|
||||
|
||||
session.add(zone_db)
|
||||
session.commit()
|
||||
session.refresh(zone_db)
|
||||
|
||||
return zone_db
|
||||
|
||||
|
||||
@app.post(
|
||||
"/api/zone/{zone_id}/adhoc_message",
|
||||
response_model=ZonePublic,
|
||||
description="**NOTE**: this does not update the device.",
|
||||
)
|
||||
def edit_message(zone_id: int, message: MessagePublic, session: SessionDep):
|
||||
zone_db = session.get(ZoneDB, zone_id)
|
||||
|
||||
if not zone_db:
|
||||
raise HTTPException(404, "Zone not found")
|
||||
|
||||
device_id = zone_db.netbrite_id
|
||||
if not device_id in active_devices:
|
||||
raise HTTPException(500, "Device inactive")
|
||||
|
||||
session.add(zone_db)
|
||||
session.commit()
|
||||
session.refresh(zone_db)
|
||||
|
||||
return zone_db
|
||||
|
||||
|
||||
@app.post(
|
||||
"/api/zone/{zone_id}/adhoc_message",
|
||||
response_model=ZonePublic,
|
||||
description="**NOTE**: this updates the device temporarily. Edit the zone message for permanent changes.",
|
||||
)
|
||||
def adhoc_message(zone_id: int, message: MessagePublic, session: SessionDep):
|
||||
zone_db = session.get(ZoneDB, zone_id)
|
||||
|
||||
if not zone_db:
|
||||
raise HTTPException(404, "Zone not found")
|
||||
|
||||
device_id = zone_db.netbrite_id
|
||||
if not device_id in active_devices:
|
||||
raise HTTPException(500, "Device inactive")
|
||||
|
||||
nb_message = nb.Message(
|
||||
text=message.text,
|
||||
activation_delay=message.activation_delay,
|
||||
display_delay=message.display_delay,
|
||||
display_repeat=message.display_repeat,
|
||||
priority=message.priority,
|
||||
sound_alarm=message.sound_alarm,
|
||||
ttl=message.ttl,
|
||||
)
|
||||
|
||||
try:
|
||||
active_devices[device_id].message(nb_message, zone_db.name)
|
||||
except nb.NetbriteTransferException:
|
||||
del active_devices[device_id]
|
||||
raise HTTPException(500, "Failed to send message. Device inactive now.")
|
||||
|
||||
return 200
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue