TTS (-Queue) mit Home Assistant und Alexa als Skript

Mein Zuhause ist ja zu einem Großteil durch automatisiert. Dazu gehört auch die eine oder andere Information über den Status bestimmter Sensoren. Um mich Audiovisuell auf Dinge hinweisen zu lassen, nutze ich seither Alexa in Kombination mit der Nabu-Casa Cloud. Es gibt hier natürlich noch viele weitere Wege (ohne, dafür bezahlen zu müssen), aber dafür, dass Home Assistant grundsätzlich schon kostenfrei ist (und wöchentlich weiter entwickelt wird), ist es mir ein wichtiges meinen jährlichen kleinen Beitrag zu leisten. Aber ich schweife ab.

Welches Problem gilt es zu lösen?

Jeder der sich über Home Assistant Informationen über Alexa (oder ggf. auch andere) schicken lässt, kennt es eventuell: Wenn kurzzeitig zwei Ankündigungen hintereinander einfliegen, wird die erste mitunter unterbrochen und Alexa erzählt die zweite, bevor die erste vollständig herunter gerattert wurde. Je nachdem ob es wichtig oder weniger wichtig war, kann das blöd sein.

Ich habe daher darüber nachgedacht, dass die Nachrichten an Alexa gequeued, sprich in eine Warteschlange gelegt werden sollten, wenn die erste derzeitige Nachricht noch nicht fertig erzählt wurde.

Das war das eigentliche Problem, dass ich lösen wollte. Daraus entstand jedoch noch etwas viel tolleres.

Das Skript

Voraussetzungen

Eigentlich keine. Eventuell wird noch ein Helfer benötigt um Alexa im Haus stumm zu schalten. Wobei Stumm sich nur auf die TTS Funktion bezieht, nicht eine stumme Alexa als solche. 

Sollte das nicht gebraucht oder gewünscht sein, kann der Teil einfach ausgebaut werden. (Die Bedingung ob input_boolean.alexa_stumm „off“ ist).

Auch muss natürlich die einzelnen Entitäten ggf. angepasst werden um die Benachrichtigungen an das korrekte Handy / App zu schicken oder die Licht Entitäten auf eure Gegebenheiten abzustimmen.

Hier gilt es dann: Köpfchen bemühen (oder schreib mir ^^).

Lass knaggen: Das Skript

Hier gehe ich zunächst ein wenig auf das Skript und den Ablauf ein um zu verstehen, wie das ganze überhaupt funktioniert und gedacht ist.

Ursprünglich bringt man Alexa mit diesem Snippet zum reden:

service: notify.alexa_media
data:
  message: Heute wird ein schöner Tag
  data:
    type: tts
  target:
    - media_player.alexa_wohnzimmer

Ruft man dieses Skript nun mehrfach hintereinander auf, wird Alexa also immer genötigt von vorne anzufangen.

Diesen Teil (das direkte Ansprechen via notify.alexa_media) ersetze ich mit einem Skript. Dieses Skript, nimmt verschiedene Parameter entgegen, errechnet ungefähr die Sprechzeit die Alexa benötigt, setzt eine Verzögerung und wird dann beendet.

Sollte nun der Fall eintreten, dass mehrere Informationen an Alexa gegeben werden sollten (z.B. „Waschmaschine ist fertig“ und gleichzeitig „Geschirrspüler ist fertig“) und das Skript ist in der Zeit noch aktiv (durch die Verzögerung), startet das Skript nicht automatisch neu, sondern wird selbstständig in eine Warteschlange versetzt.

Damit ist es also möglich, das Skript mehrfach aufzurufen und es wird im Anschluss neu gestartet, sobald der vorherige Ablauf abgeschlossen ist.

Das komplette Skript

