Komplettes Radio-Steuerungs-Interface

Weiter unten findet Ihr die Anpassungsanleitung.

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML

  - type: masonry
    path: radio
    cards:
      - type: custom:button-card
        entity: media_player.kuche_2
        show_name: false
        show_state: false
        show_icon: false
        tap_action:
          action: none
        styles:
          card:
            - height: 400px
            - background: rgba(20, 20, 25, 0.75)
            - backdrop-filter: blur(10px)
            - border: 1px solid rgba(255, 255, 255, 0.08)
            - border-radius: 25px
            - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3)
            - padding: 30px
          custom_fields:
            logo:
              - position: absolute
              - top: 50px
              - left: 50%
              - transform: translateX(-50%)
              - width: 220px
              - height: 220px
            title:
              - position: absolute
              - bottom: 80px
              - left: 30px
              - right: 30px
              - text-align: center
              - font-size: 24px
              - font-weight: 400
              - color: white
              - letter-spacing: 0.5px
            artist:
              - position: absolute
              - bottom: 50px
              - left: 30px
              - right: 30px
              - text-align: center
              - font-size: 18px
              - font-weight: 300
              - color: rgba(255, 255, 255, 0.7)
        custom_fields:
          logo: |
            [[[
              const albumName = entity.attributes.media_album_name || '';
              const entityPicture = entity.attributes.entity_picture || '';
              const mediaContentId = entity.attributes.media_content_id || '';
              
              // Prüfe ob es Spotify ist
              if (mediaContentId.includes('spotify:')) {
                return `<img src="${entityPicture}">`;
              }
              
              // Sonst Radio-Logos
              let logoSrc = '/local/radio-logos/flashbackfm.png';
              
              if (albumName.includes('Flashback')) {
                logoSrc = '/local/radio-logos/flashbackfm.png';
              } else if (albumName.includes('Munot')) {
                logoSrc = '/local/radio-logos/radiomunot.png';
              } else if (albumName.includes('Radio 24')) {
                logoSrc = '/local/radio-logos/radio24.png';
              }
              
              return `<img src="${logoSrc}">`;
            ]]]
          title: |
            [[[
              return entity.attributes.media_title || 'Kein Titel';
            ]]]
          artist: |
            [[[
              return entity.attributes.media_artist || '';
            ]]]
      - type: custom:bubble-card
        card_type: separator
        card_layout: normal
      - type: vertical-stack
        cards:
          - square: false
            type: grid
            columns: 3
            cards:
              - show_name: false
                show_icon: true
                type: button
                icon: mdi:volume-minus
                tap_action:
                  action: call-service
                  service: media_player.volume_down
                  target:
                    entity_id: media_player.kuche_2
                card_mod:
                  style: |
                    ha-card {
                      height: 130px;
                      width: 130px;
                      background: rgba(20,20,25,0.75);
                      backdrop-filter: blur(12px);
                      border-radius: 50%;
                      border: 1px solid rgba(255,255,255,0.08);
                      box-shadow: 0 8px 28px rgba(0,0,0,0.35);
                      color: white;
                      margin: auto;
                    }
                    ha-card:active {
                      transform: scale(0.95);
                    }
                color: white
              - show_name: false
                show_icon: true
                type: button
                icon: mdi:play-pause
                tap_action:
                  action: call-service
                  service: media_player.media_play_pause
                  target:
                    entity_id: media_player.kuche_2
                color: white
                card_mod:
                  style: |
                    ha-card {
                      height: 130px;
                      width: 130x;
                      background: rgba(20,20,25,0.75);
                      backdrop-filter: blur(12px);
                      border-radius: 50%;
                      border: 1px solid rgba(255,255,255,0.08);
                      box-shadow: 0 8px 28px rgba(0,0,0,0.35);
                      color: white;
                      margin: auto;
                    }
                    ha-card:active {
                      transform: scale(0.95);
                    }
              - show_name: false
                show_icon: true
                type: button
                icon: mdi:volume-plus
                tap_action:
                  action: call-service
                  service: media_player.volume_up
                  target:
                    entity_id: media_player.kuche_2
                card_mod:
                  style: |
                    ha-card {
                      height: 130px;
                      width: 130px;
                      background: rgba(20,20,25,0.75);
                      backdrop-filter: blur(12px);
                      border-radius: 50%;
                      border: 1px solid rgba(255,255,255,0.08);
                      box-shadow: 0 8px 28px rgba(0,0,0,0.35);
                      color: white;
                      margin: auto;
                    }
                    ha-card:active {
                      transform: scale(0.95);
                    }
                color: white
          - square: true
            type: grid
            columns: 3
            cards:
              - show_name: false
                show_icon: false
                type: button
                tap_action:
                  action: call-service
                  service: media_player.play_media
                  target:
                    entity_id: media_player.kuche_2
                  data:
                    media_content_type: url
                    media_content_id: tunein--kqdEaHjB://radio/s303414
                icon: ''
                card_mod:
                  style: |
                    ha-card {
                      height: 300px;
                      margin-top: 4px;
                      margin-bottom: 4px;
                      background: rgba(20,20,25,0.75);
                      backdrop-filter: blur(16px);
                      border-radius: 26px;
                      border: 1px solid rgba(255,255,255,0.08);
                      box-shadow: 0 14px 45px rgba(0,0,0,0.4);
                      position: relative;
                      overflow: hidden;
                    }
                    ha-card::before {
                      content: "";
                      position: absolute;
                      inset: 14%;
                      background: url('/local/radio-logos/flashbackfm.png') center / contain no-repeat;
                    }
              - type: button
                show_name: false
                show_icon: false
                tap_action:
                  action: call-service
                  service: media_player.play_media
                  target:
                    entity_id: media_player.kuche_2
                  data:
                    media_content_type: url
                    media_content_id: tunein--kqdEaHjB://radio/s15496
                card_mod:
                  style: |
                    ha-card {
                      height: 300px;
                      margin-top: 4px;
                      margin-bottom: 4px;
                      background: rgba(20,20,25,0.75);
                      backdrop-filter: blur(16px);
                      border-radius: 26px;
                      border: 1px solid rgba(255,255,255,0.08);
                      box-shadow: 0 14px 45px rgba(0,0,0,0.4);
                      position: relative;
                      overflow: hidden;
                    }
                    ha-card::before {
                      content: "";
                      position: absolute;
                      inset: 14%;
                      background: url('/local/radio-logos/radiomunot.png') center / contain no-repeat;
                    }
              - type: button
                show_name: false
                show_icon: false
                tap_action:
                  action: call-service
                  service: media_player.play_media
                  target:
                    entity_id: media_player.kuche_2
                  data:
                    media_content_type: url
                    media_content_id: tunein--kqdEaHjB://radio/s2773
                card_mod:
                  style: |
                    ha-card {
                      height: 300px;
                      margin-top: 4px;
                      margin-bottom: 4px;
                      background: none;
                      backdrop-filter: blur(16px);
                      border-radius: 26px;
                      border: 0px solid rgba(255,255,255,0.08);
                      box-shadow: 0 14px 45px rgba(0,0,0,0.4);
                      position: relative;
                      overflow: hidden;
                    }
                    ha-card::before {
                      content: "";
                      position: absolute;
                      inset: 14%;
                      background: url('/local/radio-logos/radio24.png') center / contain no-repeat;
                    }
        grid_options:
          columns: 12
          rows: 5
    title: Radio
 

