From 3a941b36fa4fa539efc7f76a3fce7e0a8f612a76 Mon Sep 17 00:00:00 2001 From: Kenearos <86194771+Kenearos@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:03:23 +0100 Subject: [PATCH] Add Home Assistant overview tool This script connects to Home Assistant and generates a comprehensive overview report of integrations, entities, and services, including options to save the report in JSON, TXT, and HTML formats. --- ha-overview.py | 488 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 488 insertions(+) create mode 100644 ha-overview.py diff --git a/ha-overview.py b/ha-overview.py new file mode 100644 index 0000000..d4cefdc --- /dev/null +++ b/ha-overview.py @@ -0,0 +1,488 @@ +#!/usr/bin/env python3 +""" +Home Assistant Complete Overview Tool +Erstellt eine vollständige Dokumentation aller Integrationen, Entitäten und Dienste +""" + +import requests +import json +from datetime import datetime +from collections import defaultdict + +class HomeAssistantOverview: + def __init__(self, url, token): + """ + Initialize Home Assistant connection + + Args: + url: Home Assistant URL (z.B. http://homeassistant.local:8123) + token: Long-Lived Access Token + """ + self.url = url.rstrip('/') + self.headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json" + } + + def test_connection(self): + """Teste die Verbindung zu Home Assistant""" + try: + response = requests.get(f"{self.url}/api/", headers=self.headers, timeout=10) + if response.status_code == 200: + print("✓ Verbindung erfolgreich!") + return True + else: + print(f"✗ Fehler: Status Code {response.status_code}") + return False + except Exception as e: + print(f"✗ Verbindungsfehler: {e}") + return False + + def get_config(self): + """Hole die Konfiguration""" + response = requests.get(f"{self.url}/api/config", headers=self.headers) + return response.json() + + def get_components(self): + """Hole alle installierten Komponenten/Integrationen""" + response = requests.get(f"{self.url}/api/config/core", headers=self.headers) + data = response.json() + return data.get('components', []) + + def get_states(self): + """Hole alle Entitäten mit ihren Zuständen""" + response = requests.get(f"{self.url}/api/states", headers=self.headers) + return response.json() + + def get_services(self): + """Hole alle verfügbaren Services""" + response = requests.get(f"{self.url}/api/services", headers=self.headers) + return response.json() + + def get_events(self): + """Hole alle verfügbaren Events""" + response = requests.get(f"{self.url}/api/events", headers=self.headers) + return response.json() + + def analyze_entities(self, states): + """Analysiere Entitäten nach Domains""" + by_domain = defaultdict(list) + for entity in states: + domain = entity['entity_id'].split('.')[0] + by_domain[domain].append(entity) + return dict(by_domain) + + def generate_report(self): + """Erstelle einen vollständigen Bericht""" + print("\n" + "="*80) + print("HOME ASSISTANT - VOLLSTÄNDIGER ÜBERBLICK") + print("="*80) + print(f"Generiert am: {datetime.now().strftime('%d.%m.%Y um %H:%M:%S')}") + print("="*80 + "\n") + + # Test connection + if not self.test_connection(): + return None + + print("\n📊 Sammle Daten...\n") + + # Sammle alle Daten + config = self.get_config() + components = self.get_components() + states = self.get_states() + services = self.get_services() + events = self.get_events() + entities_by_domain = self.analyze_entities(states) + + # Erstelle Report-Struktur + report = { + "timestamp": datetime.now().isoformat(), + "system_info": { + "version": config.get('version'), + "location_name": config.get('location_name'), + "timezone": config.get('time_zone'), + "unit_system": config.get('unit_system'), + "latitude": config.get('latitude'), + "longitude": config.get('longitude') + }, + "statistics": { + "total_components": len(components), + "total_entities": len(states), + "total_services": sum(len(domain['services']) for domain in services), + "total_domains": len(entities_by_domain), + "total_events": len(events) + }, + "components": sorted(components), + "entities_by_domain": { + domain: len(entities) for domain, entities in sorted(entities_by_domain.items()) + }, + "detailed_entities": entities_by_domain, + "services": services, + "events": events, + "all_states": states + } + + return report + + def print_summary(self, report): + """Drucke eine Zusammenfassung auf die Konsole""" + if not report: + return + + print("\n" + "="*80) + print("SYSTEM INFORMATIONEN") + print("="*80) + info = report['system_info'] + print(f"Version: {info['version']}") + print(f"Standort: {info['location_name']}") + print(f"Zeitzone: {info['timezone']}") + print(f"Einheitensystem: {info['unit_system']}") + + print("\n" + "="*80) + print("STATISTIKEN") + print("="*80) + stats = report['statistics'] + print(f"Komponenten: {stats['total_components']}") + print(f"Entitäten: {stats['total_entities']}") + print(f"Services: {stats['total_services']}") + print(f"Domains: {stats['total_domains']}") + print(f"Events: {stats['total_events']}") + + print("\n" + "="*80) + print("ENTITÄTEN NACH DOMAIN") + print("="*80) + for domain, count in sorted(report['entities_by_domain'].items(), key=lambda x: x[1], reverse=True): + print(f"{domain:.<30} {count:>4}") + + print("\n" + "="*80) + print("TOP 20 KOMPONENTEN") + print("="*80) + for i, component in enumerate(report['components'][:20], 1): + print(f"{i:2}. {component}") + if len(report['components']) > 20: + print(f"... und {len(report['components']) - 20} weitere") + + def save_report(self, report, format='json'): + """Speichere den Report in verschiedenen Formaten""" + if not report: + return None + + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + + if format == 'json': + filename = f"/mnt/user-data/outputs/ha_overview_{timestamp}.json" + with open(filename, 'w', encoding='utf-8') as f: + json.dump(report, f, indent=2, ensure_ascii=False) + return filename + + elif format == 'txt': + filename = f"/mnt/user-data/outputs/ha_overview_{timestamp}.txt" + 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") + + # System Info + f.write("SYSTEM INFORMATIONEN\n") + f.write("-"*80 + "\n") + info = report['system_info'] + for key, value in info.items(): + f.write(f"{key:20}: {value}\n") + + # Statistiken + f.write("\n" + "="*80 + "\n") + f.write("STATISTIKEN\n") + f.write("-"*80 + "\n") + stats = report['statistics'] + for key, value in stats.items(): + f.write(f"{key:20}: {value}\n") + + # Komponenten + f.write("\n" + "="*80 + "\n") + f.write(f"ALLE KOMPONENTEN ({len(report['components'])})\n") + f.write("-"*80 + "\n") + for component in sorted(report['components']): + f.write(f" • {component}\n") + + # Entitäten nach Domain + f.write("\n" + "="*80 + "\n") + f.write("ENTITÄTEN NACH DOMAIN\n") + f.write("-"*80 + "\n") + for domain, count in sorted(report['entities_by_domain'].items(), key=lambda x: x[1], reverse=True): + f.write(f"{domain:.<30} {count:>4}\n") + + # Detaillierte Entitäten + f.write("\n" + "="*80 + "\n") + f.write("ALLE ENTITÄTEN (DETAILLIERT)\n") + f.write("-"*80 + "\n") + for domain, entities in sorted(report['detailed_entities'].items()): + f.write(f"\n### {domain.upper()} ({len(entities)} Entitäten) ###\n") + for entity in entities: + f.write(f"\n Entity ID: {entity['entity_id']}\n") + f.write(f" Name: {entity['attributes'].get('friendly_name', 'N/A')}\n") + f.write(f" Zustand: {entity['state']}\n") + if entity['attributes'].get('device_class'): + f.write(f" Klasse: {entity['attributes']['device_class']}\n") + f.write(f" Letzte Änderung: {entity['last_changed']}\n") + + # Services + f.write("\n" + "="*80 + "\n") + f.write("VERFÜGBARE SERVICES\n") + f.write("-"*80 + "\n") + for domain_services in report['services']: + domain = domain_services['domain'] + f.write(f"\n### {domain.upper()} ###\n") + for service_name, service_data in domain_services['services'].items(): + f.write(f" • {domain}.{service_name}\n") + if service_data.get('description'): + f.write(f" {service_data['description']}\n") + + # Events + f.write("\n" + "="*80 + "\n") + f.write("VERFÜGBARE EVENTS\n") + f.write("-"*80 + "\n") + for event in report['events']: + f.write(f" • {event['event']}\n") + + return filename + + elif format == 'html': + filename = f"/mnt/user-data/outputs/ha_overview_{timestamp}.html" + with open(filename, 'w', encoding='utf-8') as f: + f.write(""" + + + + + Home Assistant Überblick + + + +""") + + f.write(f""" +
+

