[Tutorial] Alle HA Entitäten per CSV auslesen und mit Analyzer Tool oder Excel auswerten

Wir hatten diese Woche ein sehr interessantes Wochenthema. Vielen Dank an @Dreckfresse für den Input. Ich wollte nicht, dass dieses Thema untergeht und habe daher ein kleines Wiki inkl. Analyzer Tool geschrieben in der Hoffnung, dass hier viele mitlesen und es nutzen können.

Man kann wie im HA-Forum beschrieben wurde, auf dem Dahsboard einen Button anlegen, der nach drücken alle Home Assistant Entitäten, Automationen usw. in eine csv Datei exportiert. Diese Funktion vermisse ich aktuell in HA, da man so eine schöne “offline/backup” Variante hat, die Entitäten für sich zu strukturieren, zu kontrollieren, zu dokumentieren bzw. sich einen Überblick zu verschaffen. Perfekt um “Leichen” auszusortieren, Namenstrukturen zu entwickeln usw… Anschauen könnt ihr euch die csv-Datei z.B. mit dem beigefügtem Analyzer Tool oder mit Excel.

image (1)

Erstellt als erstes im Dashboard eine neue custom button card und fügt dort folgenden Code ein. Im Anschluss solltet ihr wie im Bild gezeigt diesen Button erhalten. Drückt nach Fertigstellung den Button und ihr bekommt die csv-Datei in den Download-Ordner.

type: custom:button-card
name: Entity Export as CSV
tap_action:
  action: javascript
  javascript: |
    [[[
      function generateEntityItems() {
          const hass = document.querySelector("home-assistant").hass;
          const entities = hass.entities;
          
          const sorted = Object.values(entities).sort((a, b) => {
              const idA = a.entity_id?.toLowerCase() || '';
              const idB = b.entity_id?.toLowerCase() || '';
              return idA.localeCompare(idB);
          });
      
          let csvContent = "ENTITY ID;ENTITY NAME;DEVICE NAME;DEVICE ID;AREA;PLATFORM (INTEGRATION);STATE;FORMATED STATE\n";
          
          sorted.forEach((ent) => {
              const eId = ent.entity_id;
              const stateObj = hass.states[eId];
              const entityName = hass.formatEntityName(stateObj, "entity");
              const deviceName = hass.formatEntityName(stateObj, "device");
              const deviceId =  ent.device_id;
              const areaName = hass.formatEntityName(stateObj, "area") || '';
              const platform = ent.platform || '';
              const state = stateObj.state;
              const formatedState = hass.formatEntityState(stateObj);
              
              const info = [eId, entityName, deviceName, deviceId, areaName, platform, state, formatedState].join("; ");
              
              csvContent += `${info}\n`;
          });
      
          const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
          const url = URL.createObjectURL(blob);
          const link = document.createElement("a");
          link.setAttribute("href", url);
          link.setAttribute("download", "hass_entities.csv");
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
      };
      generateEntityItems();
    ]]]

Ich habe ein kleines Python Tool entwickelt, dass die CSV einlesen kann. Ihr könnt aber auch z.B. mit Excel (Spaltenansicht) oder anderem Programm die Datei anschauen. Für Windows gibt es gibt zwei Wege für die Installation, erstens bequem mit fertigem Programm arbeiten oder zweitens Python direkt installieren und das py-Script starten. Für Linux bleibt aktuell nur die Möglichkeit über Python direkt zu arbeiten, folgt dazu den Anweisungen.

Für Windows ladet euch einfach die ausführbare Version (.exe) herunter und startet das Programm.

Hier könnt ihr das Tool bei mir im github herunterladen:


Betrifft nur die manuelle Installation:

Das Tool nutzt Python, daher muss Python installiert sein oder werden!

In Windows öffnet ihr dazu die Powershell und gebt folgenden Befehl ein:

winget install Python

Alternativ oder sogar besser ist es die aktuelle Python-Version von der Website für Windows herunterzuladen und zu installieren.

Danach installiert ihr noch das pandas Paket bzw. die Bibliothek:

pip install pandas

Unter Windows könnt ihr die Python Datei direkt aus dem „src“ Ordner mit Doppelklick starten.


Unter Linux gebt folgende Befehle im Terminal ein:

sudo apt update && sudo apt install python3

Danach installiert ihr noch das pandas Paket bzw. die Bibliothek:

pip install pandas

Um das Programm zu öffnen, wechselt mit cd /euer Verzeichnis in den Ordner wo euer Entity_Analyzer liegt und startet mit folgendem Befehl das Tool.

python3 entity_analyzer_v1.py

Nun könnt ihr den Entity_Analyzer öffnen und eure csv-Datei auswählen. Die Oberfläche bietet ein paar Möglichkeiten eure Entitäten zu sichten. Nach dem öffnen seht ihr unten links die Anzahl der Entitäten!

  1. Jetzt könnt ihr beispielsweise nach gewünschten Entitäten suchen:

    Über die Spaltennamen kann beim auswählen eine aufsteigende oder absteigende Sortierung erfolgen.

  1. Die Entitätsstatistik abrufen und sehen wie viele Lichter oder Schalter ihr habt usw.:

  1. Oder ihr könnt nach Area also Bereichen bzw. nach Platform und somit Integrationen filtern.

Ihr könnt die geänderte csv-Datei mit Semikolon Trenner auch direkt in Excel öffnen und einsehen. Wer sich dort ein wenig auskennt, kann schnell die obere Zeile fixieren und ein Filter auf die Tabelle anwenden. Damit hat man einen ähnlichen Funktionsumfang wie mit meinem Tool. Aber nicht so ein eine schöne Zusammenfassung wie in den letzten Bildern. :wink:

So hoffe nichts vergessen zu haben, ansonsten schreibt gerne und ich kann das hier noch entsprechend ergänzen. :slight_smile:

Danke an @Nicknol für die Änderung der Formatierung von Komma in Semikolon Trenner.

14 „Gefällt mir“

Großartig, danke @jayjojayson :pray::blush:

Um sich die externe Konvertierung der Kommas in Semikolons zu sparen, funktioniert folgender Code:

type: custom:button-card
name: Entity Export
tap_action:
  action: javascript
  javascript: |
    [[[
      function generateEntityItems() {
          const hass = document.querySelector("home-assistant").hass;
          const entities = hass.entities;
          
          const sorted = Object.values(entities).sort((a, b) => {
              const idA = a.entity_id?.toLowerCase() || '';
              const idB = b.entity_id?.toLowerCase() || '';
              return idA.localeCompare(idB);
          });
      
          let csvContent = "ENTITY ID;ENTITY NAME;DEVICE NAME;DEVICE ID;AREA;PLATFORM (INTEGRATION);STATE;FORMATED STATE\n";
          
          sorted.forEach((ent) => {
              const eId = ent.entity_id;
              const stateObj = hass.states[eId];
              const entityName = hass.formatEntityName(stateObj, "entity");
              const deviceName = hass.formatEntityName(stateObj, "device");
              const deviceId =  ent.device_id;
              const areaName = hass.formatEntityName(stateObj, "area") || '';
              const platform = ent.platform || '';
              const state = stateObj.state;
              const formatedState = hass.formatEntityState(stateObj);
              
              const info = [eId, entityName, deviceName, deviceId, areaName, platform, state, formatedState].join("; ");
              
              csvContent += `${info}\n`;
          });
      
          const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
          const url = URL.createObjectURL(blob);
          const link = document.createElement("a");
          link.setAttribute("href", url);
          link.setAttribute("download", "hass_entities.csv");
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
      };
      generateEntityItems();
    ]]]
grid_options:
  columns: 6
  rows: 1

Mit dem Python Programm muss ich mich noch beschäftigen :wink:

Nochmals vielen Dank an @Dreckfresse für’s finden und an @jayjojayson für den Wiki-Eintrag und das Python-Programm. :slight_smile:

5 „Gefällt mir“