1. NOW PLAYING CARD (Große obere Karte)

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
- type: custom:button-card
  entity: media_player.kuche_2        # ← Dein Media Player
  show_name: false
  show_state: false
  show_icon: false
  tap_action:
    action: none                      # ← Kein Klick-Event

Was macht sie?

Zeigt das aktuell laufende Lied/Radio mit:

  • Großes Logo (220x220px)
  • Titel unten
  • Künstler darunter

Design

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
styles:
  card:
    - height: 400px                   # Karten-Höhe
    - background: rgba(20, 20, 25, 0.75)  # Dunkler Hintergrund
    - backdrop-filter: blur(10px)     # Blur-Effekt
    - border: 1px solid rgba(255, 255, 255, 0.08)  # Dezenter Rahmen
    - border-radius: 25px             # Runde Ecken
    - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3)  # Schatten
    - padding: 30px                   # Innenabstand

Hintergrund:

  • rgba(20, 20, 25, 0.75) = Fast schwarz mit 75% Deckkraft
  • blur(10px) = Weichzeichner-Effekt hinter der Karte

Logo-Position

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
custom_fields:
  logo:
    - position: absolute
    - top: 50px                       # 50px von oben
    - left: 50%                       # Horizontal zentriert
    - transform: translateX(-50%)     # Zentrierungs-Korrektur
    - width: 220px                    # Logo-Breite
    - height: 220px                   # Logo-Höhe

Logo-Logik (JavaScript)

Code
const albumName = entity.attributes.media_album_name || '';
const entityPicture = entity.attributes.entity_picture || '';
const mediaContentId = entity.attributes.media_content_id || '';

// Spotify-Check
if (mediaContentId.includes('spotify:')) {
  // Zeige Spotify-Album-Cover
  return `<img src="${entityPicture}">`;
}

// Radio-Logo-Auswahl
let logoSrc = '/local/radio-logos/flashbackfm.png';  // Standard

if (albumName.includes('Flashback')) {
  logoSrc = '/local/radio-logos/flashbackfm.png';
} else if (albumName.includes('Munot')) {
  logoSrc = '/local/radio-logos/radiomunot.png';
} else if (albumName.includes('Radio 24')) {
  logoSrc = '/local/radio-logos/radio24.png';
}

return `<img src="${logoSrc}">`;