🏠 Home Assistant Überblick

+

Generiert am: {datetime.now().strftime('%d.%m.%Y um %H:%M:%S')}

+

Version: {report['system_info']['version']} | Standort: {report['system_info']['location_name']}

+
+ +
+
+

Komponenten

+
{report['statistics']['total_components']}
+
+
+

Entitäten

+
{report['statistics']['total_entities']}
+
+
+

Services

+
{report['statistics']['total_services']}
+
+
+

Domains

+
{report['statistics']['total_domains']}
+
+
+

Events

+
{report['statistics']['total_events']}
+
+
+ +
+

📦 Installierte Komponenten

+""") + + for component in sorted(report['components']): + f.write(f' {component}\n') + + f.write(""" +
+ +
+

📊 Entitäten nach Domain

+ + + + + + + + +""") + + for domain, count in sorted(report['entities_by_domain'].items(), key=lambda x: x[1], reverse=True): + f.write(f""" + + + + +""") + + f.write(""" + +
DomainAnzahl
{domain}{count}
+
+ +
+

🔧 Alle Entitäten

+""") + + for domain, entities in sorted(report['detailed_entities'].items()): + f.write(f""" +

{domain.upper()} ({len(entities)} Entitäten)

+
+""") + for entity in entities: + name = entity['attributes'].get('friendly_name', entity['entity_id']) + f.write(f""" +
+
{entity['entity_id']}
+
{name}
+
Zustand: {entity['state']}
+
+""") + f.write("
\n") + + f.write(""" +
+ + +""") + + return filename + + +def main(): + """Hauptfunktion""" + print("\n" + "="*80) + print("HOME ASSISTANT OVERVIEW TOOL") + print("="*80 + "\n") + + # Eingaben + url = input("Home Assistant URL (z.B. http://homeassistant.local:8123): ").strip() + token = input("Long-Lived Access Token: ").strip() + + # Erstelle Overview-Objekt + ha = HomeAssistantOverview(url, token) + + # Generiere Report + report = ha.generate_report() + + if report: + # Zeige Zusammenfassung + ha.print_summary(report) + + # Speichere in allen Formaten + print("\n" + "="*80) + print("SPEICHERE BERICHTE...") + print("="*80) + + json_file = ha.save_report(report, 'json') + txt_file = ha.save_report(report, 'txt') + html_file = ha.save_report(report, 'html') + + print(f"\n✓ JSON-Bericht: {json_file}") + print(f"✓ Text-Bericht: {txt_file}") + print(f"✓ HTML-Bericht: {html_file}") + + print("\n" + "="*80) + print("FERTIG!") + print("="*80 + "\n") + + +if __name__ == "__main__": + main()