Homeassistant/app.py
Claude eb77fdd17d
Add Claude-friendly export format for Home Assistant data
Adds a new 'Export für Claude (AI)' button that generates a well-structured
Markdown file optimized for pasting into Claude. The export includes:
- System information
- Statistics overview
- Entities grouped by domain with details
- Installed components
- Available services
- Helpful hints for Claude on how to use the data
2025-12-13 13:31:19 +00:00

262 lines
9.8 KiB
Python

#!/usr/bin/env python3
"""
Home Assistant Overview - Web Application
Flask-basierte Web-Anwendung mit Frontend und Backend
"""
from flask import Flask, render_template, request, jsonify, send_file
from ha_overview import HomeAssistantOverview
import os
import json
from datetime import datetime
app = Flask(__name__)
# Konfigurationsdatei
CONFIG_FILE = 'config.json'
def load_config():
"""Lade gespeicherte Konfiguration"""
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, 'r') as f:
return json.load(f)
return {}
def save_config(url, token):
"""Speichere Konfiguration"""
config = {'url': url, 'token': token}
with open(CONFIG_FILE, 'w') as f:
json.dump(config, f)
@app.route('/')
def index():
"""Hauptseite mit Anleitung und Formular"""
config = load_config()
return render_template('index.html',
saved_url=config.get('url', ''),
has_config=bool(config))
@app.route('/api/test-connection', methods=['POST'])
def test_connection():
"""Teste die Verbindung zu Home Assistant"""
data = request.json
url = data.get('url')
token = data.get('token')
if not url or not token:
return jsonify({'success': False, 'error': 'URL und Token sind erforderlich'})
try:
ha = HomeAssistantOverview(url, token)
success = ha.test_connection()
if success:
# Speichere Konfiguration wenn gewünscht
if data.get('save_config'):
save_config(url, token)
return jsonify({'success': True, 'message': 'Verbindung erfolgreich!'})
else:
return jsonify({'success': False, 'error': 'Verbindung fehlgeschlagen'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
@app.route('/api/generate-report', methods=['POST'])
def generate_report():
"""Generiere vollständigen Bericht"""
data = request.json
url = data.get('url')
token = data.get('token')
if not url or not token:
return jsonify({'success': False, 'error': 'URL und Token sind erforderlich'})
try:
ha = HomeAssistantOverview(url, token)
report = ha.generate_report()
if report:
# Speichere Konfiguration wenn gewünscht
if data.get('save_config'):
save_config(url, token)
return jsonify({
'success': True,
'report': report
})
else:
return jsonify({'success': False, 'error': 'Report-Generierung fehlgeschlagen'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
@app.route('/api/download-report', methods=['POST'])
def download_report():
"""Erstelle und lade Report-Datei herunter"""
data = request.json
url = data.get('url')
token = data.get('token')
format_type = data.get('format', 'json')
if not url or not token:
return jsonify({'success': False, 'error': 'URL und Token sind erforderlich'})
try:
ha = HomeAssistantOverview(url, token)
report = ha.generate_report()
if report:
# Erstelle temporäres Verzeichnis falls nicht vorhanden
os.makedirs('downloads', exist_ok=True)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
if format_type == 'json':
filename = f'downloads/ha_overview_{timestamp}.json'
with open(filename, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
elif format_type == 'txt':
filename = f'downloads/ha_overview_{timestamp}.txt'
# Vereinfachte Textausgabe
with open(filename, 'w', encoding='utf-8') as f:
f.write("="*80 + "\n")
f.write("HOME ASSISTANT - VOLLSTÄNDIGER ÜBERBLICK\n")
f.write("="*80 + "\n")
f.write(f"Generiert am: {datetime.now().strftime('%d.%m.%Y um %H:%M:%S')}\n")
f.write("="*80 + "\n\n")
f.write(f"System: {report['system_info']['version']}\n")
f.write(f"Entitäten: {report['statistics']['total_entities']}\n")
f.write(f"Komponenten: {report['statistics']['total_components']}\n")
elif format_type == 'claude':
filename = f'downloads/ha_overview_{timestamp}_claude.md'
with open(filename, 'w', encoding='utf-8') as f:
f.write(generate_claude_format(report))
else:
return jsonify({'success': False, 'error': 'Ungültiges Format'})
return send_file(filename, as_attachment=True)
else:
return jsonify({'success': False, 'error': 'Report-Generierung fehlgeschlagen'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
def generate_claude_format(report):
"""Generiere Claude-freundliches Markdown-Format"""
lines = []
# Header
lines.append("# Home Assistant Konfiguration")
lines.append("")
lines.append("Dieser Export enthält alle relevanten Informationen meiner Home Assistant Installation.")
lines.append("Bitte nutze diese Daten um mir bei Fragen, Automatisierungen oder Problemlösungen zu helfen.")
lines.append("")
# System Info
sys_info = report.get('system_info', {})
lines.append("## System Information")
lines.append("")
lines.append(f"- **Version:** {sys_info.get('version', 'Unbekannt')}")
lines.append(f"- **Standort:** {sys_info.get('location_name', 'Unbekannt')}")
lines.append(f"- **Zeitzone:** {sys_info.get('timezone', 'Unbekannt')}")
lines.append(f"- **Einheiten:** {sys_info.get('unit_system', 'Unbekannt')}")
lines.append("")
# Statistiken
stats = report.get('statistics', {})
lines.append("## Übersicht / Statistiken")
lines.append("")
lines.append(f"- **Komponenten/Integrationen:** {stats.get('total_components', 0)}")
lines.append(f"- **Entitäten gesamt:** {stats.get('total_entities', 0)}")
lines.append(f"- **Services:** {stats.get('total_services', 0)}")
lines.append(f"- **Domains:** {stats.get('total_domains', 0)}")
lines.append(f"- **Events:** {stats.get('total_events', 0)}")
lines.append("")
# Entitäten nach Domain
entities_by_domain = report.get('entities_by_domain', {})
if entities_by_domain:
lines.append("## Entitäten nach Domain")
lines.append("")
lines.append("| Domain | Anzahl |")
lines.append("|--------|--------|")
for domain, count in sorted(entities_by_domain.items(), key=lambda x: -x[1]):
lines.append(f"| {domain} | {count} |")
lines.append("")
# Detaillierte Entitäten
detailed = report.get('detailed_entities', {})
if detailed:
lines.append("## Alle Entitäten (Details)")
lines.append("")
for domain, entities in sorted(detailed.items()):
lines.append(f"### {domain.upper()} ({len(entities)} Entitäten)")
lines.append("")
for entity in entities:
entity_id = entity.get('entity_id', 'unknown')
friendly_name = entity.get('attributes', {}).get('friendly_name', entity_id)
state = entity.get('state', 'unknown')
device_class = entity.get('attributes', {}).get('device_class', '')
device_info = f" ({device_class})" if device_class else ""
lines.append(f"- `{entity_id}`: **{friendly_name}**{device_info} = `{state}`")
lines.append("")
# Installierte Komponenten
components = report.get('components', [])
if components:
lines.append("## Installierte Komponenten/Integrationen")
lines.append("")
# Gruppiere in Zeilen zu je 5
for i in range(0, len(components), 5):
chunk = components[i:i+5]
lines.append("- " + ", ".join(f"`{c}`" for c in chunk))
lines.append("")
# Services (gruppiert)
services = report.get('services', [])
if services:
lines.append("## Verfügbare Services")
lines.append("")
services_by_domain = {}
for service in services:
domain = service.get('domain', 'unknown')
if domain not in services_by_domain:
services_by_domain[domain] = []
services_by_domain[domain].append(service.get('service', ''))
for domain, service_list in sorted(services_by_domain.items()):
lines.append(f"### {domain}")
for svc in sorted(service_list):
lines.append(f"- `{domain}.{svc}`")
lines.append("")
# Footer mit Hinweis
lines.append("---")
lines.append("")
lines.append("## Hinweise für Claude")
lines.append("")
lines.append("Mit diesen Daten kannst du mir helfen bei:")
lines.append("- Automatisierungen erstellen (YAML für automations.yaml)")
lines.append("- Skripte schreiben")
lines.append("- Dashboard/Lovelace Konfigurationen")
lines.append("- Problemdiagnose")
lines.append("- Entity-IDs für Szenen und Skripte finden")
lines.append("- Service-Calls zusammenstellen")
lines.append("")
lines.append(f"*Exportiert am: {datetime.now().strftime('%d.%m.%Y um %H:%M:%S')}*")
return "\n".join(lines)
if __name__ == '__main__':
# Erstelle templates-Verzeichnis falls nicht vorhanden
os.makedirs('templates', exist_ok=True)
os.makedirs('static', exist_ok=True)
print("\n" + "="*80)
print("HOME ASSISTANT OVERVIEW - WEB APPLICATION")
print("="*80)
print("\nStarte Server auf http://localhost:5000")
print("Drücke CTRL+C zum Beenden\n")
# Note: debug=False for security. Set to True only in trusted development environments.
app.run(debug=False, host='0.0.0.0', port=5000)