Danke @Nicknol, oh man, dass wollte ich auch noch ändern im java-script. :hugs: Hatte zumindest die Idee. Schon wieder so oft über das Wiki gelesen… Wird direkt geändert und funktioniert mit meinem Tool einwandfrei, gerade getestet! :slight_smile:

3 „Gefällt mir“

Super Tutorial! Das python-Tool sieht auch ziemlich cool aus, was bietet das für ein Vorteil im Gegensatz zur eingebauten HA-Geräte-Suche (unter Geräte & Dienste)?
Ansonsten noch etwas zu dem Tool: Du kannst es mit pyinstaller --onefile filename --windowed auch in eine .exe File verwandeln. Das ist für Windows-User sicherlich die bequemste Variante :slight_smile: Dann muss man weder Python noch Pandas installiert haben :))
Mit dem gleichen Tool kannst du auch fertige Programme für MacOS und Linux erzeugen, dafür werden die jeweiligen Systeme aber benötigt…

3 „Gefällt mir“

@jayjojayson
Klasse Aufbereitet
und kleines Python Tool (das muss ich mir dringend anschauen) :+1:
und
@Nicknol fürs Anpassung der Formatierung :+1:

4 „Gefällt mir“

Hi, ich weiß die python kann man umwandeln, aber die pyw kann auch direkt ausgeführt werden, wird also wie eine exe behandelt. Man muss aber halt python und das pandas Paket installiert haben. Ist ja eigentlich schnell gemacht.

Die Umwandlung habe ich auch schon versucht, aber scheitere da aktuell noch an Fehlern mit dem numpy Paket. Problem ist dann auch oft unter Win, dass die exe als Virus erkannt wird, warum auch immer. Web sagt, kommt durch das packen vom Python Paket. Ich werde das nochmal versuchen, so lange funktioniert der andere Weg auch erstmal sehr gut und jeder kann der Code nachvollziehen, wenn er mag (ist gut dokumentiert).

Vorteil sehe ich darin, die ganzen Sache „offline“ als Datei zu haben. Wenn man ein neues HA erstellt, kann man sich so die alten Entitätennamen wiederholen. Oder während man mal wieder ein Template schreibt Namen heraussuchen usw. Die Entitäts-Statistik finde ich auch ganz nett. Ist natürlich alles Spielerei, aber finde ich schon irgendwie praktisch.

3 „Gefällt mir“

Ah, ich verstehe! Das macht dann tatsächlich Sinn :slight_smile:
Zu der .exe-Generierung: Ich habe es mal bei deinem Tool probiert - es funktioniert bei mir ziemlich gut, leider hat die .exe aber 230MB :face_with_diagonal_mouth:

230MB hört sich sehr groß an, aber cool das es überhaupt funktioniert. Bei meinen Versuchen waren es zwischen 15 und 44MB. Muss ja etwas mit den verpackten Bibliotheken zu tun haben. Ich teste später nochmal, sind heute mal wieder zum Geburtstag eingeladen.

Hast du das jetzt auf dem Mac gepackt oder unter Win?

Windows. Wenn du es später nochmal weiter getestet hast, können wir das sonst auch gerne im Privatchat weiter besprechen, sonst wird der schöne Beitrag so unübersichtlich :grin:

2 „Gefällt mir“

Ich habe es hinbekommen und auch gleich noch die py unter Linux im Windows Subsystem getestet. Läuft jetzt auch korrekt. Die exe ist nun 35MB groß, damit kann man leben.

Oben das Wiki habe ich entsprechend geändert und einen neuen Release im Github veröffentlicht. Schaut gerne vorbei. :slight_smile:

Update Analyzer Tool:

  • release ausführbare .exe Datei für Windows (Python muss nicht installiert sein)
  • Überarbeitung vom pyscript für Linux, so dass die py korrekt öffnet
  • neue Ordnerstruktur im Github
  • ReadMe im Github überarbeitet
4 „Gefällt mir“

Großartigis Tool , danke super einfach zu verwenden @jayjojayson :pray: :+1:

1 „Gefällt mir“

