Finetuning prove of concept for the dashboard
This commit is contained in:
@@ -11,8 +11,11 @@ from utils.mqtt_client import publish, start_loop
|
|||||||
from config import ENV
|
from config import ENV
|
||||||
import dash_bootstrap_components as dbc
|
import dash_bootstrap_components as dbc
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
import pytz
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
API_BASE_URL = os.getenv("API_BASE_URL", "http://infoscreen-api:8000")
|
API_BASE_URL = os.getenv("API_BASE_URL", "http://192.168.43.100")
|
||||||
|
|
||||||
mqtt_thread_started = False
|
mqtt_thread_started = False
|
||||||
SCREENSHOT_DIR = "received-screenshots"
|
SCREENSHOT_DIR = "received-screenshots"
|
||||||
@@ -25,12 +28,13 @@ def ensure_mqtt_running():
|
|||||||
mqtt_thread_started = True
|
mqtt_thread_started = True
|
||||||
|
|
||||||
def get_latest_screenshot(client_uuid):
|
def get_latest_screenshot(client_uuid):
|
||||||
|
cache_buster = int(time.time()) # aktuelle Unix-Zeit in Sekunden
|
||||||
# TODO: Hier genau im Produkitv-Modus die IPs testen!
|
# TODO: Hier genau im Produkitv-Modus die IPs testen!
|
||||||
# Wenn API_BASE_URL auf "http" beginnt, absolute URL verwenden (z.B. im lokalen Dev)
|
# Wenn API_BASE_URL auf "http" beginnt, absolute URL verwenden (z.B. im lokalen Dev)
|
||||||
if API_BASE_URL.startswith("http"):
|
if API_BASE_URL.startswith("http"):
|
||||||
return f"{API_BASE_URL}/screenshots/{client_uuid}"
|
return f"{API_BASE_URL}/screenshots/{client_uuid}?t={cache_buster}"
|
||||||
# Sonst relative URL (nginx-Proxy übernimmt das Routing)
|
# Sonst relative URL (nginx-Proxy übernimmt das Routing)
|
||||||
return f"/screenshots/{client_uuid}"
|
return f"/screenshots/{client_uuid}?t={cache_buster}"
|
||||||
|
|
||||||
def fetch_clients():
|
def fetch_clients():
|
||||||
try:
|
try:
|
||||||
@@ -52,21 +56,42 @@ def update_clients(n):
|
|||||||
cards = []
|
cards = []
|
||||||
for client in clients:
|
for client in clients:
|
||||||
uuid = client["uuid"]
|
uuid = client["uuid"]
|
||||||
# screenshot = get_latest_screenshot(uuid)
|
|
||||||
screenshot = get_latest_screenshot(uuid)
|
screenshot = get_latest_screenshot(uuid)
|
||||||
# if screenshot[-3] != "jpg":
|
last_alive_utc = client.get("last_alive")
|
||||||
# screenshot += ".jpg"
|
if last_alive_utc:
|
||||||
print(f"UUID: {uuid}, Screenshot: {screenshot}")
|
try:
|
||||||
|
# Unterstützt sowohl "2024-06-08T12:34:56Z" als auch "2024-06-08T12:34:56"
|
||||||
|
if last_alive_utc.endswith("Z"):
|
||||||
|
dt_utc = datetime.strptime(last_alive_utc, "%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
else:
|
||||||
|
dt_utc = datetime.strptime(last_alive_utc, "%Y-%m-%dT%H:%M:%S")
|
||||||
|
dt_utc = dt_utc.replace(tzinfo=pytz.UTC)
|
||||||
|
# Lokale Zeitzone fest angeben, z.B. Europe/Berlin
|
||||||
|
local_tz = pytz.timezone("Europe/Berlin")
|
||||||
|
dt_local = dt_utc.astimezone(local_tz)
|
||||||
|
last_alive_str = dt_local.strftime("%d.%m.%Y %H:%M:%S")
|
||||||
|
except Exception:
|
||||||
|
last_alive_str = last_alive_utc
|
||||||
|
else:
|
||||||
|
last_alive_str = "-"
|
||||||
|
|
||||||
card = dbc.Card(
|
card = dbc.Card(
|
||||||
[
|
[
|
||||||
dbc.CardHeader(client["location"]),
|
dbc.CardHeader(client["location"]),
|
||||||
dbc.CardBody([
|
dbc.CardBody([
|
||||||
html.Img(
|
html.Img(
|
||||||
src=screenshot,
|
src=screenshot,
|
||||||
style={"width": "160px", "height": "90px", "object-fit": "cover"},
|
style={
|
||||||
|
"width": "240px",
|
||||||
|
"height": "135px",
|
||||||
|
"object-fit": "cover",
|
||||||
|
"display": "block",
|
||||||
|
"margin-left": "auto",
|
||||||
|
"margin-right": "auto"
|
||||||
|
},
|
||||||
),
|
),
|
||||||
html.P(f"IP: {client["ip_address"] or '-'}", className="card-text"),
|
html.P(f"IP: {client['ip_address'] or '-'}", className="card-text"),
|
||||||
html.P(f"Letzte Aktivität: {client["last_alive"] or '-'}", className="card-text"),
|
html.P(f"Letzte Aktivität: {last_alive_str}", className="card-text"),
|
||||||
dbc.ButtonGroup([
|
dbc.ButtonGroup([
|
||||||
dbc.Button("Reload Page", color="primary", id={"type": "btn-reload", "index": uuid}, n_clicks=0),
|
dbc.Button("Reload Page", color="primary", id={"type": "btn-reload", "index": uuid}, n_clicks=0),
|
||||||
dbc.Button("Restart Client", color="danger", id={"type": "btn-restart", "index": uuid}, n_clicks=0),
|
dbc.Button("Restart Client", color="danger", id={"type": "btn-restart", "index": uuid}, n_clicks=0),
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ def Sidebar(collapsed: bool = False) -> List[Any]:
|
|||||||
nav_items = [
|
nav_items = [
|
||||||
{"label": "Übersicht", "href": "/overview", "icon": "mdi:view-dashboard"},
|
{"label": "Übersicht", "href": "/overview", "icon": "mdi:view-dashboard"},
|
||||||
{"label": "Termine", "href": "/appointments","icon": "mdi:calendar"},
|
{"label": "Termine", "href": "/appointments","icon": "mdi:calendar"},
|
||||||
|
{"label": "Bildschirme", "href": "/clients", "icon": "mdi:monitor"},
|
||||||
{"label": "Einstellungen","href": "/settings", "icon": "mdi:cog"},
|
{"label": "Einstellungen","href": "/settings", "icon": "mdi:cog"},
|
||||||
{"label": "Benutzer", "href": "/users", "icon": "mdi:account"},
|
{"label": "Benutzer", "href": "/users", "icon": "mdi:account"},
|
||||||
]
|
]
|
||||||
|
|||||||
12
dashboard/pages/clients.py
Normal file
12
dashboard/pages/clients.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# dashboard/pages/clients.py
|
||||||
|
from dash import html, dcc
|
||||||
|
import dash
|
||||||
|
|
||||||
|
dash.register_page(__name__, path="/clients", name="Bildschirme")
|
||||||
|
|
||||||
|
layout = html.Div(
|
||||||
|
className="clients-page",
|
||||||
|
children=[
|
||||||
|
html.H3("Bildschirme"),
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
alembic>=1.16.1
|
||||||
bcrypt>=4.3.0
|
bcrypt>=4.3.0
|
||||||
paho-mqtt>=2.1.0
|
paho-mqtt>=2.1.0
|
||||||
PyMySQL>=1.1.1
|
PyMySQL>=1.1.1
|
||||||
|
|||||||
Reference in New Issue
Block a user