Heute gibt es einen 2-teiligen Beitrag der gleichzeitig auch einige (für mich) neue Techniken vorstellt.
Ich zeige diesmal nicht nur das Ergebnis sondern auch den Weg dorthin, mal sehen, wie das hier ankommt.
Im ersten Teil sehen wir, wie man sporadisch eintreffende Daten in einem Ringspeicher abgelegen kann,
im zweiten Teil geht es darum, wie man Daten über die Rest-API beziehen kann.
In beiden Teilen geht es aber um die grundsätzlich gleiche Aufgabe, einen Newsticker zu erstellen, nur halt mit unterschiedlichen Lösungsansätzen.
Also worum geht's jetzt wirklich?
Mein Dashboard zeigt ja schon sehr viel Info, nur der Badge-Bereich war bis jetzt noch leer.
Viele zeigen dort Datum, Uhrzeit, Innen-/Außen-Temp. usw, aber für all das hab ich schon andere Plätze gefunden. Meine Idee war, den Badge-Bereich für News-Meldungen zu nutzen, links die letzte und rechts davon ältere.
So sieht das ganze dann aus, wenn's fertig ist.
ORF-News als Badge Leiste.png
Ich hab bei der Erstellung des Codes viele Fehler gemacht und auch einige Rekursionen gedreht.
Da man aus Fehlern lernen kann, möchte ich hier den Werdegang meines Newstickers vorstellen.
Wer sich nur für das Ergebnis interessiert, an dem Werdegang aber kein Interesse hat, dem empfehle ich den Teil 1 komplett zu überspringen und gleich zu Teil 2 (im Post #2) weiterzugehen.
Teil 1: Newsticker über Feedreader Integration
Teil 2: Newsticker über Rest-API
Für meinen Newsticker gibt es einen passenden RSS-Feed vom ORF und um diese Daten abzuholen ist der Feedreader wie geschaffen - dachte ich.
Der Feedreader selbst war über das GUI auch sehr rasch eingerichtet, nur leider hat der erstellte Sensor gleich mehrere Nachteile.
event.news_orf_at zeigt als State den timestamp der letzten Abholung und unter anderem folgende Attribute: description, title, link, content.
Hier die Nachteile im Einzelnen:
Als Lösung 1 hab ich einen Template-Trigger geschrieben, und obwohl der Code gar nicht so lang ist, hab ich ganz schön lang daran gearbeitet.
Wenn ich von Anfang an gewusst hätte, dass ich das alles in die Tonne werfen werde, hätte ich mich nicht so bemüht, aber ich verbuche es einfach als Lernerfolg.
Die größte Schwierigkeit beim Testen war, dass der Trigger nur dann zündet, wenn der ORF einen neuen Beitrag einstellt. Am besten macht man also noch irgendwas anderes (nicht zu spannendes) parallel dazu. Als Workaround hab ich den Trigger alle 2 min zünden lassen, musste dann aber als weiteren Workaround abfangen, wenn der eigentliche Event des Trigger leer war.
Ich werde den Code dieses Mal etwas anders posten. Hier im Text eingebettet steht der Trigger mit seinen Test-Workarounds, im Anhang habe ich den Trigger von diesem Testcode bereinigt.
Der folgende Code steht bei mir in der Datei template_triggers.yaml, daher fehlt auch das erste Schlüsselwort template:
Zuerst mal nur der Kopf des Triggers, der event trigger holt die echten Events ab und übergibt sie in der Variable trigger.event. Der time_pattern trigger ist für meine Testcases, trigger.event ist in diesem Fall aber dann leer. Hier ist dieser Trigger bereits disabled.
So eine Test-Action verwende ich gerne, da kann ich mir ausgeben lassen, welche Daten genau gekommen sind. enabled muss natürlich auf true stehen, sonst wird das übersprungen. Bei Time-Pattern hab ich dann den Dummy-Titel "No Title", damit funktioniert der Code auch ohne echtes trigger.event
In diesem Sensor hebe ich mir jetzt die letzten 25 Meldungen auf, zufällig genauso viele wie der ORF auch im RSS-Feed belässt.
unique_id vergebe ich mittlerweile für fast alles, HA mag das einfach. Tipp für Studio-Code-Server: re-Maus & Generate UUID at Cursor
Im State schreibe ich den aktuellen Timestamp im gleichen Format, wie die Integration das auch macht.
Wer so wie ich mit den Zeitformaten immer noch durcheinander kommt, hier mein Schummelzettel dazu.
In current_items hole ich den aktuellen Ringpuffer mit 25 Einträgen.
In links hole ich nur die Links in dieser Liste, um zu prüfen, ob der neu gemeldete Eintrag wirklich neu ist.
Wie ich oben schon geschrieben hab, verändert der ORF manchmal auch ältere Meldungen im Nachhinein. Das fange ich damit ab, indem ich die Links vergleiche und nicht die title. Bei mir bleibt dann halt der ursprüngliche Meldungstext im Ringpuffer, da ich ihn nicht ersetze.
([new_entry] + current_items)[:25] hängt den neuen Eintrag vorne dran und schneidet die Liste nach dem 25. wieder ab.
Ich konnte in der Docu keine Info darüber finden, wie oft die Integration neue Daten holt, meiner Erfahrung nach war es ca. im Stundenintervall, dann aber gleich mehrere innerhalb von ms. Es gibt aber eine Möglichkeit das Intervall selbst in die Hand zu nehmen, und das habe ich auch gemacht.
Achtung: Ich würde niemandem raten, dieser Anleitung "Defining a custom polling interval" zu folgen, ohne meine Warnung vorher gelesen zu haben.
Das hat mich einiges an Nerven gekostet und ich möchte das anderen daher ersparen.
Meine Anleitung hier anhand von good old YAML-Code kann jedenfalls gefahrlos übernommen werden.
Der folgende Automation-Trigger steht bei mir jetzt in automations_manual.yaml, und es fehlt wie üblich das erste Schlüsselwort automation:
Die unique_id heisst hier nur id, muss man nicht verstehen. Der Rest sollte eigentlich selbsterklärend sein.
Nicht vergessen sollte man jedoch, in den "Systemoptionen für Feedreader" die "Abfrage von Änderungen" zu deaktivieren, denn sonst wird möglicherweise doppelt gezündet. Das ist der gefahrlose Teil der oberen Anleitung.
So, das war's - nein, noch nicht ganz. Wir haben jetzt zwar die Daten in einem Ringpuffer alle 10 min aktualisiert, aber die Anzeige dazu fehlt ja noch.
Auch das war für einen HTML-Neuling wie mich ganz schön aufwändig, aber diesen Teil konnte ich wenigstens für die Rest-Lösung wiederverwenden.
Ich hab 2 Karten gebaut, eine in Form einer Badge-Leiste, die hab ich oben schon gezeigt, und eine Listenansicht, diese hier.
ORF-News als chronologische Liste.png
Ich zeige hier nur den Screenshot, der Code ist auch attached, aber vorstellen werde ich den Code erst im 2. Teil, da die Card dort noch etwas hübscher ist.
Zusammenfassend kann ich sagen, dass ich mit dieser Lösung nicht vollständig zufrieden bin. Daher folgt jetzt auch noch eine bessere Lösung in Teil 2.
Ich zeige diesmal nicht nur das Ergebnis sondern auch den Weg dorthin, mal sehen, wie das hier ankommt.
Im ersten Teil sehen wir, wie man sporadisch eintreffende Daten in einem Ringspeicher abgelegen kann,
im zweiten Teil geht es darum, wie man Daten über die Rest-API beziehen kann.
In beiden Teilen geht es aber um die grundsätzlich gleiche Aufgabe, einen Newsticker zu erstellen, nur halt mit unterschiedlichen Lösungsansätzen.
Also worum geht's jetzt wirklich?
Mein Dashboard zeigt ja schon sehr viel Info, nur der Badge-Bereich war bis jetzt noch leer.
Viele zeigen dort Datum, Uhrzeit, Innen-/Außen-Temp. usw, aber für all das hab ich schon andere Plätze gefunden. Meine Idee war, den Badge-Bereich für News-Meldungen zu nutzen, links die letzte und rechts davon ältere.
So sieht das ganze dann aus, wenn's fertig ist.
ORF-News als Badge Leiste.png
Ich hab bei der Erstellung des Codes viele Fehler gemacht und auch einige Rekursionen gedreht.
Da man aus Fehlern lernen kann, möchte ich hier den Werdegang meines Newstickers vorstellen.
Wer sich nur für das Ergebnis interessiert, an dem Werdegang aber kein Interesse hat, dem empfehle ich den Teil 1 komplett zu überspringen und gleich zu Teil 2 (im Post #2) weiterzugehen.
Teil 1: Newsticker über Feedreader Integration
Teil 2: Newsticker über Rest-API
Für meinen Newsticker gibt es einen passenden RSS-Feed vom ORF und um diese Daten abzuholen ist der Feedreader wie geschaffen - dachte ich.
Der Feedreader selbst war über das GUI auch sehr rasch eingerichtet, nur leider hat der erstellte Sensor gleich mehrere Nachteile.
event.news_orf_at zeigt als State den timestamp der letzten Abholung und unter anderem folgende Attribute: description, title, link, content.
Hier die Nachteile im Einzelnen:
- Ich bekomme immer nur genau die letzte Meldung im Sensor, alle Meldungen davor sind für mich weg, obwohl im RSS-Feed eigentlich immer die letzten 25 Meldungen drinnen bleiben würden.
- Das Feld content wird vom ORF nicht genutzt, das Feld description ist bei 90% der Meldungen leer (gut, dafür kann die Integration jetzt nichts)
- Das Feld <dc:subject> wäre für mich interessant gewesen (Inhalt z.B.: Inland, Ausland, Chronik, ...), leider kann die Integration nur die 4 genannten Felder abholen.
- Die Integration erlaubt keine direkte Änderung des Abhol-Intervalls, dafür gibt es aber eine Lösung.
- Der ORF verändert gemeinerweise auch ältere Meldungen im Nachhinein, was mein Code von Teil 1 gar nicht mag, der Teil2-Code hat dann aber keine Probleme damit.
Als Lösung 1 hab ich einen Template-Trigger geschrieben, und obwohl der Code gar nicht so lang ist, hab ich ganz schön lang daran gearbeitet.
Wenn ich von Anfang an gewusst hätte, dass ich das alles in die Tonne werfen werde, hätte ich mich nicht so bemüht, aber ich verbuche es einfach als Lernerfolg.
Die größte Schwierigkeit beim Testen war, dass der Trigger nur dann zündet, wenn der ORF einen neuen Beitrag einstellt. Am besten macht man also noch irgendwas anderes (nicht zu spannendes) parallel dazu. Als Workaround hab ich den Trigger alle 2 min zünden lassen, musste dann aber als weiteren Workaround abfangen, wenn der eigentliche Event des Trigger leer war.
Ich werde den Code dieses Mal etwas anders posten. Hier im Text eingebettet steht der Trigger mit seinen Test-Workarounds, im Anhang habe ich den Trigger von diesem Testcode bereinigt.
Der folgende Code steht bei mir in der Datei template_triggers.yaml, daher fehlt auch das erste Schlüsselwort template:
HTML-Code:
- triggers:
- trigger: event
event_type: feedreader
event_data:
feed_url: "https://rss.orf.at/news.xml"
- trigger: time_pattern
enabled: false
minutes: "/2"
HTML-Code:
actions:
- action: persistent_notification.create
enabled: false
data:
title: "Feedreader Event"
message: >
{% set new_title = trigger.event.data.title if trigger.event is defined else "No Title" %}
{% set new_link = trigger.event.data.link if trigger.event is defined else "https://orf.at/stories/0/" %}
Feedreader hat eine neue ORF-News Meldung erhalten
{{- '\n' -}}
feed_url: {{ trigger.event.data.feed_url }}
{{- '\n' -}}
{{ new_title }}
{{- '\n' -}}
{{ new_link }}
{{- '\n' -}}
Zeitpunkt: {{ now().strftime('%Y-%m-%d %H:%M:%S') }}
HTML-Code:
sensor:
- name: "News ORF Items aus Feedreader"
unique_id: a89d28d7-43e2-4d92-95cb-a33cbf0605a5
state: "{{ now().isoformat(timespec='seconds') }}"
attributes:
items: >
{% set new_title = trigger.event.data.title if trigger.event is defined else "No Title" %}
{% set new_link = trigger.event.data.link if trigger.event is defined else "https://orf.at/stories/0/" %}
{% set current_items = state_attr('sensor.news_orf_items_aus_feedreader', 'items') or [] %}
{% set links = current_items | map(attribute='link') | list %}
{% if new_link not in links %}
{% set new_datetime_iso = now().isoformat(timespec='seconds') %}
{% set new_entry = {"title": new_title, "link": new_link, "zeitstempel": new_datetime_iso} %}
{{ ([new_entry] + current_items)[:25] }}
{% else %}
{{ current_items }}
{% endif %}
unique_id vergebe ich mittlerweile für fast alles, HA mag das einfach. Tipp für Studio-Code-Server: re-Maus & Generate UUID at Cursor
Im State schreibe ich den aktuellen Timestamp im gleichen Format, wie die Integration das auch macht.
Wer so wie ich mit den Zeitformaten immer noch durcheinander kommt, hier mein Schummelzettel dazu.
In current_items hole ich den aktuellen Ringpuffer mit 25 Einträgen.
In links hole ich nur die Links in dieser Liste, um zu prüfen, ob der neu gemeldete Eintrag wirklich neu ist.
Wie ich oben schon geschrieben hab, verändert der ORF manchmal auch ältere Meldungen im Nachhinein. Das fange ich damit ab, indem ich die Links vergleiche und nicht die title. Bei mir bleibt dann halt der ursprüngliche Meldungstext im Ringpuffer, da ich ihn nicht ersetze.
([new_entry] + current_items)[:25] hängt den neuen Eintrag vorne dran und schneidet die Liste nach dem 25. wieder ab.
Ich konnte in der Docu keine Info darüber finden, wie oft die Integration neue Daten holt, meiner Erfahrung nach war es ca. im Stundenintervall, dann aber gleich mehrere innerhalb von ms. Es gibt aber eine Möglichkeit das Intervall selbst in die Hand zu nehmen, und das habe ich auch gemacht.
Achtung: Ich würde niemandem raten, dieser Anleitung "Defining a custom polling interval" zu folgen, ohne meine Warnung vorher gelesen zu haben.
Das hat mich einiges an Nerven gekostet und ich möchte das anderen daher ersparen.
Meine Anleitung hier anhand von good old YAML-Code kann jedenfalls gefahrlos übernommen werden.
Der folgende Automation-Trigger steht bei mir jetzt in automations_manual.yaml, und es fehlt wie üblich das erste Schlüsselwort automation:
HTML-Code:
- alias: "Trigger News ORF Event"
id: b8b273d5-08ea-4a57-ade8-c7d4664fbe1a
description: Alle 10 min neue RSS-Feed Einträge abholen
triggers:
- trigger: time_pattern
minutes: /10
conditions: []
actions:
- action: homeassistant.update_entity
data:
entity_id:
- event.news_orf_at
Nicht vergessen sollte man jedoch, in den "Systemoptionen für Feedreader" die "Abfrage von Änderungen" zu deaktivieren, denn sonst wird möglicherweise doppelt gezündet. Das ist der gefahrlose Teil der oberen Anleitung.
So, das war's - nein, noch nicht ganz. Wir haben jetzt zwar die Daten in einem Ringpuffer alle 10 min aktualisiert, aber die Anzeige dazu fehlt ja noch.
Auch das war für einen HTML-Neuling wie mich ganz schön aufwändig, aber diesen Teil konnte ich wenigstens für die Rest-Lösung wiederverwenden.
Ich hab 2 Karten gebaut, eine in Form einer Badge-Leiste, die hab ich oben schon gezeigt, und eine Listenansicht, diese hier.
ORF-News als chronologische Liste.png
Ich zeige hier nur den Screenshot, der Code ist auch attached, aber vorstellen werde ich den Code erst im 2. Teil, da die Card dort noch etwas hübscher ist.
Zusammenfassend kann ich sagen, dass ich mit dieser Lösung nicht vollständig zufrieden bin. Daher folgt jetzt auch noch eine bessere Lösung in Teil 2.


Kommentar