Logik:

  1. Prüft ob Spotify läuft → Zeigt Album-Cover
  2. Sonst: Prüft Radio-Sender-Name im Album-Name
  3. Wählt passendes Logo aus

Titel und Künstler

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
title:
  - bottom: 80px                      # 80px von unten
  - font-size: 24px                   # Größe
  - color: white                      # Farbe

artist:
  - bottom: 50px                      # 50px von unten
  - font-size: 18px
  - color: rgba(255, 255, 255, 0.7)  # Halbtransparent
YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
title: |
  return entity.attributes.media_title || 'Kein Titel';

artist: |
  return entity.attributes.media_artist || '';

Holt Informationen aus dem Media Player:

  • media_title = Song-/Sendungs-Name
  • media_artist = Künstler/Interpret

2. SEPARATOR (Trennlinie)

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
- type: custom:bubble-card
  card_type: separator
  card_layout: normal

Was macht sie?

  • Visuelle Trennung zwischen Player und Controls
  • Dünne horizontale Linie

3. CONTROL BUTTONS (Runde Steuerungs-Buttons)

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
- type: vertical-stack
  cards:
    - square: false
      type: grid
      columns: 3                      # 3 Buttons nebeneinander

Button-Struktur (alle 3 gleich)

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
- show_name: false
  show_icon: true
  type: button
  icon: mdi:volume-minus              # Icon
  tap_action:
    action: call-service              # Service aufrufen
    service: media_player.volume_down # Lautstärke runter
    target:
      entity_id: media_player.kuche_2

Die 3 Buttons:

ButtonIconServiceFunktion
Linksmdi:volume-minusmedia_player.volume_downLeiser
Mittemdi:play-pausemedia_player.media_play_pausePlay/Pause
Rechtsmdi:volume-plusmedia_player.volume_upLauter

Button-Design

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
card_mod:
  style: |
    ha-card {
      height: 130px;
      width: 130px;                   # Rund: 130x130px
      background: rgba(20,20,25,0.75);
      backdrop-filter: blur(12px);
      border-radius: 50%;             # ← 50% = Kreis
      border: 1px solid rgba(255,255,255,0.08);
      box-shadow: 0 8px 28px rgba(0,0,0,0.35);
      color: white;
      margin: auto;                   # Zentriert
    }
    ha-card:active {
      transform: scale(0.95);         # ← Klick-Animation
    }

Design-Merkmale:

  • border-radius: 50% macht sie rund
  • transform: scale(0.95) beim Klick = Drück-Effekt
  • margin: auto = automatisch zentriert

4. SENDER-BUTTONS (Große Radio-Sender-Karten)

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
- square: true
  type: grid
  columns: 3                          # 3 Sender nebeneinander

Sender-Button-Struktur

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
- show_name: false
  show_icon: false
  type: button
  tap_action:
    action: call-service
    service: media_player.play_media  # Medien abspielen
    target:
      entity_id: media_player.kuche_2
    data:
      media_content_type: url         # Stream-URL
      media_content_id: tunein--kqdEaHjB://radio/s303414  # ← TuneIn ID

Was passiert beim Klick?

  1. Ruft media_player.play_media Service auf
  2. Sendet Stream-URL an media_player.kuche_2
  3. Radio beginnt zu spielen

Stream-IDs der Sender

SenderTuneIn IDLogo
Flashback FMs303414/local/radio-logos/flashbackfm.png
Radio Munots15496/local/radio-logos/radiomunot.png
Radio 24s2773/local/radio-logos/radio24.png

Button-Design

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
card_mod:
  style: |
    ha-card {
      height: 300px;                  # Hohe Buttons
      margin-top: 4px;
      margin-bottom: 4px;
      background: rgba(20,20,25,0.75);
      backdrop-filter: blur(16px);
      border-radius: 26px;
      border: 1px solid rgba(255,255,255,0.08);
      box-shadow: 0 14px 45px rgba(0,0,0,0.4);
      position: relative;
      overflow: hidden;               # Logo bleibt im Button
    }

Logo im Button (via ::before)

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
ha-card::before {
  content: "";                        # Pseudo-Element
  position: absolute;
  inset: 14%;                         # 14% Abstand von allen Seiten
  background: url('/local/radio-logos/flashbackfm.png') center / contain no-repeat;
}

Wie funktioniert das?

  • ::before erstellt ein unsichtbares Element vor dem Card-Inhalt
  • inset: 14% = 14% Abstand oben/unten/links/rechts (Logo ist zentriert)
  • background: url(...) = Logo als Hintergrund
  • contain = Logo vollständig sichtbar, ohne Verzerrung
  • no-repeat = Logo nur einmal anzeigen

Vorteil dieser Methode:

  • Kein -Tag nötig
  • Logo ist Teil des Button-Styles
  • Sauberer Code

Anpassungen

Media Player ändern

Überall wo media_player.kuche_2 steht:

Code
entity: media_player.DEIN_PLAYER

Neuen Sender hinzufügen

  1. Neuen Button kopieren:
YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
- type: button
  show_name: false
  show_icon: false
  tap_action:
    action: call-service
    service: media_player.play_media
    target:
      entity_id: media_player.kuche_2
    data:
      media_content_type: url
      media_content_id: tunein--kqdEaHjB://radio/DEINE_ID  # ← Neue ID
  card_mod:
    style: |
      ha-card {
        height: 300px;
        # ... (gleich wie oben)
      }
      ha-card::before {
        background: url('/local/radio-logos/NEUER_SENDER.png') center / contain no-repeat;
      }
  1. TuneIn ID finden:
    • Gehe auf tunein.com
    • Suche deinen Sender
    • URL anschauen: tunein.com/radio/SENDERNAME-s12345/
    • Die Zahl 12345 ist die ID
    • Komplette ID: tunein--kqdEaHjB://radio/s12345
  2. Logo hochladen:
    • Logo in /config/www/radio-logos/ speichern
    • Pfad: /local/radio-logos/SENDERNAME.png
  3. Now Playing Card anpassen:
Code
// Im logo-Bereich hinzufügen:
} else if (albumName.includes('DEIN SENDER')) {
  logoSrc = '/local/radio-logos/SENDERNAME.png';
}

Control-Buttons anpassen

Größere Buttons:

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
ha-card {
  height: 150px;
  width: 150px;
}

Andere Icons:

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
icon: mdi:skip-previous    # Zurück
icon: mdi:skip-next        # Weiter
icon: mdi:stop             # Stop

Andere Services:

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
tap_action:
  action: call-service
  service: media_player.media_next_track  # Nächster Track

Sender-Buttons Layout ändern

4 Buttons pro Reihe:

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
type: grid
columns: 4                    # 4 statt 3

2 Buttons pro Reihe:

Code
columns: 2

Dann passen sich die Breiten automatisch an.

Höhere Buttons:

Code
ha-card {
  height: 350px;              # Statt 300px
}

Now Playing Card anpassen

Kleinere Card:

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
styles:
  card:
    - height: 350px           # Statt 400px

Kleineres Logo:

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
logo:
  - width: 180px              # Statt 220px
  - height: 180px

Andere Hintergrundfarbe:

Code
- background: rgba(0, 161, 136, 0.3)  # Türkis transparent

Grid-Layout Optionen

Ganz unten im Code:

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
grid_options:
  columns: 12                 # 12 Spalten-Grid
  rows: 5                     # 5 Zeilen

Was bedeutet das?

  • Das Dashboard nutzt ein 12-Spalten-Raster
  • Karten können unterschiedlich viele Spalten belegen
  • Ermöglicht flexible Layouts

Standard: Karten nutzen die volle Breite (alle 12 Spalten)

Zusammenfassung der Komponenten

KomponenteTypFunktion
Now Playingcustom:button-cardZeigt aktuellen Song/Sender
Separatorcustom:bubble-cardVisuelle Trennung
Control Buttonsbutton in gridLautstärke & Play/Pause
Sender Buttonsbutton in gridRadio-Sender starten

 Wichtige Code-Bereiche

Media Player Entity: Suche media_player.kuche_2 (4x im Code)

Stream-URLs: Suche media_content_id: bei den Sender-Buttons

