From eb77fdd17db60e7c2c0de1a345e05264598c6a4d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 13 Dec 2025 13:31:19 +0000 Subject: [PATCH] Add Claude-friendly export format for Home Assistant data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- app.py | 124 ++++++++++++++++++++++++++++++++++++++++--- templates/index.html | 15 ++++-- 2 files changed, 128 insertions(+), 11 deletions(-) diff --git a/app.py b/app.py index efa1471..3c55bd6 100644 --- a/app.py +++ b/app.py @@ -96,20 +96,20 @@ def download_report(): 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: @@ -126,15 +126,127 @@ def download_report(): 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) diff --git a/templates/index.html b/templates/index.html index d596ce5..f0254d3 100644 --- a/templates/index.html +++ b/templates/index.html @@ -397,10 +397,13 @@
+
@@ -557,13 +560,15 @@ const downloadUrl = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = downloadUrl; - a.download = `ha_overview.${format}`; + // Setze korrekte Dateiendung + const extension = format === 'claude' ? 'md' : format; + a.download = `ha_overview.${extension}`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(a); - - showAlert('✓ Download gestartet!', 'success'); + + showAlert('Download gestartet!', 'success'); } else { showAlert('✗ Download fehlgeschlagen', 'error'); }