Die Variante, die CSV Datei per Java-Script über die Button-Card zu erzeugen, ist für ad-hoc Auswertungen hervorragend.
Als regelmäßiges Backup ist sie daher nicht optimal, und daher habe ich (mit Hilfe einer KI für die Syntax) einen Weg über Skripte in HA und Shell gewählt.

Die erzeugte Datei ist direkt in Excel einlesbar. und wird mit einem Zeitstempel im Dateinamen versehen.
Falls man den Speicherpfad auf z.b. ein NAS legt, ist sie auch bei einem Ausfall von HA verfügbar.

CSV Export aller Entitäten per Skript

Insgesamt brauchen wir:

  • Ein HA Skript, das alle Entitäten und deren Daten zusammenstellt und in eine Datei schreibt
  • Etwas, was per HA in eine Datei schreiben kann.Dafür habe ich bislang nur eine Datei-Entität mit Einsatzzweck „Benachrichtigung“ gefunden
  • Ein Shell Skript, das im Dateisystem für Ordnung sorgt.
  • Eine Automation, die regelmäßig einen Export anstößt

ich verwende hier <<<Zielverzeichnis für den Export>>>, dies muss für die eigene Verwendung angepasst werden

Skript: Entittäten zusammenstellen

sequence:
  - variables:
      entity_ids_sorted: "{{ states | map(attribute='entity_id') | list | sort }}"
  - data:
      entity_id: notify.entity_dump
      message: >-
        "entity_id";"friendly_name";"device";"domain";"area";"floor";"active";"state"
    action: notify.send_message
  - repeat:
      count: "{{ entity_ids_sorted | count }}"
      sequence:
        - variables:
            id: "{{ entity_ids_sorted[repeat.index-1] }}"
            obj: "{{ states(id) }}"
        - choose:
            - conditions:
                - condition: template
                  value_template: "{{ obj is not none }}"
              sequence:
                - variables:
                    name: "{{ obj.name | default('') }}"
                    dev: "{{ device_id(id) | default('') }}"
                    dev_name: "{{ device_name(id) or dev }}"
                    dom: "{{ id.split('.',1)[0] }}"
                    area: "{{ area_name(id) | default('') }}"
                    area_identifier: "{{ area_id(id) | default('') }}"
                    flo_id: "{{ floor_id(area_identifier) | default('') }}"
                    flo_name: "{{ floor_name(flo_id) | default('') }}"
                    aktiv: >-
                      {{ states(id) not in ['unavailable','unknown','none','']
                      }}
                    state: "{{ states(id) | default('')  }}"
                    state_tr: "{{ state_translated(id) | default('')  }}"
                - data:
                    entity_id: notify.entity_dump
                    message: >-
                      "{{ id }}";"{{ name }}";"{{ dev_name }}";"{{ dom }}";"{{
                      area }}";"{{ flo_name }}";"{{ aktiv }}";"{{ state }}";"{{
                      state_tr }}"
                  action: notify.send_message
  - action: shell_command.manage_entity_dump
    data:
      action: trim
  - action: shell_command.manage_entity_dump
    data:
      action: rename
  - action: shell_command.manage_entity_dump
    data:
      action: purge
alias: Entity Dump to File
description: ""

Datei-Entität für Benachrichtigungen

Integration File hinzufügen

Dort einen Benachrichtigungsdienst auswählen

Den Pfad inkl Dateiname zur export datei eintragen, der Dateiname, der im Shellscript verwendet wird, ist entity_dump.csv - er sollte beibehalten werden.
und es soll kein Zeitstempel geschrieben werden

anschließend die File Entität finden (sieht ähnlich aus wie im Screenshot)

und dann umbenennen wie im Screenshot, dann passt es zum HA Skript

Shell Skript für’s Dateisystem

um das Skript aus HA aufrufen zu können, muss ein shell_command definiert werden.

configuration.yaml:

shell_command: !include shell_command.yaml

shell_command.yaml:

  /config/custom_scripts/entity_dump/manage_entity_dump.sh --action "{{ action }}"

Shell Script

