1. **Entfernung von 'node_modules'**: Es scheint, dass Sie den 'node_modules'-Ordner entfernt oder aktualisiert haben, da einige Dateien wie '.gitignore', 'package
321 lines
14 KiB
HTML
321 lines
14 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ device.name }} - Energiedetails - Mercedes-Benz TBA Marienfelde{% endblock %}
|
|
|
|
{% block head %}
|
|
{{ super() }}
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-slate-800">
|
|
|
|
<!-- Breadcrumb Navigation -->
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
|
<nav class="flex" aria-label="Breadcrumb">
|
|
<ol class="inline-flex items-center space-x-1 md:space-x-3">
|
|
<li class="inline-flex items-center">
|
|
<a href="/dashboard" class="text-gray-700 hover:text-mercedes-blue">
|
|
Dashboard
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<div class="flex items-center">
|
|
<svg class="w-6 h-6 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
|
</svg>
|
|
<a href="/energy" class="ml-1 text-gray-700 hover:text-mercedes-blue">
|
|
Energiemonitoring
|
|
</a>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div class="flex items-center">
|
|
<svg class="w-6 h-6 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
|
</svg>
|
|
<span class="ml-1 text-gray-500">{{ device.name }}</span>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
</nav>
|
|
</div>
|
|
|
|
<!-- Device Header -->
|
|
<div class="relative overflow-hidden bg-gradient-to-r from-slate-900 via-blue-900 to-indigo-900 text-white rounded-3xl mx-4 mb-8">
|
|
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
<div class="flex items-center space-x-6">
|
|
<div class="w-16 h-16 bg-white/10 backdrop-blur-sm rounded-full flex items-center justify-center">
|
|
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<h1 class="text-4xl font-bold">{{ device.name }}</h1>
|
|
<p class="text-xl text-blue-200">{{ device.model }} - Energiedetails</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-8">
|
|
|
|
<!-- Device Status Cards -->
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
|
|
|
<!-- Current Status -->
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6">
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Aktueller Status</h3>
|
|
<div class="space-y-3">
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Status:</span>
|
|
<span class="font-medium {% if device.status == 'online' %}text-green-600{% else %}text-red-600{% endif %}">
|
|
{{ 'Online' if device.status == 'online' else 'Offline' }}
|
|
</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Aktuelle Leistung:</span>
|
|
<span class="font-medium" id="current-power">{{ energy_data.current_power or '0.0' }} W</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Letzte Aktualisierung:</span>
|
|
<span class="font-medium" id="last-update">{{ energy_data.last_update or 'Unbekannt' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Daily Stats -->
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6">
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Heute</h3>
|
|
<div class="space-y-3">
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Verbrauch:</span>
|
|
<span class="font-medium" id="daily-consumption">{{ energy_data.daily_consumption or '0.0' }} kWh</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Betriebszeit:</span>
|
|
<span class="font-medium" id="daily-runtime">{{ energy_data.daily_runtime or '0h 0m' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Kosten:</span>
|
|
<span class="font-medium" id="daily-cost">{{ "%.2f"|format((energy_data.daily_consumption or 0) * 0.30) }} €</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Monthly Stats -->
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6">
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Diesen Monat</h3>
|
|
<div class="space-y-3">
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Verbrauch:</span>
|
|
<span class="font-medium" id="monthly-consumption">{{ energy_data.monthly_consumption or '0.0' }} kWh</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Betriebszeit:</span>
|
|
<span class="font-medium" id="monthly-runtime">{{ energy_data.monthly_runtime or '0h 0m' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Kosten:</span>
|
|
<span class="font-medium" id="monthly-cost">{{ "%.2f"|format((energy_data.monthly_consumption or 0) * 0.30) }} €</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts -->
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
|
|
|
<!-- Power Timeline -->
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6">
|
|
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-4">Leistungsverlauf (24h)</h3>
|
|
<div class="relative h-80">
|
|
<canvas id="powerTimelineChart"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Energy Consumption -->
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6">
|
|
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-4">Energieverbrauch (7 Tage)</h3>
|
|
<div class="relative h-80">
|
|
<canvas id="energyConsumptionChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Device Information -->
|
|
<div class="mt-8 bg-white dark:bg-gray-800 rounded-xl shadow-md p-6">
|
|
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-6">Geräteinformationen</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<h4 class="font-semibold text-gray-900 dark:text-white mb-3">Druckerdetails</h4>
|
|
<div class="space-y-2">
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Name:</span>
|
|
<span class="font-medium">{{ device.name }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Modell:</span>
|
|
<span class="font-medium">{{ device.model or 'Unbekannt' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Standort:</span>
|
|
<span class="font-medium">{{ device.location or 'TBA Marienfelde' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">IP-Adresse:</span>
|
|
<span class="font-medium">{{ device.ip_address or 'Nicht konfiguriert' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-semibold text-gray-900 dark:text-white mb-3">Smart Plug</h4>
|
|
<div class="space-y-2">
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Plug IP:</span>
|
|
<span class="font-medium">{{ device.plug_ip or 'Nicht konfiguriert' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Verbindung:</span>
|
|
<span class="font-medium {% if device.plug_ip %}text-green-600{% else %}text-red-600{% endif %}">
|
|
{{ 'Konfiguriert' if device.plug_ip else 'Nicht konfiguriert' }}
|
|
</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-600 dark:text-gray-400">Erstellungsdatum:</span>
|
|
<span class="font-medium">{{ device.created_at.strftime('%d.%m.%Y') if device.created_at else 'Unbekannt' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initializeCharts();
|
|
loadDeviceData();
|
|
|
|
// Auto-Update alle 30 Sekunden
|
|
setInterval(loadDeviceData, 30000);
|
|
});
|
|
|
|
function initializeCharts() {
|
|
// Power Timeline Chart
|
|
const powerCtx = document.getElementById('powerTimelineChart');
|
|
if (powerCtx) {
|
|
new Chart(powerCtx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: [],
|
|
datasets: [{
|
|
label: 'Leistung (W)',
|
|
data: [],
|
|
borderColor: '#0073ce',
|
|
backgroundColor: 'rgba(0, 115, 206, 0.1)',
|
|
fill: true,
|
|
tension: 0.4
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
title: {
|
|
display: true,
|
|
text: 'Leistung (W)'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Energy Consumption Chart
|
|
const energyCtx = document.getElementById('energyConsumptionChart');
|
|
if (energyCtx) {
|
|
new Chart(energyCtx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: [],
|
|
datasets: [{
|
|
label: 'Verbrauch (kWh)',
|
|
data: [],
|
|
backgroundColor: 'rgba(0, 115, 206, 0.8)',
|
|
borderColor: '#0073ce',
|
|
borderWidth: 1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
title: {
|
|
display: true,
|
|
text: 'Verbrauch (kWh)'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
async function loadDeviceData() {
|
|
try {
|
|
const deviceId = {{ device.id }};
|
|
const response = await fetch(`/api/energy/device/${deviceId}`);
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
updateDeviceMetrics(data);
|
|
}
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden der Gerätedaten:', error);
|
|
}
|
|
}
|
|
|
|
function updateDeviceMetrics(data) {
|
|
// Update current values
|
|
if (data.current_power !== undefined) {
|
|
document.getElementById('current-power').textContent = data.current_power.toFixed(1) + ' W';
|
|
}
|
|
|
|
if (data.daily_consumption !== undefined) {
|
|
document.getElementById('daily-consumption').textContent = data.daily_consumption.toFixed(2) + ' kWh';
|
|
|
|
// Update cost
|
|
const dailyCost = (data.daily_consumption * 0.30).toFixed(2);
|
|
document.getElementById('daily-cost').textContent = dailyCost + ' €';
|
|
}
|
|
|
|
if (data.monthly_consumption !== undefined) {
|
|
document.getElementById('monthly-consumption').textContent = data.monthly_consumption.toFixed(2) + ' kWh';
|
|
|
|
// Update cost
|
|
const monthlyCost = (data.monthly_consumption * 0.30).toFixed(2);
|
|
document.getElementById('monthly-cost').textContent = monthlyCost + ' €';
|
|
}
|
|
|
|
if (data.daily_runtime !== undefined) {
|
|
document.getElementById('daily-runtime').textContent = data.daily_runtime;
|
|
}
|
|
|
|
if (data.monthly_runtime !== undefined) {
|
|
document.getElementById('monthly-runtime').textContent = data.monthly_runtime;
|
|
}
|
|
|
|
if (data.last_update !== undefined) {
|
|
document.getElementById('last-update').textContent = new Date(data.last_update).toLocaleString('de-DE');
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %} |