Home-Assistant: (fast) werbefreies Internetradio

Wir erstellen uns ein Internet-Radio mit einer Pausen-Funktion zu festen Uhrzeiten. Damit können wir bei einigen Sendern die nervige Werbung ausblenden.

Außerdem: warum der Home-Assistant-Radio-Browser nichts taugt. Und eine USB-Soundbar besser ist als ein Sonos- oder Symfonisk-Lautsprecher.

Grund

Wer mag ihn nicht, den nervigen Herrn Seitenbacher der uns seit Jahren mit unendlichen Wiederholungen traktiert?

Oder die unvorteilhaften Stimmen von LILD und Kaufland, deren einzige Qualifikation wahrscheinlich die Aussprache ist … und das sie maximal nervend sind, um Aufmerksamkeitsheischend zu unseren Gehirnzellen vorzudringen?

Wer mag sie nicht …. ICH !!!

Was man braucht

Man muss ein Sound-Device haben, welches als “media_player.irgendwas” erreichbar ist.

Zwei Beispiele von vielen:

Symfonisk- oder Sonos-Lautsprecher

Diese werden beide durch die Sonos-Integration unterstützt. Allerdings kann man diese nicht empfehlen:

  • die Sonos-App für Android funktioniert seit Monaten nicht und hat deshalb unterirdische Bewertungen
  • der Symfonisk/Sonos-Lautsprecher reagiert sehr langsam auf Abspielkommandos. Stoppen geht hingegen recht schnell.
  • aber er spielt auch langsam ab. Zwischen der USB/VLC basierter Soundbar und dem Symfonisk-Lautsprecher gibt es eine mächtige Verzögerung. Über USB kommt der Sound fast eine Sekunde schneller als via Symfonisk/Sonos.

USB-Lautsprecher

Ich hatte aber noch eine “Creative Stage V2 Soundbar”. Diese hat u.A. USB. Und ich habe sie darüber an meinen Intel NUC angeschlossen, auf dem Home-Assistant innerhalb von Proxmox läuft. Das ganze sieht grob so aus:

Was auch immer man macht, man braucht für alles folgende ein funktionierendes “media_player.*” Device!

Radio Browser - lieblos!

Es gibt den integrierten Radio Browser nutzen. Aber dessen Datenbasis ist… unterirdisch. Wenn man links auf “Media” und dann auf “Radio Browser” klickt, sieht man die Landesflaggen.

Also runter zu “Germany”. Huch, da gibt’s ja zwei? Ich dachte, das wäre Geschichte. Aber wo sind bei der zweiten Flagge dann Hammer und Sichel?

Klickt man auf eine, dann auf den Zurückbutton des Radio-Browser (nicht von Firefox/Chromium etc …) dann landet man … wieder an Anfang der Länderliste. Die Position wird sich nicht gemerkt, ich muss wieder runterscrollen.

Wenn ich dann auf eine der deutschen Flagge klicke … welche ist egal .. dann kommen Radiosender. Doch sie erscheinen irgendwie unsortiert.

Bis man merkt, das auch da Aufmerksamkeitsheischende Leutchen getrickst haben. Ein " 90s" (zwei Leerzeichen) wird halt, wenn man stur nach ASCII-Alphabet sortiert, vor “HR3” angezeigt. Wäre ich der Plugin-Autor, würde ich diese Tricks-Namen einfach herausfiltern.

Apropos “HR3”… man suche nun mal diesen Sender. Fast unmöglich, weil es keine Suchfunktion gibt. Also ist Suchen per Scrollen und Lesen angesagt.

Page-Up und Page-Down gehen natürlich auch nicht.

Nehmen wir mal an, wir sind glücklich bei HR3 gelandet. Klickt man nun auf den Zurück-Button des Radio-Browsers, sucht erneut die deutsche Flagge, und klickt dann wieder darauf … ist man wieder am Anfang. Und darf wieder suchen.

Und wenn ich nun einen Sender per Automation hören will … hier findet man keine Information, wie das denn gehen könnte. Wie ich also z.B. den HR3-Button automatisiert drücken könnte.

Am besten vergessen wir den eingebauten “Radio Browser” ganz schnell. Das ist insgesamt ein grausames UI.

Radio-Browser, diesmal per Web

Aber woher holt sich Home-Assistant überhaupt die Sender? Von https://www.radio-browser.info/ — man findet da zwar auch die getricksten Sendernamen. Aber wenigstens gibt es eine Suchfunktion.

Also oben rechts “hr3” eingeben und schon hat man die Streams:

Wenn man nun auf einen der Einträge klickt, sieht in der Adresszeile von Firefox/Chromium URLs dieser Art:

https://www.radio-browser.info/history/c9f56165-ab64-4af8-ba90-dfb0aa735218

