Script to temorary adjust the volume and restore afterwards

Hi, I’m having difficulty finding the bug in my script. When I try to save it, HA gives the error message: Message malformed: extra keys not allowed @ data[‘script’].**

When I look at the documentation, I see nothing wrong. It’s the first script I’ve written, so I probably did something obviously wrong.
I started with pressing the button to create a new script and then converted a part of an automation in a script because I want to use it many times.

script:
  tts_volume_restore:
    alias: "Dynamische TTS Met Volume Herstel"
    description: "Speelt een bericht af op een gespecificeerde mediaspeler met tijdelijke volumeverhoging en herstelt daarna het volume."
    fields:
      media_player_entity_id:
        name: Mediaspeler Entiteit ID
        description: De entity_id van de speler (bv. media_player.keuken).
        required: true
        example: media_player.aanrecht
        selector:
          entity:
            domain: media_player
      target_device_id:
        name: Doel Device ID (Optioneel)
        description: De device_id van de speler. Wordt gebruikt indien entity_id niet volstaat.
        required: false
        example: ab5694a6f25b783628746ee723a521e6
        selector:
          device:
            domain: media_player
      tts_volume_level:
        name: Tijdelijk TTS Volume
        description: Het volume tijdens de uitspraak (0.0 tot 1.0).
        required: true
        example: 0.6
        default: 0.6
        selector:
          number:
            min: 0.0
            max: 1.0
            step: 0.05
            mode: box
      message_content:
        name: Berichten Inhoud
        description: De tekst die uitgesproken moet worden.
        required: true
        example: De droogkast is aangezet.
        selector:
          text:
    sequence:
      # STAP 1: Snapshot van huidig volume - Slaat het volume op in een tijdelijke variabele
      - variables:
          saved_volume_level: "{{ state_attr(media_player_entity_id, 'volume_level') | float(0) }}"
      # STAP 2: Mediaspeler inschakelen
      - service: media_player.turn_on
        target:
          entity_id: "{{ media_player_entity_id }}"
      # STAP 3: Tijdelijk volume instellen voor TTS
      - service: media_player.volume_set
        data:
          volume_level: "{{ tts_volume_level | float }}"
        target:
          entity_id: "{{ media_player_entity_id }}"
      # STAP 4: Het TTS bericht afspelen
      - service: tts.google_translate_say
        data:
          entity_id: "{{ media_player_entity_id }}"
          cache: false
          language: nl
          message: "{{ message_content }}"
      # STAP 5: Herstellen van het oorspronkelijke volume
      - service: media_player.volume_set
        data:
          volume_level: "{{ saved_volume_level }}"
        target:
          entity_id: "{{ media_player_entity_id }}"

When using the UI Script Editor you do not use the top_level key script… nor do you use the object id (tts_volume_restore) as a key.

Be aware that the UI Editors do not support comments, so all those will be removed if you ever go to review the script’s configuration. Use the alias key for each step if you want to keep them:

alias: "Dynamische TTS Met Volume Herstel"
description: "Speelt een bericht af op een gespecificeerde mediaspeler met tijdelijke volumeverhoging en herstelt daarna het volume."
fields:
  media_player_entity_id:
    name: Mediaspeler Entiteit ID
    description: De entity_id van de speler (bv. media_player.keuken).
    required: true
    example: media_player.aanrecht
    selector:
      entity:
        filter:
          - domain: media_player
  target_device_id:
    name: Doel Device ID (Optioneel)
    description: De device_id van de speler. Wordt gebruikt indien entity_id niet volstaat.
    required: false
    example: ab5694a6f25b783628746ee723a521e6
    selector:
      device:
        entity:
          - domain: media_player
  tts_volume_level:
    name: Tijdelijk TTS Volume
    description: Het volume tijdens de uitspraak (0.0 tot 1.0).
    required: true
    example: 0.6
    default: 0.6
    selector:
      number:
        min: 0.0
        max: 1.0
        step: 0.05
        mode: box
  message_content:
    name: Berichten Inhoud
    description: De tekst die uitgesproken moet worden.
    required: true
    example: De droogkast is aangezet.
    selector:
      text:
sequence:
  - alias: "STAP 1: Snapshot van huidig volume - Slaat het volume op in een tijdelijke variabele"
    variables:
      saved_volume_level: "{{ state_attr(media_player_entity_id, 'volume_level') | float(0) }}"
  - alias: "STAP 2: Mediaspeler inschakelen" 
    action: media_player.turn_on
    target:
      entity_id: "{{ media_player_entity_id }}"
  - alias: "STAP 3: Tijdelijk volume instellen voor TTS"
    action: media_player.volume_set
    data:
      volume_level: "{{ tts_volume_level | float }}"
    target:
      entity_id: "{{ media_player_entity_id }}"
  - alias: "STAP 4: Het TTS bericht afspelen"
    action: tts.google_translate_say
    data:
      entity_id: "{{ media_player_entity_id }}"
      cache: false
      language: nl
      message: "{{ message_content }}"
  - alias: "STAP 5: Herstellen van het oorspronkelijke volume"
    action: media_player.volume_set
    data:
      volume_level: "{{ saved_volume_level }}"
    target:
      entity_id: "{{ media_player_entity_id }}"
1 Like

Hi Didgeridrew,

Sorry, that was not the only error, it’s just so a generic message without line number or explanation.
Now I have the following code and won’t save:

tts_volume_restore:
  alias: "Dynamische TTS Met Volume Herstel"
  description: "Speelt een bericht af op een gespecificeerde mediaspeler met tijdelijke volumeverhoging en herstelt daarna het volume."
  fields:
    media_player_entity_id:
      name: Mediaspeler Entiteit ID
      description: De entity_id van de speler (bv. media_player.keuken).
      required: true
      example: media_player.aanrecht
      selector:
        entity:
          domain: media_player
    target_device_id:
      name: Doel Device ID (Optioneel)
      description: De device_id van de speler. Wordt gebruikt indien entity_id niet volstaat.
      required: false
      example: ab5694a6f25b783628746ee723a521e6
      selector:
        device:
          domain: media_player
    tts_volume_level:
      name: Tijdelijk TTS Volume
      description: Het volume tijdens de uitspraak (0.0 tot 1.0).
      required: true
      example: 0.6
      default: 0.6
      selector:
        number:
          min: 0.0
          max: 1.0
          step: 0.05
          mode: box
    message_content:
      name: Berichten Inhoud
      description: De tekst die uitgesproken moet worden.
      required: true
      example: De droogkast is aangezet.
      selector:
        text:
  sequence:
    # STAP 1: Snapshot van huidig volume - Slaat het volume op in een tijdelijke variabele
    - variables:
        saved_volume_level: "{{ state_attr(media_player_entity_id, 'volume_level') | float(0) }}"
    # STAP 2: Mediaspeler inschakelen
    - service: media_player.turn_on
      target:
        entity_id: "{{ media_player_entity_id }}"
     # STAP 3: Tijdelijk volume instellen voor TTS
    - service: media_player.volume_set
      data:
        volume_level: "{{ tts_volume_level | float }}"
      target:
        entity_id: "{{ media_player_entity_id }}"
    # STAP 4: Het TTS bericht afspelen
    - service: tts.google_translate_say
      data:
        entity_id: "{{ media_player_entity_id }}"
        cache: false
        language: nl
        message: "{{ message_content }}"
    # STAP 5: Herstellen van het oorspronkelijke volume
    - service: media_player.volume_set
      data:
        volume_level: "{{ saved_volume_level }}"
      target:
        entity_id: "{{ media_player_entity_id }}"

I already addressed that… maybe you missed the edit.

It’s line 1, tts_volume_restore: is not valid in the Script Editor.

You’re just missing a key piece of context…

By convention, configuration examples you see in the docs are written as if you are adding them directly to configuration.yaml. The Script and Automation Editors show a simplified configuration in the “Edit in YAML” view, because they are processed a bit differently.

1 Like

Thanks for you quick response, i’ll fix it.

The error is becomming more verbose: “Message malformed: extra keys not allowed @ data[‘fields’][‘target_device_id’][‘selector’][‘domain’]”.
It remembers my on writing Java with an elementery text editor and now I have IntelliJ Ultimate.

