{"id":5248,"date":"2023-10-21T15:56:49","date_gmt":"2023-10-21T13:56:49","guid":{"rendered":"https:\/\/www.sigalou-domotique.fr\/?p=5248"},"modified":"2026-01-04T21:26:27","modified_gmt":"2026-01-04T19:26:27","slug":"utiliser-un-script-python-pour-enregistrer-des-donnees-dans-ha","status":"publish","type":"post","link":"https:\/\/www.sigalou-domotique.fr\/de\/utiliser-un-script-python-pour-enregistrer-des-donnees-dans-ha","title":{"rendered":"Verwenden eines Python-Skripts zum Speichern von Daten in HA"},"content":{"rendered":"<p>Ich warne sofort davor, dass dieser Retex nur p\u00e4dagogischen Zwecken dient, ich schreibe ihn, um eine Methodik zu teilen, n\u00e4mlich dass ich diese Funktion seitdem anders umgesetzt habe, also habe ich diesen Prozess nicht in der Hand.<!--more--><\/p>\r\n<h3>Integration zum Ausf\u00fchren des Python-Skripts<\/h3>\r\n<p>Aus einem Grund, den ich nie verstanden habe, sind die in HA integrierten Python-Skriptfunktionen archi-mini, kein Import ist m\u00f6glich, daher muss ich eine Integration verwenden, die als <a href=\"https:\/\/github.com\/custom-components\/pyscript\" target=\"_blank\" rel=\"noopener\">Pyscript<\/a>.<\/p>\r\n<p><a href=\"https:\/\/hacs-pyscript.readthedocs.io\/en\/latest\/\" target=\"_blank\" rel=\"noopener\">Die Doc ist hier.<\/a><\/p>\r\n<p>Ich \u00fcbergebe die Details, um es zu installieren, es ist sehr einfach mit HACS und alles ist in der Dok.<\/p>\r\n<p>In configuration.yaml habe ich folgende Zeilen:<\/p>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\">pyscript: allow_all_imports: true hass_is_global: true<\/pre>\r\n<h3>Ich hole ein Token<\/h3>\r\n<p>Ich \u00f6ffne die Home Assistant-Benutzeroberfl\u00e4che.<\/p>\r\n<p>In der unteren linken Ecke klicke ich auf meinen Benutzernamen (oder das Profilsymbol).<\/p>\r\n<p>Ich klicke auf \"Profil\".<\/p>\r\n<p>Ich scrolle nach unten zum Abschnitt \u201eLangzeit-Token\u201c.\u00a0<\/p>\r\n<p>Ich klicke auf \"Token erstellen\", um ein neues Token zu generieren.<\/p>\r\n<p>Ich gebe meinem Token einen Namen, damit ich ihn leichter finden kann.<\/p>\r\n<p>Sobald das Token erstellt wurde, sehe ich seinen Inhalt. Ich kopiere den Wert des Tokens, d. h. den alphanumerischen Zeichensatz, und f\u00fcge ihn in meine Konfiguration ein (nachfolgender Absatz).<\/p>\r\n<h3>Erkl\u00e4rung der Plattform, die Python mit dem Sensor verbindet<\/h3>\r\n<p>In configuration.yaml f\u00fcge ich folgende Zeilen hinzu:<\/p>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\">rest_command: send_data_to_api: URL: 'http:\/\/homeAssistant.local:8123\/api\/states\/sensor.wallbox_charges' method: 'post' content_type: 'application\/json' headers: Autorisierung: 'Bearer TOKEN' # Ersetzen Sie TOKEN durch den Token cf vorherigen Absatz payload: '{{ data | tojson }}}'  <\/pre>\r\n<p>Dies ist die Eingangst\u00fcr, die \u00fcber das Python-Skript (unten) bereitgestellt wird und die Informationen an die sensor.wallbox_charges sendet.<\/p>\r\n<h3>Mein Python-Skript<\/h3>\r\n<p>Ich lege die Datei wallbox_charges.py in den Ordner \/config\/pyscript<\/p>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\">import datetime import pytz @service def wallbox_charges(lastdata=None, action=None, preis=\"123\", km=\"123\", dateDebut=\"01\/01\/2000 12:00:00\", Wert=\"123\"): Zeitzone_paris = pytz.timezone(\"Europa\/Paris\") jetzt_timestamp = int(datetime.datetime.now().timestamp()) jetzt_heure_paris = datetime.datetime.fromtimestamp(jetzt_timestamp, Zeitzone_paris) jetzt_formate = jetzt_heure_paris.strftime(\"%d\/%m\/%Y %H:%M:%S\") jetztMinus20min = datetime.datetime.now() - datetime.timedelta(minutes=20) jetztMinus20min_formatee = jetztMinus20min.strftime(\"%H:%M\") dateDebutRecue = datetime.datetime.strptime(dateDebut, '%d\/%m\/%Y %H:%M:%S').replace(tzinfo=Zeitzone_paris) debut_timestamp_formatee = dateDebutRecue.strftime(\"%d\/%m\/%Y %H:%M:%S\") debut_timestamp_formatee_OhneSekunden = DatumDebutRecue.strftime(\"%d\/%m\/%Y %H:%M\") # Verwandeln Sie Zeichenfolgen jetzt in datetime-Objekte_dt = datetime.datetime.strptime(jetzt_formatee, \"%d\/%m\/%Y %H:%M:%S\") debut_dt = datetime.datetime.strptime(debut_timestamp_formatee, \"%d\/%m\/%Y %H:%M:%S\") # Berechnen Sie die Differenz zwischen Objekten datetime ZeitDeCharge = jetzt_dt - debut_dt - datetime.timedelta(minutes=20) # Formatieren Sie die Dauer in Stunden, Minuten und Sekunden Stunden, Rest = divmod(timeDeCharge.seconds, 3600) Minuten, Sekunden = divmod(reste, 60) # Zeigen Sie die Dauer im HH:MM:SS-Format anDeCharge_formatee = f\"{Stunden:02}:{Minuten:02}\" # Schreiben Sie eine Informationsnachricht in das Tagebuch #log.info(action) if action == \"speichern\": wertaadd = [{ \"saved_at\": _timestamp, \"Anfang\": debut_timestamp_formatee_OhneSekunden, \"Ende\": jetztWeniger20min_formatee, \"Dauer\": ZeitDeCharge_formatee, \"Verbrauch\": Wert, \"km\": km, \"Kosten\": round(Wert * Preis, 2) }] if lastdata is not None: wertaadd = lastdata + wertaadd data = { \"state\": debut_timestamp_formatee_OhneSekunden, \"Attribute\": { \"updated_at\": jetzt_dt.strftime(\"%d\/%m\/%Y %H:%M:%S\"), \"Sessionscharge\": wertaadd } } if action == \"init\": data = { \"state\": \"on\", \"attributes\": { \"updated_at\": \u201e14\/10\/2023 16:42:39\u201c, \u201eSessionscharge\u201c: [ { \"Verbrauch\": 2.14 \"Kosten\": 0.43, \"Dauer\": \"00:27\", \"Anfang\": \u201e19\/09\/2023 20:36\u201c, \u201eEnde\u201c: \"21:03\", \"km\": 17, \"saved_at\": 1695150359 }, { \"Verbrauch\": 23.29, \"Kosten\": 4.66, \"Dauer\": \"04:19\", \"Anfang\": \u201e21\/09\/2023 21:06\u201c, \u201eEnde\u201c: \"01:25\", \"km\": 192, \"saved_at\": 1695323159 }, { \"Verbrauch\": 7.68, \"Kosten\": 1.54, \"Dauer\": \"01:23\", \"Anfang\": \u201e22\/09\/2023 08:45\u201c, \u201eEnde\u201c: \"10:08\", \"km\": 63, \"saved_at\": 1695409559 }, { \"Verbrauch\": 23.80, \"Kosten\": 4.76, \"Dauer\": \"04:26\", \"Anfang\": \u201e23\/09\/2023 16:57\u201c, \u201eEnde\u201c: \"21:23\", \"km\": 196, \"saved_at\": 1695495959 } ] } } # Rufen Sie den REST-Dienst an, um die Daten zu senden _data = { \"token\": \"xxxxxx\", # Ersetzen durch das \"Data\"-Token: data } if action == \"speichern\" or action == \"init\": # Rufen Sie den REST-Dienst asynchron an await hass.services.async_call('rest_command', 'send_data_to_api', service_data) # Schreiben Sie eine Fehlermeldung in das Protokoll #log.error(\"End script\")<\/pre>\r\n<h3>Zwei Automatisierungen hinzuf\u00fcgen<\/h3>\r\n<p>Eine zum Initialisieren des Sensors, die andere zum Hinzuf\u00fcgen von Daten<\/p>\r\n<h4>Initialisieren von Daten<\/h4>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\">alias: Initialisiert Ladesitzungen Beschreibung: \"\" Trigger: [] Bedingung: [] Ma\u00dfnahme: - Dienststelle: pyscript.wallbox_charges data: Ma\u00dfnahme: Init Mode: Single\r\n<\/pre>\r\n<h4>Daten speichern<\/h4>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\">alias: Speichert eine Ladesitzung Beschreibung: &gt;- Diese Automatisierung wird ausgel\u00f6st, wenn der Sensor den Wert seit 20 Minuten nicht ge\u00e4ndert hat und sich nicht bei 0 Trigger befindet: - platform: state entity_id: - sensor.wallbox_portal_added_range for: hours: 0 Minuten: 20 Zweite: 0 enabled: true condition: - Bedingung: numeric_state entity_id: sensor.wallbox_portal_added_energy above: 0 - Bedingung: not conditions: - Bedingung: state entity_id: sensor.wallbox_charges state: &gt;- {{ as_timestamp(states('sensor.wallbox_portal_added_range_min')) | int | timestamp_custom('%d\/%m\/%Y %H:%M:%S', true)} enabled: False Action: - Dienststelle: pyscript.wallbox_charges data: Ma\u00dfnahme: Wert speichern: \"{{states('sensor.wallbox_portal_added_energy')}}\" Preis: \"{{states('sensor.wallbox_portal_energy_price')}}\" km: \"{{states('sensor.wallbox_portal_added_range')}}\" lastdata: \"{{state_attr('sensor.wallbox_charges', 'sessionscharge')}}\" DatumBeginn: &gt;- {{ as_timestamp(states('sensor.wallbox_portal_added_range_min')) | int | timestamp_custom('%d\/%m\/%Y %H:%M:%S', true)} - Service: variable.update_sensor data: replace_attributes: false value: &gt;- {{ as_timestamp(states('sensor.wallbox_portal_added_range_min')) | int | timestamp_custom('%d\/%m\/%Y %H:%M:%S', true)}} target: entity_id: sensor.wallbox_charges enabled: False Mode: Single<\/pre>\r\n<p>Um den minimalen Lastwert zu erhalten, verwende ich statistic, um den min-Wert zu erhalten.<\/p>\r\n<p>Dieser Sensor wird in sensors.yaml deklariert<\/p>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\">- platform: statistics name: \"Wallbox Portal Added Range Min\" entity_id: sensor.wallbox_portal_added_range state_characteristic: datetime_value_min max_age: hours: 10  \r\n   <\/pre>\r\n<h3>Ergebnis der Informationsspeicherung<\/h3>\r\n<p><a href=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-5258\" src=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge.png\" alt=\"\" width=\"729\" height=\"546\" srcset=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge.png 729w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge-600x449.png 600w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge-300x225.png 300w\" sizes=\"auto, (max-width: 729px) 100vw, 729px\" \/><\/a><\/p>\r\n<h3>Anzeigekarte f\u00fcr alle Sitzungen<\/h3>\r\n<p><a href=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-5261\" src=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge2.png\" alt=\"\" width=\"388\" height=\"375\" srcset=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge2.png 388w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge2-300x290.png 300w\" sizes=\"auto, (max-width: 388px) 100vw, 388px\" \/><\/a><\/p>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\">&lt;div&gt;Ladesitzungen&lt;\/div&gt; \r\nLetzte Aktualisierung: {{ state_attr(&#039;sensor.wallbox_charges&#039;,&#039;updated_at&#039;)}} &lt;br&gt;&lt;br&gt;\r\n{% set items = state_attr(&#039;sensor.wallbox_charges&#039;, &#039;sessionscharge&#039;) %}\r\n&lt;table width=&#039;100%&#039;&gt;\r\n&lt;tbody&gt;\r\n{% for i in range(0, items | count, 1) %}\r\n&lt;tr&gt;\r\n&lt;td&gt;{{ items[i].Anfang }} bis {{ items[i].fin }} ({{ items[i].Dauer }})&lt;\/td&gt;\r\n&lt;td&gt;{{ items[i].Verbrauch }} kWh&lt;\/td&gt;\r\n&lt;td&gt;+{{ items[i].km }} km&lt;\/td&gt;\r\n&lt;td&gt;{{ items[i].cost }} &euro;&lt;\/td&gt;\r\n&lt;\/tr&gt;\r\n\r\n{% endfor %}\r\n&lt;\/tbody&gt;\r\n&lt;\/table&gt;<\/pre>\r\n<p>Plakatkarte mit Summen pro Jahr, Monat, Woche<\/p>\r\n<p><a href=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge3.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-5262\" src=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge3.png\" alt=\"\" width=\"383\" height=\"415\" srcset=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge3.png 383w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2023\/10\/charge3-277x300.png 277w\" sizes=\"auto, (max-width: 383px) 100vw, 383px\" \/><\/a><\/p>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\">Typ: Markdown Content: &amp;gt;-\r\n  &lt;div&gt;&lt;h1&gt;Ladesitzungen&lt;\/div&gt;  {%- set default_language = &#039;de&#039; %} Letzte Aktualisierung: {{ state_attr(&#039;sensor.wallbox_charges&#039;,&#039;updated_at&#039;)}} &lt;br&gt;&lt;br&gt;\r\n\r\n\r\n  {% set items = state_attr(&#039;sensor.wallbox_charges&#039;, &#039;sessionscharge&#039;) %} {% set sieben Tage = now() - timedelta(days=7) %} {% set power_Woche = namespace(value=0) %} {% set cost_woche = namespace(value=0) %} {% set einen Monat = now() - timedelta(days=30) %} {% set power_Monat = namespace(value=0) %} {% set cot_mois = namespace(value=0) %} {% set uneannee = now() - timedelta(days=365) %} {% set power_annee = namespace(value=0) %} {% set cout_annee = namespace(value=0) %} {% for i in range(0, items | count, 1) %} {% if items[i].saved_at | int &amp;gt;= as_timestamp(uneannee) %} {% set power_annee.value = power_annee.value + items[i].Verbrauch %} {% set cot_annee.value = cot_annee.value + items[i].kosten %} {% if items[i].saved_at | int &amp;gt;= as_timestamp(ein Monat) %} {% set power_mois.value = power_mois.value + items[i].Verbrauch %} {% set cot_mois.value = cot_mois.value + items[i].kosten %} {% if items[i].saved_at | int &amp;gt;= as_timestamp(sieben Tage) %} {% set power_woche.value = power_woche.value + items[i].Verbrauch %} {% set cout_swoche.value = cout_swoche.value + items[i].kosten %} {% endif %} {% endif %} {% endif %} {% endfor %}\r\n\r\n  &lt;\/ha-alert&gt; &lt;ha-alert alert-type=&quot;info&quot; title=&quot;Letzter Monat: {{ power_mois.value | int }} kWh - {{ cot_mois.value | float | round(2) }} &euro;&quot;&gt;&lt;\/ha-alert&gt; &lt;ha-alert alert-type=&quot;info&quot; title=&quot;Letztes Jahr: {{ power_annee.value | int }} kWh - {{ cot_annee.value | float | round(2) }} &euro;&quot;&gt;&lt;\/ha-alert&gt;\r\n\r\n\r\n  &lt;br&gt; \r\n\r\n\r\n  {% set items = state_attr(&#039;sensor.wallbox_charges&#039;, &#039;sessionscharge&#039;) %} {% set sieben Tage = now() - timedelta(days=7) %}\r\n\r\n  &lt;table width=&#039;100%&#039;&gt; &lt;tbody&gt;  {% for i in range(0, items | count, 1) %} {% if items[i].saved_at | int &amp;gt;= as_timestamp(sieben Tage) %} {% set datetime_obj = strptime(items[i].Anfang, &#039;%d\/%m\/%Y %H:%M&#039;) %}\r\n\r\n  &lt;tr&gt; &lt;td&gt;&lt;h5&gt;{{items[i].Anfang }} bis {{ items[i].fin }} ({{ items[i].Dauer }})&lt;\/td&gt; &lt;td&gt;{{ items[i].Verbrauch }} kWh&lt;\/td&gt; &lt;td&gt;+{{ items[i].km }} km&lt;\/td&gt; &lt;td&gt;{{ items[i].cost }} &euro;&lt;\/td&gt; &lt;\/tr&gt; {% endif %} {% endfor %} &lt;\/tbody&gt; &lt;\/table&gt;\r\n    &lt;ha-alert alert-type=&quot;success&quot; title=&quot;Letzte Woche: {{ power_semaine.value | int}} kWh - {{ cot_semaine.value | float | round(2) }}&euro;&quot;&gt;    \r\nStil: .: | ha-card { margin: 0px 0px 0px 0px; Box-Shadow: none; } ha-markdown: $: | h5 { font-size: 15px!wichtig; font-weight: normal! wichtig; Padding: 0px 0px 0px 8px!wichtig; Border-Left: 3px solid #429f46; }\r\n<\/pre>\r\n<p>&nbsp;<\/p>","protected":false},"excerpt":{"rendered":"<p>Ich warne sofort davor, dass dieser Retex nur p\u00e4dagogischen Zwecken dient, ich schreibe ihn, um eine Methodik zu teilen, n\u00e4mlich dass ich diese Funktion seitdem anders umgesetzt habe, also habe ich diesen Prozess nicht in der Hand.<\/p>","protected":false},"author":1,"featured_media":5257,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[14,53,166],"tags":[81],"class_list":["post-5248","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-domotique","category-home-assistant","category-retex","tag-developpement"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/posts\/5248","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/comments?post=5248"}],"version-history":[{"count":0,"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/posts\/5248\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/media\/5257"}],"wp:attachment":[{"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/media?parent=5248"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/categories?post=5248"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/de\/wp-json\/wp\/v2\/tags?post=5248"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}