Logo-Pfade: Suche url('/local/radio-logos/

Logo-Logik: Suche if (albumName.includes(

Button-Größen: Suche height: und width:

Farben: Suche rgba(

Aktualisierte Dashboard-Version

Diese Version stammt aus dem aktuellen YAML-Dashboard. Sie nutzt media_player.kuche_2, dynamische Logos, Lauftext für lange Titel, Play/Pause, Lautstärke und direkte Senderbuttons.

Kompletter aktueller Radio-View-Code

YAML-Hilfe

Vor dem Einsetzen kurz prüfen

  • Ersetze Entity-IDs, Pfade und Namen durch deine eigenen Werte.
  • Prüfe, ob die genannte Card, Integration oder Erweiterung wirklich installiert ist.
  • Teste die Änderung zuerst in einem kleinen Bereich, bevor du das ganze Dashboard umbaust.
YAML
- title: Radio
    path: radio
    type: masonry
    cards:
      - type: vertical-stack
        cards:
          - type: custom:button-card
            entity: media_player.kuche_2
            show_name: false
            show_state: false
            show_icon: false
            tap_action:
              action: none
            variables:
              card_height: 230px
              card_radius: 28px
              cover_size: 164px
              cover_left: 22px
              cover_top: 22px
              cover_radius: 20px
              info_left: 192px
              info_right: 20px
              badge_bottom: 10px
              font_title: 22px
              font_artist: 14px
              font_station: 12px
              blur_amount: 4px
              blur_opacity: "0.45"
              scroll_duration_title: 20
              scroll_duration_artist: 13
              max_chars: 22
            styles:
              card:
                - height: "[[[ return variables.card_height ]]]"
                - border-radius: "[[[ return variables.card_radius ]]]"
                - padding: 0
                - overflow: hidden
                - background: >-
                    linear-gradient(135deg, rgba(0,161,136,.28) 0%,
                    rgba(17,17,20,.98) 48%, rgba(17,17,20,.98) 100%)
                - border: 1px solid rgba(255,255,255,.09)
                - box-shadow: 0 16px 45px rgba(0,0,0,.45)
              custom_fields:
                cover:
                  - position: absolute
                  - left: "[[[ return variables.cover_left ]]]"
                  - top: "[[[ return variables.cover_top ]]]"
                  - width: "[[[ return variables.cover_size ]]]"
                  - height: "[[[ return variables.cover_size ]]]"
                badge:
                  - position: absolute
                  - left: "[[[ return variables.cover_left ]]]"
                  - bottom: "[[[ return variables.badge_bottom ]]]"
                  - display: flex
                  - align-items: center
                info:
                  - position: absolute
                  - left: "[[[ return variables.info_left ]]]"
                  - right: "[[[ return variables.info_right ]]]"
                  - top: 0
                  - bottom: 0
                  - display: flex
                  - flex-direction: column
                  - justify-content: center
            custom_fields:
              cover: |
                [[[
                  const isPaused = entity.state !== 'playing';
                  const albumName = entity.attributes.media_album_name || '';
                  const mediaContentId = entity.attributes.media_content_id || '';
                  const entityPicture = entity.attributes.entity_picture || '';
                  let logoSrc = '/local/radio-logos/flashbackfm.png';
                  if (albumName.includes('Munot') || mediaContentId.includes('s15496') || entityPicture.includes('s15496'))
                    logoSrc = '/local/radio-logos/radiomunot.png';
                  if (albumName.includes('Radio 24') || mediaContentId.includes('s2773') || entityPicture.includes('s2773'))
                    logoSrc = '/local/radio-logos/radio24.png';
                  if (mediaContentId.includes('spotify:') && entityPicture)
                    logoSrc = entityPicture;
                  const blur = isPaused ? `filter:blur(${variables.blur_amount});opacity:${variables.blur_opacity};` : '';
                  return `<img src="${logoSrc}" style="width:100%;height:100%;object-fit:contain;border-radius:${variables.cover_radius};box-shadow:0 8px 24px rgba(0,0,0,.5);transition:filter .4s,opacity .4s;${blur}">`;
                ]]]
              badge: |
                [[[
                  const isPlaying = entity.state === 'playing';
                  if (isPlaying) {
                    return `
                      <style>
                        @keyframes _pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}
                        @keyframes _eq{0%,100%{transform:scaleY(1)}50%{transform:scaleY(.2)}}
                        ._dot{animation:_pulse 1.4s ease-in-out infinite}
                        ._b1{animation:_eq .9s linear infinite}._b2{animation:_eq .7s linear infinite}
                        ._b3{animation:_eq 1.1s linear infinite}._b4{animation:_eq .8s linear infinite}
                        ._b5{animation:_eq 1.0s linear infinite}
                      </style>
                      <div style="display:flex;align-items:center;gap:6px;background:rgba(0,0,0,.35);border:1px solid rgba(0,220,180,.28);border-radius:20px;padding:5px 11px;">
                        <div class="_dot" style="width:7px;height:7px;border-radius:50%;background:#00dcb4;"></div>
                        <span style="font-size:11px;font-weight:700;letter-spacing:1.4px;color:#00dcb4;">LÄUFT GERADE</span>
                        <div style="display:flex;align-items:flex-end;gap:2px;height:14px;margin-left:4px;">
                          <div class="_b1" style="width:3px;height:6px;border-radius:2px;background:#00dcb4;transform-origin:bottom;"></div>
                          <div class="_b2" style="width:3px;height:12px;border-radius:2px;background:#00dcb4;transform-origin:bottom;"></div>
                          <div class="_b3" style="width:3px;height:8px;border-radius:2px;background:#00dcb4;transform-origin:bottom;"></div>
                          <div class="_b4" style="width:3px;height:13px;border-radius:2px;background:#00dcb4;transform-origin:bottom;"></div>
                          <div class="_b5" style="width:3px;height:5px;border-radius:2px;background:#00dcb4;transform-origin:bottom;"></div>
                        </div>
                      </div>`;
                  } else {
                    return `
                      <div style="display:flex;align-items:center;gap:6px;background:rgba(0,0,0,.35);border:1px solid rgba(255,255,255,.12);border-radius:20px;padding:5px 11px;">
                        <span style="font-size:11px;font-weight:700;letter-spacing:1.4px;color:rgba(255,255,255,.4);">PAUSIERT</span>
                      </div>`;
                  }
                ]]]
              info: |
                [[[
                  const isPlaying = entity.state === 'playing';
                  const station = (() => {
                    const a = entity.attributes.media_album_name || '';
                    const c = entity.attributes.media_content_id || '';
                    if (a.includes('Munot') || c.includes('s15496')) return 'Radio Munot';
                    if (a.includes('Radio 24') || c.includes('s2773')) return 'Radio 24';
                    if (a.includes('Flashback') || c.includes('s303414')) return 'Flashback FM';
                    return a || 'Radio';
                  })();
                  if (!isPlaying) {
                    return `
                      <div style="font-size:13px;color:rgba(255,255,255,.35);margin-bottom:10px;">${station}</div>
                      <div style="font-size:18px;font-weight:600;color:rgba(255,255,255,.45);margin-bottom:6px;">Pausiert</div>
                      <div style="font-size:12px;color:rgba(0,220,180,.75);">Doppelklick zum Starten</div>`;
                  }
                  const title_raw = entity.attributes.media_title || 'Radio';
                  const artist_raw = entity.attributes.media_artist || 'Bereit zum Abspielen';
                  const isMunot = (entity.attributes.media_album_name || '').includes('Munot') ||
                                  (entity.attributes.media_content_id || '').includes('s15496');
                  const title = isMunot ? artist_raw : title_raw;
                  const artist = isMunot ? title_raw : artist_raw;
                  const maxChars = variables.max_chars;
                  const titleLong = title.length > maxChars;
                  const artistLong = artist.length > maxChars;
                  return `
                    <style>
                      @keyframes _mq{0%,18%{transform:translateX(0)}82%,100%{transform:translateX(-50%)}}
                      ._mqt{animation:_mq ${variables.scroll_duration_title}s ease-in-out infinite;display:inline-block;white-space:nowrap;}
                      ._mqa{animation:_mq ${variables.scroll_duration_artist}s ease-in-out infinite;display:inline-block;white-space:nowrap;}
                    </style>
                    <div style="font-size:${variables.font_station};color:rgba(255,255,255,.4);margin-bottom:10px;">${station}</div>
                    <div style="overflow:hidden;margin-bottom:7px;">
                      ${titleLong
                        ? `<span class="_mqt" style="font-size:${variables.font_title};line-height:1.25;font-weight:700;color:white;">${title}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${title}</span>`
                        : `<span style="font-size:${variables.font_title};line-height:1.25;font-weight:700;color:white;white-space:nowrap;">${title}</span>`
                      }
                    </div>
                    <div style="overflow:hidden;">
                      ${artistLong
                        ? `<span class="_mqa" style="font-size:${variables.font_artist};color:rgba(255,255,255,.65);font-weight:300;">${artist}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${artist}</span>`
                        : `<span style="font-size:${variables.font_artist};color:rgba(255,255,255,.65);font-weight:300;white-space:nowrap;">${artist}</span>`
                      }
                    </div>`;
                ]]]
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                icon: mdi:volume-minus
                show_name: false
                tap_action:
                  action: call-service
                  service: media_player.volume_down
                  target:
                    entity_id: media_player.kuche_2
                variables:
                  btn_height: 68px
                  btn_radius: 20px
                  btn_margin_top: 10px
                  btn_icon_size: 26px
                styles:
                  card:
                    - height: "[[[ return variables.btn_height ]]]"
                    - border-radius: "[[[ return variables.btn_radius ]]]"
                    - background: rgba(17,17,20,.96)
                    - border: 1px solid rgba(255,255,255,.08)
                    - box-shadow: 0 6px 18px rgba(0,0,0,.3)
                    - margin-top: "[[[ return variables.btn_margin_top ]]]"
                  icon:
                    - color: rgba(255,255,255,.6)
                    - width: "[[[ return variables.btn_icon_size ]]]"
              - type: custom:button-card
                entity: media_player.kuche_2
                show_name: false
                show_state: false
                show_icon: false
                tap_action:
                  action: call-service
                  service: media_player.media_play_pause
                  target:
                    entity_id: media_player.kuche_2
                variables:
                  btn_height: 68px
                  btn_radius: 20px
                  btn_margin_top: 10px
                  play_icon_size: 32px
                styles:
                  card:
                    - height: "[[[ return variables.btn_height ]]]"
                    - border-radius: "[[[ return variables.btn_radius ]]]"
                    - background: "linear-gradient(135deg, #00a188, #00dcb4)"
                    - border: none
                    - box-shadow: 0 6px 18px rgba(0,0,0,.3)
                    - margin-top: "[[[ return variables.btn_margin_top ]]]"
                    - overflow: hidden
                  custom_fields:
                    btn:
                      - position: absolute
                      - top: 0
                      - left: 0
                      - right: 0
                      - bottom: 0
                      - display: flex
                      - align-items: center
                      - justify-content: center
                custom_fields:
                  btn: |
                    [[[
                      const icon = entity.state === 'playing' ? 'mdi:pause' : 'mdi:play';
                      return `<ha-icon icon="${icon}" style="--mdc-icon-size:${variables.play_icon_size};color:white;"></ha-icon>`;
                    ]]]
              - type: custom:button-card
                icon: mdi:volume-plus
                show_name: false
                tap_action:
                  action: call-service
                  service: media_player.volume_up
                  target:
                    entity_id: media_player.kuche_2
                variables:
                  btn_height: 68px
                  btn_radius: 20px
                  btn_margin_top: 10px
                  btn_icon_size: 26px
                styles:
                  card:
                    - height: "[[[ return variables.btn_height ]]]"
                    - border-radius: "[[[ return variables.btn_radius ]]]"
                    - background: rgba(17,17,20,.96)
                    - border: 1px solid rgba(255,255,255,.08)
                    - box-shadow: 0 6px 18px rgba(0,0,0,.3)
                    - margin-top: "[[[ return variables.btn_margin_top ]]]"
                  icon:
                    - color: rgba(255,255,255,.6)
                    - width: "[[[ return variables.btn_icon_size ]]]"
          - type: custom:button-card
            entity: media_player.kuche_2
            show_name: false
            show_icon: false
            show_state: false
            tap_action:
              action: none
            variables:
              vol_height: 64px
              vol_radius: 20px
              vol_margin_top: 0px
              vol_font_label: 13px
              vol_font_value: 19px
              vol_bar_height: 3px
            styles:
              card:
                - height: "[[[ return variables.vol_height ]]]"
                - border-radius: "[[[ return variables.vol_radius ]]]"
                - background: rgba(17,17,20,.96)
                - border: 1px solid rgba(255,255,255,.08)
                - box-shadow: 0 6px 18px rgba(0,0,0,.3)
                - margin-top: "[[[ return variables.vol_margin_top ]]]"
                - overflow: hidden
                - padding: 0
              custom_fields:
                vol:
                  - position: absolute
                  - top: 0
                  - left: 0
                  - right: 0
                  - bottom: 0
            custom_fields:
              vol: |
                [[[
                  const v = Math.round((entity.attributes.volume_level || 0) * 100);
                  return `
                    <div style="width:100%;height:100%;display:flex;flex-direction:column;">
                      <div style="flex:1;display:flex;align-items:center;padding:0 20px;gap:12px;">
                        <svg viewBox="0 0 24 24" style="width:20px;height:20px;flex-shrink:0;fill:none;stroke:rgba(255,255,255,.5);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;">
                          <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
                          <path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"/>
                        </svg>
                        <span style="font-size:${variables.vol_font_label};color:rgba(255,255,255,.45);flex:1;">Lautstärke</span>
                        <span style="font-size:${variables.vol_font_value};font-weight:700;color:white;">${v}%</span>
                      </div>
                      <div style="height:${variables.vol_bar_height};background:rgba(255,255,255,.07);">
                        <div style="height:100%;width:${v}%;background:linear-gradient(90deg,#00a188,#00dcb4);transition:width .3s;"></div>
                      </div>
                    </div>`;
                ]]]
          - type: grid
            columns: 3
            square: false
            cards:
              - type: custom:button-card
                entity: media_player.kuche_2
                show_name: false
                show_icon: false
                tap_action:
                  action: call-service
                  service: media_player.play_media
                  target:
                    entity_id: media_player.kuche_2
                  data:
                    media_content_type: url
                    media_content_id: tunein--kqdEaHjB://radio/s303414
                variables:
                  station_id: s303414
                  logo: /local/radio-logos/flashbackfm.png
                  station_name: Flashback FM
                  station_height: 108px
                  station_radius: 20px
                  station_margin_top: 10px
                  station_logo_height: 58px
                  station_font: 9px
                styles:
                  card:
                    - height: "[[[ return variables.station_height ]]]"
                    - border-radius: "[[[ return variables.station_radius ]]]"
                    - background: >-
                        [[[ const
                        a=(entity.attributes.media_content_id||'').includes(variables.station_id)&&entity.state==='playing';
                        return a?'rgba(0,161,136,.15)':'rgba(17,17,20,.96)'; ]]]
                    - border: >-
                        [[[ const
                        a=(entity.attributes.media_content_id||'').includes(variables.station_id)&&entity.state==='playing';
                        return a?'1px solid rgba(0,220,180,.4)':'1px solid
                        rgba(255,255,255,.08)'; ]]]
                    - box-shadow: 0 6px 18px rgba(0,0,0,.3)
                    - margin-top: "[[[ return variables.station_margin_top ]]]"
                    - padding: 14px
                    - overflow: hidden
                  custom_fields:
                    content:
                      - position: absolute
                      - top: 0
                      - left: 0
                      - right: 0
                      - bottom: 0
                      - display: flex
                      - flex-direction: column
                      - align-items: center
                      - justify-content: center
                      - gap: 8px
                      - padding: 14px
                custom_fields:
                  content: |
                    [[[
                      const isActive = (entity.attributes.media_content_id||'').includes(variables.station_id) && entity.state === 'playing';
                      return `
                        <img src="${variables.logo}" style="width:100%;max-height:${variables.station_logo_height};object-fit:contain;">
                        <span style="font-size:${variables.station_font};font-weight:700;letter-spacing:1px;text-transform:uppercase;color:${isActive?'rgba(0,220,180,.85)':'rgba(255,255,255,.28)'};">${variables.station_name}</span>`;
                    ]]]
              - type: custom:button-card
                entity: media_player.kuche_2
                show_name: false
                show_icon: false
                tap_action:
                  action: call-service
                  service: media_player.play_media
                  target:
                    entity_id: media_player.kuche_2
                  data:
                    media_content_type: url
                    media_content_id: tunein--kqdEaHjB://radio/s15496
                variables:
                  station_id: s15496
                  logo: /local/radio-logos/radiomunot.png
                  station_name: Radio Munot
                  station_height: 108px
                  station_radius: 20px
                  station_margin_top: 10px
                  station_logo_height: 58px
                  station_font: 9px
                styles:
                  card:
                    - height: "[[[ return variables.station_height ]]]"
                    - border-radius: "[[[ return variables.station_radius ]]]"
                    - background: >-
                        [[[ const
                        a=(entity.attributes.media_content_id||'').includes(variables.station_id)&&entity.state==='playing';
                        return a?'rgba(0,161,136,.15)':'rgba(17,17,20,.96)'; ]]]
                    - border: >-
                        [[[ const
                        a=(entity.attributes.media_content_id||'').includes(variables.station_id)&&entity.state==='playing';
                        return a?'1px solid rgba(0,220,180,.4)':'1px solid
                        rgba(255,255,255,.08)'; ]]]
                    - box-shadow: 0 6px 18px rgba(0,0,0,.3)
                    - margin-top: "[[[ return variables.station_margin_top ]]]"
                    - padding: 14px
                    - overflow: hidden
                  custom_fields:
                    content:
                      - position: absolute
                      - top: 0
                      - left: 0
                      - right: 0
                      - bottom: 0
                      - display: flex
                      - flex-direction: column
                      - align-items: center
                      - justify-content: center
                      - gap: 8px
                      - padding: 14px
                custom_fields:
                  content: |
                    [[[
                      const isActive = (entity.attributes.media_content_id||'').includes(variables.station_id) && entity.state === 'playing';
                      return `
                        <img src="${variables.logo}" style="width:100%;max-height:${variables.station_logo_height};object-fit:contain;">
                        <span style="font-size:${variables.station_font};font-weight:700;letter-spacing:1px;text-transform:uppercase;color:${isActive?'rgba(0,220,180,.85)':'rgba(255,255,255,.28)'};">${variables.station_name}</span>`;
                    ]]]
              - type: custom:button-card
                entity: media_player.kuche_2
                show_name: false
                show_icon: false
                tap_action:
                  action: call-service
                  service: media_player.play_media
                  target:
                    entity_id: media_player.kuche_2
                  data:
                    media_content_type: url
                    media_content_id: tunein--kqdEaHjB://radio/s2773
                variables:
                  station_id: s2773
                  logo: /local/radio-logos/radio24.png
                  station_name: Radio 24
                  station_height: 108px
                  station_radius: 20px
                  station_margin_top: 10px
                  station_logo_height: 58px
                  station_font: 9px
                styles:
                  card:
                    - height: "[[[ return variables.station_height ]]]"
                    - border-radius: "[[[ return variables.station_radius ]]]"
                    - background: >-
                        [[[ const
                        a=(entity.attributes.media_content_id||'').includes(variables.station_id)&&entity.state==='playing';
                        return a?'rgba(0,161,136,.15)':'rgba(17,17,20,.96)'; ]]]
                    - border: >-
                        [[[ const
                        a=(entity.attributes.media_content_id||'').includes(variables.station_id)&&entity.state==='playing';
                        return a?'1px solid rgba(0,220,180,.4)':'1px solid
                        rgba(255,255,255,.08)'; ]]]
                    - box-shadow: 0 6px 18px rgba(0,0,0,.3)
                    - margin-top: "[[[ return variables.station_margin_top ]]]"
                    - padding: 14px
                    - overflow: hidden
                  custom_fields:
                    content:
                      - position: absolute
                      - top: 0
                      - left: 0
                      - right: 0
                      - bottom: 0
                      - display: flex
                      - flex-direction: column
                      - align-items: center
                      - justify-content: center
                      - gap: 8px
                      - padding: 14px
                custom_fields:
                  content: |
                    [[[
                      const isActive = (entity.attributes.media_content_id||'').includes(variables.station_id) && entity.state === 'playing';
                      return `
                        <img src="${variables.logo}" style="width:100%;max-height:${variables.station_logo_height};object-fit:contain;">
                        <span style="font-size:${variables.station_font};font-weight:700;letter-spacing:1px;text-transform:uppercase;color:${isActive?'rgba(0,220,180,.85)':'rgba(255,255,255,.28)'};">${variables.station_name}</span>`;
                    ]]]