#!/bin/bash

# === Konfiguration ===
DUMP_DIR="<<<Zielverzeichnis für den Export>>>"
BASENAME="entity_dump"
EXTENSION="csv"
DUMP_FILE="${BASENAME}.${EXTENSION}"
DUMP_PATH="${DUMP_DIR}/${DUMP_FILE}"

# === Logging ===
SCRIPT_NAME="$(basename "$0" .sh)"
LOG_FILE="${DUMP_DIR}/${SCRIPT_NAME}.log"

log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}

# === Hilfe anzeigen ===
show_help() {
  echo "Usage: $SCRIPT_NAME --action [purge|trim|rename] [--dry-run]"
  echo ""
  echo "  --action purge     Löscht alle Dateien mit Präfix außer den 5 neuesten"
  echo "  --action trim      Entfernt die ersten zwei Zeilen aus der Dump-Datei"
  echo "  --action rename    Benennt die Dump-Datei mit Zeitstempel um"
  echo "  --dry-run          Zeigt nur an, was passieren würde"
  echo "  --help             Zeigt diese Hilfe"
}

# === Parameterverarbeitung ===
DRY_RUN=false
while [[ $# -gt 0 ]]; do
  case "$1" in
    --action)
      ACTION="$2"
      shift 2
      ;;
    --dry-run)
      DRY_RUN=true
      shift
      ;;
    --help)
      show_help
      exit 0
      ;;
    *)
      echo "❌ Unbekannter Parameter: $1"
      show_help
      exit 1
      ;;
  esac
done

if [ -z "$ACTION" ]; then
  echo "❌ Fehler: --action fehlt"
  show_help
  exit 1
fi

# === Aktionen ===
case "$ACTION" in
  purge)
    log "🔁 purge – Ältere Dumps löschen (nur 5 neueste behalten)"
    cd "$DUMP_DIR" || { log "❌ Verzeichnis nicht gefunden: $DUMP_DIR"; exit 1; }
    FILES_TO_DELETE=$(ls -t "${BASENAME}"*".${EXTENSION}" 2>/dev/null | tail -n +6)
    if [ -z "$FILES_TO_DELETE" ]; then
      log "ℹ️ Keine Dateien zum Löschen gefunden"
    else
      for file in $FILES_TO_DELETE; do
        if $DRY_RUN; then
          log "🧪 [dry-run] Würde löschen: $file"
        else
          log "🗑️ Lösche: $file"
          rm -f "$file"
        fi
      done
    fi
    ;;

  trim)
    log "✂️ trim – Entferne erste zwei Zeilen aus $DUMP_PATH"
    if [ -f "$DUMP_PATH" ]; then
      if $DRY_RUN; then
        log "🧪 [dry-run] Würde erste zwei Zeilen aus $DUMP_PATH entfernen"
      else
        tail -n +3 "$DUMP_PATH" > "${DUMP_PATH}.tmp" && mv "${DUMP_PATH}.tmp" "$DUMP_PATH"
        log "✅ Trim erfolgreich"
      fi
    else
      log "❌ Datei nicht gefunden: $DUMP_PATH"
      exit 1
    fi
    ;;

  rename)
    TIMESTAMP=$(date -r "$DUMP_PATH" +"%Y%m%d_%H%M%S")
    NEW_NAME="${DUMP_DIR}/${BASENAME}_${TIMESTAMP}.${EXTENSION}"
    log "📦 rename – Benenne $DUMP_PATH → $NEW_NAME"
    if [ -f "$DUMP_PATH" ]; then
      if $DRY_RUN; then
        log "🧪 [dry-run] Würde umbenennen: $DUMP_PATH → $NEW_NAME"
      else
        mv "$DUMP_PATH" "$NEW_NAME"
        log "✅ Umbenennung erfolgreich"
      fi
    else
      log "❌ Datei nicht gefunden: $DUMP_PATH"
      exit 1
    fi
    ;;

  *)
    echo "❌ Unbekannte Aktion: $ACTION"
    show_help
    exit 1
    ;;
esac

Automation