alias: tts_queue
sequence:
  - variables:
      alexa_tts_message: >
        {% if critical %} <audio
        src='soundbank://soundlibrary/computers/beeps_tones/beeps_tones_08'/> {%
        elif doorbell %} <audio
        src='soundbank://soundlibrary/home/amzn_sfx_doorbell_chime_02'/> {% elif
        announce %} <audio
        src='soundbank://soundlibrary/computers/beeps_tones/beeps_tones_12'/>
        {%endif %}

        {% if whisper %} <amazon:effect name='whispered'> {% endif %} 

        {% if excited %} <amazon:emotion name='excited' intensity='medium'> {%
        elif disappointed %} <amazon:emotion name='disappointed'
        intensity='medium'> {% endif %}

        {{ message }}

        {% if excited or disappointed %} </amazon:emotion> {% endif %} {% if
        whisper %} </amazon:effect> {% endif %}
  - alias: TTS Ambilight starten
    if:
      - condition: state
        entity_id: switch.smart_plug_2303164168077351200348e1e9bfe6df_outlet
        state: "on"
    then:
      - service: scene.create
        metadata: {}
        data:
          scene_id: tmp_ttsambilight
          snapshot_entities:
            - light.philips_tv_ambilight
      - service: light.turn_on
        target:
          entity_id: light.philips_tv_ambilight
        data:
          rgb_color:
            - 255
            - 38
            - 0
          effect: "FOLLOW_AUDIO: KNIGHT_RIDER_ALTERNATING: Expert"
  - alias: Sideboard blinken lassen 1
    if:
      - condition: template
        value_template: "{{ blink_sideboard }}"
    then:
      - service: light.turn_on
        metadata: {}
        data:
          effect: blink
        target:
          entity_id:
            - light.sideboard_links
            - light.sideboard_rechts
  - if:
      - condition: or
        conditions:
          - condition: state
            entity_id: input_boolean.alexa_stumm
            state: "off"
          - condition: template
            value_template: "{{ important }}"
          - condition: template
            value_template: "{{ critical }}"
      - condition: or
        conditions:
          - condition: numeric_state
            entity_id: zone.home
            above: 0
          - condition: state
            entity_id: input_boolean.niemand_zuhause_uberschreiben
            state: "on"
    then:
      - service: notify.alexa_media
        data:
          message: "{{ alexa_tts_message }}"
          data:
            type: tts
          target: "{{ target }}"
      - delay:
          seconds: >
            {% set l = message|length %} {% set speed = 75 %} {% set
            duration_seconds = ((speed * l)/1000)|round(0,method='ceil')|int %}

            {% if announce %} {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {% if critical %}  {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {% if doorbell %}  {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {{ duration_seconds }}
    alias: Alexa TTS
  - alias: Notification an Mobile oder HA
    if:
      - condition: or
        conditions:
          - condition: state
            entity_id: input_boolean.alexa_stumm
            state: "on"
          - condition: template
            value_template: "{{ notify }}"
    then:
      - service: notify.mobile_app_iphone_monty
        metadata: {}
        data:
          message: "{{ message }}"
          title: Venushügel Notify
      - service: notify.persistent_notification
        metadata: {}
        data:
          title: Venushügel Notify
          message: "{{ message }}"
  - alias: TTS Ambilight beenden
    if:
      - condition: state
        entity_id: switch.smart_plug_2303164168077351200348e1e9bfe6df_outlet
        state: "on"
    then:
      - if:
          - condition: state
            entity_id: input_boolean.alexa_stumm
            state: "on"
        then:
          - delay:
              hours: 0
              minutes: 0
              seconds: 10
              milliseconds: 0
      - service: scene.turn_on
        metadata: {}
        target:
          entity_id: scene.tmp_ttsambilight
      - service: scene.delete
        metadata: {}
        data: {}
        target:
          entity_id: scene.tmp_ttsambilight
  - alias: Sideboard blinken lassen 2
    if:
      - condition: template
        value_template: "{{ blink_sideboard }}"
    then:
      - service: light.turn_on
        metadata: {}
        data:
          effect: blink
        target:
          entity_id:
            - light.sideboard_links
            - light.sideboard_rechts
mode: queued
icon: mdi:account-voice
max: 100
fields:
  announce:
    selector:
      boolean: {}
    name: announce
    description: Sound zur Ankündigung spielen
  important:
    selector:
      boolean: {}
    name: important
    description: Alexa stumm ignorieren
  critical:
    selector:
      boolean: {}
    name: critical
    description: Alexa stumm ignorieren, critical Sound
  doorbell:
    selector:
      boolean: {}
    description: Alexa stumm ignorieren, Türglocke Sound
    name: doorbell
  message:
    selector:
      text:
        multiline: true
        multiple: false
    name: message
    required: true
    description: Das spricht Alexa
  whisper:
    selector:
      boolean: {}
    name: whisper
    description: Alexa flüstert
  excited:
    selector:
      boolean: {}
    name: excited
    description: Alexa ist aufgeregt
  disappointed:
    selector:
      boolean: {}
    name: disappointed
    description: Alexa ist traurig
  target:
    selector:
      entity:
        multiple: true
    name: target
    required: true
    default:
      - media_player.alexa_kuche
      - media_player.alexa_arbeitszimmer
      - media_player.alexa_flur
      - media_player.alexa_schlafzimmer
      - media_player.alexa_badezimmer
      - media_player.alexa_wohnzimmer
    description: Welche Alexa soll sprechen?
  blink_sideboard:
    selector:
      boolean: {}
    name: blink_sideboard
  notify:
    selector:
      boolean: {}
    name: notify

Ja Moin. Das ist ein ganzer Batzen. Aber schauen wir uns die einzelnen Bereiche doch einmal im Detail an und arbeiten uns von unten nach oben durch (fand ich an der Stelle recht sinnvoll):

Felder und Einstellungen des Skripts

mode: queued
icon: mdi:account-voice
max: 100
fields:
  announce:
    selector:
      boolean: {}
    name: announce
    description: Sound zur Ankündigung spielen
  important:
    selector:
      boolean: {}
    name: important
    description: Alexa stumm ignorieren
  critical:
    selector:
      boolean: {}
    name: critical
    description: Alexa stumm ignorieren, critical Sound
  doorbell:
    selector:
      boolean: {}
    description: Alexa stumm ignorieren, Türglocke Sound
    name: doorbell
  message:
    selector:
      text:
        multiline: true
        multiple: false
    name: message
    required: true
    description: Das spricht Alexa
  whisper:
    selector:
      boolean: {}
    name: whisper
    description: Alexa flüstert
  excited:
    selector:
      boolean: {}
    name: excited
    description: Alexa ist aufgeregt
  disappointed:
    selector:
      boolean: {}
    name: disappointed
    description: Alexa ist traurig
  target:
    selector:
      entity:
        multiple: true
    name: target
    required: true
    default:
      - media_player.alexa_kuche
      - media_player.alexa_arbeitszimmer
      - media_player.alexa_flur
      - media_player.alexa_schlafzimmer
      - media_player.alexa_badezimmer
      - media_player.alexa_wohnzimmer
    description: Welche Alexa soll sprechen?
  blink_sideboard:
    selector:
      boolean: {}
    name: blink_sideboard
  notify:
    selector:
      boolean: {}
    name: notify

mode

Hiermit wird der Modus definiert, in dem das Skript arbeitet. Da das Skript nur einmal zur gleichen Zeit laufen soll (sonst würde Alexa mehrfach reden bzw. dabei unterbrechen) wird der Modus queued gewählt, sprich: Warteschlange.

icon

Das Frei wählbare Icon für das Skript.

max

Wie oft darf das Skript aktiv sein (bzw. in dem Fall wie lang wäre die Warteschlange). 100 gleichzeitige TTS Nachrichten habe ich eigentlich nicht zu erwarten, aber bisschen mehr Luft nach oben ist ja auch nicht verkehrt.

fields

Die Felder hier sind das spannende. Durch das Definieren von Feldern, können wir dem Skript z.B. verschiedene Booleans mitgeben, auf die es dann reagieren soll.

Schauen wir uns Beispielsweise mal das Feld critical an. Critical ist hier als Boolean definiert, es gibt also nur true oder false (an oder aus). Wird critical im Skript also als „true“ übergeben, können wir diesen Boolean in einem Template auswerten und darauf reagieren.

In meinem Fall werden dann z.B. verschiedene andere Sounds gespielt, Alexa flüstert, Alexa schreit oder ist gelangweilt. Ein paar nette Spielereien. 

Um bei aber bei critical zu bleiben: Ist critical aktiv, wird es gleichzeitig ignoriert, wenn ich Alexa eigentlich Stumm geschalten habe (auch das sehen wir gleich noch – dafür nutze ich einen weiteren Boolean namens alexa_stumm, den ich je nach Tageszeit oder Stimmung automatisch oder über mein Dashboard aktivieren kann – in dem Fall redet Alexa nicht mehr). Gibt es nun aber eine kritische und wichtige Information über die ich mich unbedingt und immer benachrichtigen möchte (bei mir ist das z.B. sowas wie „Steckdose Kühlschrank ist aus“ kann ich dem Skript critical als true übergeben und Alexa ignoriert den stummen Modus. Zusätzlich wird ein bestimmter Ton als Sound gespielt, von dem ich weiß „Oh, da folgt jetzt was was ich wissen sollte“.

Weitere Felder 

Nebenbei habe ich noch weitere Felder eingebaut, hier z.B. notify. Wird notify als Boolean true an das Skript übergeben, bekomme ich den Alexa Text als Benachrichtigung aufs Handy und gleichzeitig als Permanente Benachrichtigung in das Home Assistant Dashboard. Das ist mega praktisch, da ich somit die Texte, die Alexa vorlesen sollte, noch einmal nachlesen kann. 

Beispiel aus dem Alltag: Ich schaue einen Film und hab Alexa (in Home Assistant) stumm. Üblicherweise würde ich eine Benachrichtigung per Sprache erhalten, dass die Waschmaschine fertig ist. Nun spricht Alexa dies aber nicht und ich bekomme diese Information automatisch aufs Handy bzw. sehe sie im Dashboard. Sonst wäre sie mir einfach entgangen.

Oder auch noch: blink_sideboard. Ist dieser Boolean true, wird mein Sideboard im Wohnzimmer blinken. Somit kann ich mich auch optisch auf einen Hinweis bzw. eine Ankündigung hinweisen lassen, wenn das Geplapper von Alexa nicht gewünscht ist.

Wir brauchen Variablen!

Damit wir nun mit dem ganzen Zeugs auch im Skript arbeiten können, können wir auf die einzelnen Felder (die am Ende nur eine Variable im Skript sind) zugreifen. Mit einfachen if’s (die Praktischerweise im Vornherein true oder false auswerten können), braucht es dazu nicht einmal besonderes Hexenwerk:

variables:
  alexa_tts_message: >
    {% if critical %} <audio
    src='soundbank://soundlibrary/computers/beeps_tones/beeps_tones_08'/> {%
    elif doorbell %} <audio
    src='soundbank://soundlibrary/home/amzn_sfx_doorbell_chime_02'/> {% elif
    announce %} <audio
    src='soundbank://soundlibrary/computers/beeps_tones/beeps_tones_12'/>
    {%endif %}

    {% if whisper %} <amazon:effect name='whispered'> {% endif %} 

    {% if excited %} <amazon:emotion name='excited' intensity='medium'> {% elif
    disappointed %} <amazon:emotion name='disappointed' intensity='medium'> {%
    endif %}

    {{ message }}

    {% if excited or disappointed %} </amazon:emotion> {% endif %} {% if whisper
    %} </amazon:effect> {% endif %}

Hier sieht man z.B. im ersten Bereich ({% if critical %} würde ein zusätzlicher Text in die eigentliche Nachricht in Alexa eingebaut werden um einen Sound zu erzeugen. Dabei greife ich einfach auf die Audio-Bibliothek von Amazon zurück. Die kann man einfach im TTS von Alexa einbauen und Alexa macht dann ein bisschen Ton. Wäre z.B. das Feld doorbell true, dann würde der Sound amzn_sfx_doorbell_chime_02 gespielt werden.

Die ganzen Sachen lassen sich kombinieren (wobei ich bei den Sounds if und elif verwende, womit nur ein Sound abgespielt wird und das in der Priorität: critical, doorbell und announce. Wären also critical und announce im Skript auf true, gäbe es nur einen Sound vom critical.

Danach folgen noch whipser und exicited um die Stimmlage von Alexa zu beeinflussen und danach kommt in {{ Message }} das gleichnamige Feld, dass dem Skript ebenfalls übergeben wird (das wäre das, was Alexa wirklich sprechen soll).

Als letztes werden die Emotionen noch beendet.

Das ganze (nun fertig zusammengesetzte Konstrukt) wandert nun in die Variable alexa_tts_message.

Und das ist am Ende nun die, die wir alexa im notify.alexa_media übergeben werden:

Jetzt red mit mir!

service: notify.alexa_media
data:
  message: "{{ alexa_tts_message }}"
  data:
    type: tts
  target: "{{ target }}"

Bei message wird nun die vorher definierte Variable übergeben, dass was Alexa nun sprechen soll.

target ist ebenfalls als Feld definiert und hier übergeben wir dann eine Liste, sodass wir sogar wählen können, welche Alexas reden sollen (sollte es mehrere geben – ich hab eine in jedem Raum).

TTS auf Steroiden

Jetzt machen wir das ganze aber noch ein wenig geiler:

sequence:
  - variables:
      alexa_tts_message: >
        {% if critical %} <audio
        src='soundbank://soundlibrary/computers/beeps_tones/beeps_tones_08'/> {%
        elif doorbell %} <audio
        src='soundbank://soundlibrary/home/amzn_sfx_doorbell_chime_02'/> {% elif
        announce %} <audio
        src='soundbank://soundlibrary/computers/beeps_tones/beeps_tones_12'/>
        {%endif %}

        {% if whisper %} <amazon:effect name='whispered'> {% endif %} 

        {% if excited %} <amazon:emotion name='excited' intensity='medium'> {%
        elif disappointed %} <amazon:emotion name='disappointed'
        intensity='medium'> {% endif %}

        {{ message }}

        {% if excited or disappointed %} </amazon:emotion> {% endif %} {% if
        whisper %} </amazon:effect> {% endif %}
  - alias: TTS Ambilight starten
    if:
      - condition: state
        entity_id: switch.smart_plug_2303164168077351200348e1e9bfe6df_outlet
        state: "on"
    then:
      - service: scene.create
        metadata: {}
        data:
          scene_id: tmp_ttsambilight
          snapshot_entities:
            - light.philips_tv_ambilight
      - service: light.turn_on
        target:
          entity_id: light.philips_tv_ambilight
        data:
          rgb_color:
            - 255
            - 38
            - 0
          effect: "FOLLOW_AUDIO: KNIGHT_RIDER_ALTERNATING: Expert"
  - alias: Sideboard blinken lassen 1
    if:
      - condition: template
        value_template: "{{ blink_sideboard }}"
    then:
      - service: light.turn_on
        metadata: {}
        data:
          effect: blink
        target:
          entity_id:
            - light.sideboard_links
            - light.sideboard_rechts
  - if:
      - condition: or
        conditions:
          - condition: state
            entity_id: input_boolean.alexa_stumm
            state: "off"
          - condition: template
            value_template: "{{ important }}"
          - condition: template
            value_template: "{{ critical }}"
      - condition: or
        conditions:
          - condition: numeric_state
            entity_id: zone.home
            above: 0
          - condition: state
            entity_id: input_boolean.niemand_zuhause_uberschreiben
            state: "on"
    then:
      - service: notify.alexa_media
        data:
          message: "{{ alexa_tts_message }}"
          data:
            type: tts
          target: "{{ target }}"
      - delay:
          seconds: >
            {% set l = message|length %} {% set speed = 75 %} {% set
            duration_seconds = ((speed * l)/1000)|round(0,method='ceil')|int %}

            {% if announce %} {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {% if critical %}  {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {% if doorbell %}  {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {{ duration_seconds }}
    alias: Alexa TTS
  - alias: Notification an Mobile oder HA
    if:
      - condition: or
        conditions:
          - condition: state
            entity_id: input_boolean.alexa_stumm
            state: "on"
          - condition: template
            value_template: "{{ notify }}"
    then:
      - service: notify.mobile_app_iphone_monty
        metadata: {}
        data:
          message: "{{ message }}"
          title: Venushügel Notify
      - service: notify.persistent_notification
        metadata: {}
        data:
          title: Venushügel Notify
          message: "{{ message }}"
  - alias: TTS Ambilight beenden
    if:
      - condition: state
        entity_id: switch.smart_plug_2303164168077351200348e1e9bfe6df_outlet
        state: "on"
    then:
      - if:
          - condition: state
            entity_id: input_boolean.alexa_stumm
            state: "on"
        then:
          - delay:
              hours: 0
              minutes: 0
              seconds: 10
              milliseconds: 0
      - service: scene.turn_on
        metadata: {}
        target:
          entity_id: scene.tmp_ttsambilight
      - service: scene.delete
        metadata: {}
        data: {}
        target:
          entity_id: scene.tmp_ttsambilight
  - alias: Sideboard blinken lassen 2
    if:
      - condition: template
        value_template: "{{ blink_sideboard }}"
    then:
      - service: light.turn_on
        metadata: {}
        data:
          effect: blink
        target:
          entity_id:
            - light.sideboard_links
            - light.sideboard_rechts

Hier haben wir nun einen Haufen an zusätzlichen IFs, die je nachdem noch andere Dinge tun (können).

Zum Beispiel: Immer wenn Alexa spricht und mein Fernseher aktiv ist (ein Philips mit Ambilight) erstelle ich eine Szene um den vorherigen Ambilight-Status zu sichern. Dann wird ein Ambilight Modus follow_audio: knight_rider_alternating…“ aktiviert und ich hab nen nettes rotes Blinkelauflicht hinter dem Fernseher.

Das blinkende Sideboard habe ich ja schon kurz erklärt: Hier startet wenn das Feld blink_sideboard true ist nur ein kurzer Lichteffekt auf meine Hue-Play-Bars.

Damit Alexa auch wirklich spricht, prüfe ich noch auf den Helfer input_boolean.alexa_stumm und ob überhaupt jemand zuhause ist (Zone.home größer als 0) – ist ja sonst auch Quatsch, wobei es außer meinen Katzen auch niemanden interessiert, wenn Alexa mit sich selber reden würde.

(Das Sideboard blinkt übrigens zweimal, einmal zu beginn und einmal zum Ende ^^).

Nachdem Alexa fertig ist mit dem Reden (wie wir das ungefähr herausfinden, erkläre ich gleich), wird die temporäre Szene vom Ambiligt wieder aktiviert (also der Ursprungszustand) und anschließend gelöscht (5 Bytes sparen – habs ausgerechnet – … nicht).

Übrigens: Wenn alexa_stumm aktiv ist, habe ich noch eine extra Verzögerung von 10 Sekunden eingebaut. Das ist dafür da, damit das Ambilight 10 Sekunden Knight Rider spielt, da die – gleich nachfolgend erklärte Verzögerung – ja übergangen wird.

Ja, woher wissen wir nun wie lange Alexa redet?

delay:
          seconds: >
            {% set l = message|length %} {% set speed = 75 %} {% set
            duration_seconds = ((speed * l)/1000)|round(0,method='ceil')|int %}

            {% if announce %} {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {% if critical %}  {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {% if doorbell %}  {% set duration_seconds = duration_seconds + 2
            |round(0,method='ceil')|int %} {% endif %}

            {{ duration_seconds }}

Darum kümmert sich dieser putzige Teil.

Ich bin ehrlich: Das ist nicht auf meinem Mist gewachsen. Ich habe dieses Snippet (bzw. den ersten Teil davon) in irgend einem Thread im Home Assistant Forum gefunden. Ich habe es leider auch nicht mehr wiedergefunden, vermutlich suche ich jetzt einfach nicht mehr nach den richtigen Buzzwords. 

Solltest du deinen Code hier wieder erkennen, schreib mir kurz, dann verlinke ich dich gerne!

Das ganze berechnet nun anhand der länge der Zeichen die ungefähre Zeit, die zum Sprechen gebraucht wird. Und es haut sogar sehr gut hin. Ich habe noch die anderen Teile ergänzt und addiere für einen Sound jeweils 2 Sekunden.

Sprich, Home Assistant errechnet hier jetzt ein bisschen anhand der Zeichen und der Sounds die Zeit, die für die Nachricht gebraucht wird und gibt Alexa damit die Möglichkeit zu erzählen, bevor das Skript weiterläuft.

Mega geil.

Und zack, haben wir am Ende eigentlich auch schon unsere fertige Warteschlange:

Rufen wir das Skript auf, legt Alexa los, das Skript wird um xx Sekunden verzögert. Startet das Skript ein weiteres mal, wird es eingereiht und ausgeführt sobald der vorherige Durchlauf fertig ist. Schlussendlich spricht Alexa damit zu Ende und dann startet die zweite Nachricht.

Die Gedanken sind frei...

Nun ist nur noch deiner Fantasie eine Grenze gesetzt. Drumherum kannst du nun Lampen wild blinken lassen oder auch deine Garage öffnen, wenn Alexa spricht. xD

Benutzung im Automatisierungsalltag

Lustig wurde es, da ich nun jede Automatisierung durchforsten musste, in der ich Alexa nutzen möchte.

Aus:

service: notify.alexa_media
data:
  message: Die Waschmaschine ist fertig.
  data:
    type: tts
  target:
    - media_player.alexa_wohnzimmer
    - media_player.alexa_schlafzimmer
    - media_player.alexa_badezimmer

wird nun:

service: script.tts_queue
data:
  target:
    - media_player.alexa_schlafzimmer
    - media_player.alexa_badezimmer
    - media_player.alexa_wohnzimmer
  message: Die Waschmaschine ist fertig

Eigentlich kein nennenswerter Unterschied. Aber spannend wird es nun, da sich einfach die zusätzlichen Aktionen ergänzen lassen:

service: script.tts_queue
data:
  target:
    - media_player.alexa_schlafzimmer
    - media_player.alexa_badezimmer
    - media_player.alexa_wohnzimmer
  message: Die Waschmaschine ist fertig
  critical: true
  blink_sideboard: true
  notify: true
  excited: true

Und schwupp: Habe ich eine Alexa, die mir immer sagen wird, dass die Waschmaschine fertig ist, obwohl ich sie eigentlich stumm geschaltet habe, gleichzeitig blinkt mein Sideboard, ich bekomme ne Info aufs Handy und sie erzählt es mir sogar noch freudig erregt.

Und ich muss nicht jedes mal den Audio-Sound aus der Amazon-Bibliothek neu kopieren.

Gleichzeitig ergibt sich natürlich eine einfache Art der Wartung: Möchte ich den Critical-Sound ändern: Mache ich das nur einmal im Skript und nicht in 10 Automatisierungen. Genauso wenn ich möchte, dass statt dem Sideboard meine Sofa-LED blinkt. Dann ändere ich das einmal im Skript.

So sieht das ganze übrigens in den Entwicklertools aus, falls man damit herumspielen möchte.

TTS Queue Skript Entwicklertools Home Assistant

Bildquellen

Kategorien: Smarthome

0 Kommentare

Schreibe einen Kommentar

Avatar-Platzhalter

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.

DSGVO Cookie Consent mit Real Cookie Banner