Und dieses “c9f56165-ab64-4af8-ba90-dfb0aa735218” (eine sog. UUID) ist nun das, was wir gleich in Home-Assistant brauchen werden.

Wir nutzen also https://www.radio-browser.info, um die UUIDs der Sender zu erfahren.

Internetradio

Service-Aufruf

Was macht man nun mit der UUID? Zunächst einen Test! In den Developer-Tools gibt man das ein:

bzw. dieses YAML:

action: media_player.play_media
target:
  entity_id: media_player.soundbar_wz
data:
  media_content_id: media-source://radio_browser/c9f56165-ab64-4af8-ba90-dfb0aa735218
  media_content_type: music

Wir sehen hier “media-source://radio_browser/” gefolgt von unser eben herausgefunden UUID.

Wenn wir das nun als Script (statt in den Developer Tools) anlegen, können wir es in Automationen, GUI-Elementen nutzen.

… oder mit Hardware-Schaltern steuern.

Helferlein

Wir erstellen uns zwei String-Helfer. Das geht so:

  • Settings
  • Devices & services
  • Helpers
  • Create helper
  • Text
  • Name: “Radio Sender”
  • Icon: nach belieben

Und dann noch einen Helfer dieser Art für “Radio UUID”:

Script: nächster Sender

Diese Helfer werden in den folgenden Skripten genutzt. Beispielsweise wie hier für eine Funktion, um zum nächsten Sender zu springen:

script:
  radio_next:
    alias: "Radio Next"
    sequence:
      - choose:
          - conditions:
              - condition: template
                value_template: "{{ states('input_text.radio_sender') == '' }}"
            sequence:
              - action: script.radio_hr1
          - conditions:
              - condition: template
                value_template: "{{ states('input_text.radio_sender') == 'HR1' }}"
            sequence:
              - action: script.radio_hr3
          - conditions:
              - condition: template
                value_template: "{{ states('input_text.radio_sender') == 'HR3' }}"
            sequence:
              - action: script.radio_hrinfo
          - conditions:
              - condition: template
                value_template: "{{ states('input_text.radio_sender') == 'hr INFO' }}"
            sequence:
              - action: script.radio_dlf
          - conditions:
              - condition: template
                value_template: "{{ states('input_text.radio_sender') == 'DLF' }}"
            sequence:
              - action: script.radio_dlfnova
          - conditions:
              - condition: template
                value_template: "{{ states('input_text.radio_sender') == 'DLF Nova' }}"
            sequence:
              - action: script.radio_hr1

(Das YAML startet mit “script:” weil ich Home-Assistant’s Packages verwende. Ich habe alle Media-Script in /config/packages/media.yaml gesammelt. Wer das YAML direkt in den Editor reinhaut, muss es entsprechend anpassen.)

Im Prinzip ist das, analog zu C, ein switch/case Statement. Und die Bedingungen wird über ein Template festgelegt.

Script: vorheriger Sender

Das Script für “vorheriger Sender” ist analog wie “nächster Sender” aufgebaut.

Scripte: Sender starten

Dieses Script setzt die beiden Helfer auf Text und UUID. Es ruft nicht direkt media_player.play_media auf. Denn ich brauche die UUID für eine Pause/Continue-Funktion. Und wenn ich sowieso eine Continue-Funktion erstellen werden, kann ich die auch gleich hier aufrufen:

script:
  radio_hr1:
    alias: "Radio HR1"
    sequence:
      - action: input_text.set_value
        target:
          entity_id: input_text.radio_sender
        data:
          value: "HR1"
      - action: input_text.set_value
        target:
          entity_id: input_text.radio_uuid
        data:
          value: "600c73d1-2ea5-45ee-b3c1-c108674343e6"
      - action: script.radio_continue

Dieses Script erstelle ich dann abgewandelt für alle Sender die ich per Button starten will: HR1, HR3, hr-info, DLF, DLF Nova.

Script: Weitermachen

Hier ist das “script.radio_continue”, das oben aufgerufe wurde:

script:
  radio_continue:
    alias: "Radio Continue"
    sequence:
      - action: media_player.play_media
        target:
          entity_id: media_player.soundbar_wz
        data:
          media_content_type: music
          media_content_id: "media-source://radio_browser/{{ states('input_text.radio_uuid') }}"

Script: Radio Pausieren

Und da “script.radio_continue” ja mit einer Pause-Funktion zusammenspielen soll, brauchen wir die auch noch:

radio_pause:
  alias: "Radio Pause"
  sequence:
    - action: media_player.media_stop
      target:
        entity_id: media_player.soundbar_wz

Script: Radio aus

Wenn wir hingegen richtig asusschalten wollen, dann Stoppen wir den Media-Player und setzen auch die Helfer zurück.