alias: Dump Entities to File
description: ""
triggers:
  - trigger: time
    at: "02:17:00"
conditions: []
actions:
  - action: script.entity_dump_to_file
    metadata: {}
    data: {}
mode: single
4 „Gefällt mir“

Hi, danke für deinen Input zum automatischen Abruf der csv-file @Nicknol. Ich habe diese Woche leider nicht viel Zeit, werde es mir aber am Wochenende genauer anschauen und würde deinen Teil gerne oben mit ins Wiki aufnehmen, mache dann einen ausklappbaren Teil mit deiner Beschreibung zur automatischen Erstellung.

Am Wochenende habe ich ein wenig das Entity-Analyzer-Tool für die csv überarbeitet. Hat jetzt eine ordentliche Menüleiste bekommen, csv-files können nun auch exportiert werden, die Suche ist wesentlich schneller und in der GUI ist neben einem dark/light modus die Möglichkeit gegeben das Programmfenster im Vordergrund zu halten. Die neue Version findet ihr unter Releases im Github von mir.

App-Features:

  • :page_facing_up: simple Entities Tool to analyze your csv-file
  • ↔️ import and export csv file
  • :mag: free entity search
  • :bookmark: area & platform filter
  • :bar_chart: entities statistic

Gui-Features

  • works on win, (macos & linux in Arbeit)
  • dark/lite mode
  • app on top (keep in foreground)

Danke an @MarzyHA für die Erstellung der build.yml in github. Richtig cool, kannte ich vorher noch nicht und so wird die exe direkt in github gebaut, sobald ich eine neue Version veröffentliche. Muss also nicht mehr manuell die exe erstellen, passiert automatisch im Hintergrund. Außerdem wird die Datei so auch direkt im Release als Download angeboten.

Zusammen sind wir ein starkes Team. :partying_face:

4 „Gefällt mir“

In der HA Community hat mich einer aufmerksam gemacht, dass er keine Area und Platform mehr in der exportierten CSV vorhanden sind! Dann hatte ich mir das heute Abend mal angeschaut und ist tatsächlich so. HA hat etwas verändert, so dass ich die button-card auf die Anfrage in den jeweiligen Registern umgestellt habe. Jetzt funktioniert auch Area und Platform wieder korrekt. Das Ananlyzer-Tool musste dafür im neuen Release auch anpassen und habe auch gleich noch ein paar andere Optimierungen vorgenommen.

Code zur Button-Card:

type: custom:button-card
name: Entity Export as CSV
tap_action:
  action: javascript
  javascript: |
    [[[
      function clean(value) {
        if (!value) return "";
        return String(value)
          .replace(/;/g, ",")   
          .replace(/\r?\n|\r/g, " ");  
      }

      async function generateCSV() {
        const hass = document.querySelector("home-assistant").hass;

        const areas = await hass.callWS({ type: "config/area_registry/list" });
        const devices = await hass.callWS({ type: "config/device_registry/list" });
        const entities = await hass.callWS({ type: "config/entity_registry/list" });

        const areaLookup = {};
        areas.forEach(a => areaLookup[a.area_id] = a.name);

        let csv = "ENTITY ID;ENTITY NAME;DEVICE NAME;DEVICE ID;AREA;PLATFORM;STATE;FORMATTED STATE\n";

        Object.values(hass.states)
          .sort((a,b) => a.entity_id.localeCompare(b.entity_id))
          .forEach(stateObj => {

            const entReg = entities.find(e => e.entity_id === stateObj.entity_id);
            const device = devices.find(d => d.id === entReg?.device_id);

            const areaName =
              entReg?.area_id ? areaLookup[entReg.area_id] || "" :
              device?.area_id ? areaLookup[device.area_id] || "" :
              "";

            const row = [
              clean(stateObj.entity_id),
              clean(hass.formatEntityName(stateObj)),
              clean(device?.name || ""),
              clean(entReg?.device_id || ""),
              clean(areaName),
              clean(entReg?.platform || ""),
              clean(stateObj.state),
              clean(hass.formatEntityState(stateObj))
            ].join("; ");

            csv += row + "\n";
          });

        const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = "hass_entities.csv";
        a.click();
        URL.revokeObjectURL(url);
      }

      generateCSV();
    ]]]