alias: "Dynamische TTS Met Volume Herstel"
description: "Speelt een bericht af op een gespecificeerde mediaspeler met tijdelijke volumeverhoging en herstelt daarna het volume."
fields:
  media_player_entity_id:
    name: Mediaspeler Entiteit ID
    description: De entity_id van de speler (bv. media_player.keuken).
    required: true
    example: media_player.aanrecht
    selector:
      entity:
        domain: media_player
  target_device_id:
    name: Doel Device ID (Optioneel)
    description: De device_id van de speler. Wordt gebruikt indien entity_id niet volstaat.
    required: false
    example: ab5694a6f25b783628746ee723a521e6
    selector:
      device:
        domain: media_player
  tts_volume_level:
    name: Tijdelijk TTS Volume
    description: Het volume tijdens de uitspraak (0.0 tot 1.0).
    required: true
    example: 0.6
    default: 0.6
    selector:
      number:
        min: 0.0
        max: 1.0
        step: 0.05
        mode: box
  message_content:
    name: Berichten Inhoud
    description: De tekst die uitgesproken moet worden.
    required: true
    example: De droogkast is aangezet.
    selector:
      text:
sequence:
  - variables:
      saved_volume_level: "{{ state_attr(media_player_entity_id, 'volume_level') | float(0) }}"
  - service: media_player.turn_on
    target:
      entity_id: "{{ media_player_entity_id }}"
  - service: media_player.volume_set
    data:
      volume_level: "{{ tts_volume_level | float }}"
    target:
      entity_id: "{{ media_player_entity_id }}"
  - service: tts.google_translate_say
    data:
      entity_id: "{{ media_player_entity_id }}"
      cache: false
      language: nl
      message: "{{ message_content }}"
  - service: media_player.volume_set
    data:
      volume_level: "{{ saved_volume_level }}"
    target:
      entity_id: "{{ media_player_entity_id }}"

That is telling you that the issue is in the configuration of the selector for your target_device_id variable. In this case it looks like you are missing the entity key that would allow you to use domain.

  target_device_id:
    name: Doel Device ID (Optioneel)
    description: De device_id van de speler. Wordt gebruikt indien entity_id niet volstaat.
    required: false
    example: ab5694a6f25b783628746ee723a521e6
    selector:
      device:
        entity:
          - domain: media_player

Personally, I would almost never use a device selector where an entity selector would work…

Entity Selector config
  target_device_id:
    name: Doel Device ID (Optioneel)
    description: De device_id van de speler. Wordt gebruikt indien entity_id niet volstaat.
    required: false
    example: ab5694a6f25b783628746ee723a521e6
    selector:
      entity:
        filter:   
          - domain: media_player

I finally solved my problems, this is the working script with a helper variable:

alias: Dynamische TTS with Volume restore
description: >-
  Plays a message on a specified media player with a temporary volume and
  restores the volume afterwards.
fields:
  media_player_entity_id:
    name: Mediaspeler Entiteit ID
    description: Entity_id of the player (bv. media_player.kitchen).
    required: true
    example: media_player.kitchen
    selector:
      entity:
        domain: media_player
  tts_volume_level:
    name: Tijdelijk TTS Volume
    description: Volume during the message (0.0 to 1.0).
    required: true
    example: 0.6
    default: 0.6
    selector:
      number:
        min: 0
        max: 1
        step: 0.05
        mode: box
  message_content:
    name: Message content
    description: The text.
    required: true
    example: The tumble dryer is now on.
    selector:
      text: null
sequence:
  - action: media_player.turn_on
    metadata: {}
    data: {}
    target:
      entity_id: "{{ media_player_entity_id }}"
  - action: input_number.set_value
    metadata: {}
    data:
      value: "{{ state_attr(media_player_entity_id, 'volume_level') | float(0) }}"
    target:
      entity_id: input_number.vorig_media_volume
  - action: media_player.volume_set
    metadata: {}
    data:
      entity_id: "{{ media_player_entity_id }}"
      volume_level: "{{ tts_volume_level | float }}"
    target:
      entity_id: "{{ media_player_entity_id }}"
  - action: tts.google_translate_say
    data:
      entity_id: "{{ media_player_entity_id }}"
      cache: false
      language: nl
      message: "{{ message_content }}"
  - wait_for_trigger:
      - value_template: "{{ is_state(media_player_entity_id, 'idle') }}"
        trigger: template
    timeout: "00:00:15"
  - data_template:
      volume_level: "{{ states('input_number.vorig_media_volume') | float(0) }}"
    target:
      entity_id: "{{ media_player_entity_id }}"
    action: media_player.volume_set