Andere Script können dann am leeren UUID-Feld erkennen, das das Radio in wirklich aus ist (es soll also z.B. zur vollen Stunde wieder angemacht werden, etwa nach einer Werbepause).

script:
  radio_off:
    alias: "Radio Off"
    sequence:
      - action: media_player.media_stop
        target:
          entity_id: media_player.soundbar_wz
      - action: input_text.set_value
        target:
          entity_id: input_text.radio_sender
        data:
          value: ""
      - action: input_text.set_value
        target:
          entity_id: input_text.radio_uuid
        data:
          value: ""

Script: Radio Start/Stop

Dieses Script habe ich auf eine Hardware-Taste (IKEA Styrbar) gelegt:

script:
  radio_startstop:
    alias: "Radio Start/Stop"
    sequence:
      - if:
          - condition: state
            entity_id: input_text.radio_sender
            state: ""
        then:
          - action: script.radio_hr1
        else:
          - if:
              - condition: state
                entity_id: media_player.soundbar_wz
                state: "playing"
            then:
              - action: script.radio_pause
            else:
              - if:
                  - condition: state
                    entity_id: media_player.soundbar_wz
                    state: "idle"
                then:
                  - action: script.radio_continue
  • läuft kein Sender: wird HR1 gestartet
  • läuft ein Sender: dann rufe ich das Pausen-Script auf
  • ansonsten wird “Radio Continue” aufgerufen

Bedienung

GUI

Ich habe mir ein Dashboard angelegt, das mir einfachen Zugriff auf die Sender ermöglicht:

Taster

Aber meistens nehme ich den IKEA Styrbar — mit Switch Manager folgermaßen beschaltet:

  • Oben: Licht
  • Links: vorheriger Sender
  • Rechts: nächster Sender
  • Unten: Pause bzw. Weiter, bei langen Drücken: Stop

Dieser Schalter wandert von meinem PC-Schreibtisch zum Wohnzimmer-Couchtisch zum Home-Office, wo er gerade gebraucht wird.

Werbepause

Bisher haben wir nur ein Internet-Radio. Aber wie machen wir das nun mit der Werbung? Im Prinzip nutzen wir aus, das Werbung in vielen Sendern zur festen Uhrzeit kommt. Wir schalten dann einfach das Radio auf “Pause”:

automation:
  - alias: "Radio wg. Werbung aus (HR1)"
    triggers:
      - trigger: time_pattern
        minutes: "27"
      - trigger: time_pattern
        minutes: "57"
    conditions:
      # - condition: state
      #   entity_id: binary_sensor.feiertag
      #   state: "off"
      - condition: time
        after: "6:00:00"
        before: "20:00:00"
      - condition: time
        weekday:
          - mon
          - tue
          - wed
          - thu
          - fri
          - sat
      - condition: state
        entity_id: input_text.radio_sender
        state: "HR1"
    actions:
      - action: script.radio_pause
    mode: restart

(Auch hier steht wieder ein “automation:” davor, weil dieses YAML gemeinsam mit den Scripten von oben in einer Home-Assistant-Packages-Datei steht. Wer das in sein GUI rainhauen will, passt es entsprechend an.)

Wir pausieren also zwischen 6 und 20 Uhr das Radio jeweils 3 Minuten vor der vollen Stunde und halben Stunde.

Noch auskommentiert sieht man, wie man diesen “Werbeblocker” auch an Feiertagen festmachen könnte.

Wenn wir pausieren, dann wollen wir aber auch irgendwann wieder fortfahren:

automation:
  - alias: "Radio nach Werbung an (HR1)"
    triggers:
      - trigger: time_pattern
        minutes: "0"
      - trigger: time_pattern
        minutes: "32"
    conditions:
      # - condition: state
      #   entity_id: binary_sensor.feiertag
      #   state: "off"
      - condition: state
        entity_id: input_text.radio_sender
        state: "HR1"
    actions:
        action: script.radio_continue
    mode: restart

Für HR3 ist das ähnlich, nur senden sie die Werbung zur viertel- und dreiviertel Stunde.

hr-info sendet so wenig Werbung, das ich da nichts implementiert habe. DLF und DLF Nova sind sowieso vollkommen Werbefrei.

Verbesserungspotential

Besser wäre es vermutlich, wenn man die Jingles vor der Werbung erkennt. Da wir potentielle viele Strings erkennen sollten, wäre vielleicht eine Robin-Karp-Suche praktisch. Zu jedem Suchmuster könnte man eine Pausen-Zeit eintragen.

Dieser Suche nach Werbung oder Werbe-Jingles könnte Rundfunk über Stream empfangen (wie oben). Oder man könnte sie in einen Software-DAB+-Empfänger mit Hilfe eine günstigen RTL-SDR-Stick einbauen. Ein Beispiele wäre DABlin oder Welle.io.