Mit dem neuen Energiedashboard in HA kann man jetzt auch CSV Dateien der Statistiken exportieren! Mal schauen, ob ich da mit dem Analyzer Tool etwas hinbekomme. :slight_smile:

1 „Gefällt mir“

Danke @jayjojayson ! :slight_smile:

auch ich habe mein Dump Skript erweitert. es speichert nun auch Hersteller, Modell, HW/SW Version der Entitiät.

hier das erweiterte Skript

sequence:
  - variables:
      entity_ids_sorted: "{{ states | map(attribute='entity_id') | list | sort }}"
  - data:
      entity_id: notify.entity_dump
      message: >-
        "entity_id";"friendly_name";"device";"domain";"area";"floor";"active";"state";"state_tr";"manufacturer";"model";"model_id";"sw_version";"hw_version";"last_upd"
    action: notify.send_message
  - repeat:
      count: "{{ entity_ids_sorted | count }}"
      sequence:
        - variables:
            id: "{{ entity_ids_sorted[repeat.index-1] }}"
            obj: "{{ states(id) }}"
        - choose:
            - conditions:
                - condition: template
                  value_template: "{{ obj is not none }}"
              sequence:
                - variables:
                    name: "{{ obj.name | default('') }}"
                    dev: "{{ device_id(id) | default('') }}"
                    dev_name: "{{ device_name(id) or dev }}"
                    manufacturer: "{{ device_attr(id, 'manufacturer') | default('') }}"
                    model: "{{ device_attr(id, 'model') | default('')  }}"
                    model_id: "{{ device_attr(id, 'model_id') | default('') }}"
                    sw_version: "{{ device_attr(id, 'sw_version') | default('')  }}"
                    hw_version: "{{ device_attr(id, 'hw_version') | default('')  }}"
                    dom: "{{ id.split('.',1)[0] }}"
                    area: "{{ area_name(id) | default('') }}"
                    area_identifier: "{{ area_id(id) | default('') }}"
                    flo_id: "{{ floor_id(area_identifier) | default('') }}"
                    flo_name: "{{ floor_name(flo_id) | default('') }}"
                    aktiv: >-
                      {{ states(id) not in ['unavailable','unknown','none','']
                      }}
                    state: "{{ states(id) | default('') }}"
                    state_tr: "{{ state_translated(id) | default('') }}"
                    last_upd: |
                      {% set lu = states[id].last_updated %} {% if lu %}
                        {{ as_local(lu).strftime('%Y-%m-%d %H:%M:%S') }}
                      {% else %}
                        {{ "" }}
                      {% endif %}
                - data:
                    entity_id: notify.entity_dump
                    message: >-
                      "{{ id }}";"{{ name }}";"{{ dev_name }}";"{{ dom
                      }}";"{{area }}";"{{ flo_name }}";"{{ aktiv }}";"{{ state
                      }}";"{{state_tr }}";"{{ manufacturer }}";"{{ model }}";"{{
                      model_id }}";"{{ sw_version }}";"{{ hw_version }}";"{{
                      last_upd }}"
                  action: notify.send_message
  - action: shell_command.manage_entity_dump
    data:
      action: trim
  - action: shell_command.manage_entity_dump
    data:
      action: rename
  - action: shell_command.manage_entity_dump
    data:
      action: purge
alias: Entity Dump to File
description: ""

Cool, auch danke dafür. :slight_smile: Werde mal sehen, dass ich das Tool dann entsprechend erweitere, so dass auch deine csv eingelesen werden kann.

ggf passe ich gerne die Kopfzeile an.
Ansonsten ist das Format ja Standard-CSV,
(und entsteht halt automatisch und regelmäßig)

Ich muss mir das in Ruhe anschauen, aber aktuell verlangt mein Tool nach einer csv mit 8 Spalten. Durch deine Erweiterung gibt es nun mehr Spalten und das Tool sollte somit die Datei nicht mehr öffnen können. Daher meinte ich, „das Tool entsprechend zu erweitern“.

1 „Gefällt mir“

Hi, ich habe das mit der v_1.2 doch schon angepasst gehabt. Ab dieser Version können auch csv Dateien mit mehr Spalten geöffnet werden, also auch deine csv aus dem Script. Das Script habe ich jetzt auch mal bei mir in Betrieb genommen. :slight_smile:

Zu Ergänzung zum Script, wenn man es manueall anstoßen möchte, die angepasste Button-Card Version mit Hersteller, Modell, HW/SW Version.

type: custom:button-card
name: Entity Export as CSV2
tap_action:
  action: javascript
  javascript: |
    [[[
      function clean(value) {
        if (!value) return "";
        return String(value)
          .replace(/;/g, ",")
          .replace(/\r?\n|\r/g, " ");
      }

      async function generateCSV() {
        const hass = document.querySelector("home-assistant").hass;

        const areas = await hass.callWS({ type: "config/area_registry/list" });
        const devices = await hass.callWS({ type: "config/device_registry/list" });
        const entities = await hass.callWS({ type: "config/entity_registry/list" });

        const areaLookup = {};
        areas.forEach(a => (areaLookup[a.area_id] = a.name));

        let csv =
          "ENTITY ID;ENTITY NAME;DEVICE NAME;DEVICE ID;AREA;PLATFORM;STATE;FORMATTED STATE;" +
          "MANUFACTURER;MODEL;MODEL ID;SW VERSION;HW VERSION\n";

        Object.values(hass.states)
          .sort((a, b) => a.entity_id.localeCompare(b.entity_id))
          .forEach(stateObj => {
            const entReg = entities.find(e => e.entity_id === stateObj.entity_id);
            const device = devices.find(d => d.id === entReg?.device_id);

            const areaName =
              entReg?.area_id
                ? areaLookup[entReg.area_id] || ""
                : device?.area_id
                ? areaLookup[device.area_id] || ""
                : "";

            // Plattform
            const platform =
              entReg?.platform ||
              entReg?.integration ||
              stateObj.entity_id.split(".")[0];

            // Geräteattribute
            const manufacturer = device?.manufacturer || "";
            const model = device?.model || "";
            const model_id = device?.model_id || "";
            const sw_version = device?.sw_version || "";
            const hw_version = device?.hw_version || "";

            const row = [
              clean(stateObj.entity_id),
              clean(hass.formatEntityName(stateObj)),
              clean(device?.name || ""),
              clean(entReg?.device_id || ""),
              clean(areaName),
              clean(platform),
              clean(stateObj.state),
              clean(hass.formatEntityState(stateObj)),
              clean(manufacturer),
              clean(model),
              clean(model_id),
              clean(sw_version),
              clean(hw_version)
            ].join("; ");

            csv += row + "\n";
          });

        const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = "hass_entities.csv";
        a.click();
        URL.revokeObjectURL(url);
      }

      generateCSV();
    ]]]

Ich habe gestern Abend an der neuen Version 1.3 weitergebaut, zwecks der neuen Export Funktion im Energiedashboard von HA. Das Analyzer Tool unterscheidet jetzt ob eine Entitäten-csv oder eine energy-csv geladen wird. Bei Energie nimmt es dann die Daten aus der csv zur Grundlage und errechnet daraus die Liniendiagramme. Das geht mit import matplotlib.pyplot erstaunlich gut. Auf Grund der vielen Daten dauert es aber immer einen Moment bis er die Darstellung komplett geladen hat (teste immer mit Monats-csv oder Jahres-csv). Da wüsste ich aktuell nicht wie man das groß beschleunigen könnte.

So schaut es aus, man kann sich auf jeden Fall einen sehr guten Überblick verschaffen ohne extra Diagramme anlegen zu müssen.

Umschaltung auf Balkenansicht klappt auch, aber mit leichten Einschränkungen.

1 „Gefällt mir“