Use variable in kodi.call_method

How would one use a variable in kodi.call_method service so that it is passed to event kodi_call_method_result

I’ve tried several ideas but I can’t seem to find a way to pass a variable through it without success

        variables:
          is_kitchen: 'yes'

I can use trigger.event.data.entity_id with 2 media entities (media_player.) as it’s easy to just refer to the other but when introducing a third entity(media_player.) the logic appears to require a nested if function using a variable (is_kitchen:) to have more than 2 media_player entities.

Please see below for an example

automation: 

alias: "Kodi - On get playing event"
  initial_state: 'on'
  trigger:
    - platform: event
      event_type: kodi_call_method_result
      event_data:
        result_ok: true
        input:
          method: Player.GetItem
  action:
    - service: script.turn_on
      data:
        variables:
          file: "{{ trigger.event.data.result.item.file }}"
          entity_to: >-
            {%- if is_kitchen == 'yes' %}
              media_player.khtpc
            {%- else %}
              {%- if trigger.event.data.entity_id == 'media_player.lhtpc' %}
                media_player.bhtpc
              {%- elif trigger.event.data.entity_id == 'media_player.bhtpc' %}
                media_player.lhtpc
              {% endif -%}
            {% endif -%}
          entity_from: "{{ trigger.event.data.entity_id }}"
      entity_id: script.kodi_set_playing
  mode: single


script:

  kodi_get_playing_from_bedroom:
    alias: "kodi get playing from bedroom"
    sequence:
      - service: kodi.call_method
        data:
          method: Player.GetItem
          playerid: 1
          properties:
            - file
        variables:
          is_kitchen: 'yes'
        entity_id: media_player.bhtpc

thanks

As others have pointed out the original post was lacking and seeing as telepathy hasn’t been mastered yet I’ll attempt to provide detail of what I’m trying to achieve.

I have 3 media players running kodi:

media_player.lhtpc - (lounge)
media_player.bhtpc - (bedroom)
media_player.khtpc - (kitchen)

When I run a script(or call it via echodot) based on what media is playing and on what media_player I would like it to get that data and apply to another media player.

Using logic the below script makes a decision what media player to get the kodi playing data from the media player that is currently being watched. Then calls another script to make the kodi api call via the event platform. The below script also declares a variable “is_kitchen: yes” which appears to be needed due to the way the services “kodi.call_method” and “kodi.call_method_result” events work. The reason this variable (I think) is needed will be explained below.

E.g.

  going_to_kitchen:
    alias: "Going to kitchen"
    sequence:
#      - service: homeassistant.turn_on
#        data:
#          entity_id: switch.kitchen_watch_htpc
      - wait_template: "{{ states('media_player.khtpc') == 'idle' or states('media_player.khtpc') == 'playing' }}"
        timeout: '00:00:45'
      - service: script.turn_on
        data:
          variables:
            is_kitchen: 'yes'
          entity_id: >-
            {%- if ( states('media_player.lhtpc') == 'idle' or states('media_player.lhtpc') == 'playing' ) and ( states('media_player.bhtpc') == 'idle' or states('media_player.bhtpc') == 'playing' ) %}
              script.kodi_get_playing_from_lounge
            {%- elif states('media_player.bhtpc') == 'idle' or states('media_player.bhtpc') == 'playing' %}
              script.kodi_get_playing_from_bedroom
            {% else %}
              script.kodi_get_playing_from_lounge
            {% endif -%}

In this example we assume media is being played from media_player.bhtpc therefore the script “script.kodi_get_playing_from_bedroom” is run (shown below):

kodi_get_playing_from_bedroom:
    alias: "kodi get playing from bedroom"
    sequence:
      - service: kodi.call_method
        data:
          method: Player.GetItem
          playerid: 1
          properties:
            - file
        variables:
          is_kitchen: "{{ is_kitchen }}"
        entity_id: media_player.bhtpc

This doesn’t work because variables: isn’t accepted by “service: kodi.call_method” and results in a incorrect api call made to kodi and an error.
Variables needs? to be part of “service: kodi.call_method” as it needs to be pass the automation which runs on the event " event_type: kodi_call_method_result". It needs to be passed to the below automation. I do not know how to do this.
The automation is:

automation: 

alias: "Kodi - On get playing event"
  initial_state: 'on'
  trigger:
    - platform: event
      event_type: kodi_call_method_result
      event_data:
        result_ok: true
        input:
          method: Player.GetItem
  action:
    - service: script.turn_on
      data:
        variables:
          file: "{{ trigger.event.data.result.item.file }}"
          entity_to: >-
            {%- if is_kitchen == 'yes' %}
              media_player.khtpc
            {%- else %}
              {%- if trigger.event.data.entity_id == 'media_player.lhtpc' %}
                media_player.bhtpc
              {%- elif trigger.event.data.entity_id == 'media_player.bhtpc' %}
                media_player.lhtpc
              {% endif -%}
            {% endif -%}
          entity_from: "{{ trigger.event.data.entity_id }}"
      entity_id: script.kodi_set_playing

This makes a decision based on the variables “is_kitchen” , “entity_to” and “entity_from” then calls the script “script.kodi_set_playing” (below):

 kodi_set_playing:
    alias: "kodi set playing"
    sequence:
      - service: kodi.call_method
        data:
          method: Player.Open
          item:
            file: "{{ file }}"
          entity_id: "{{ entity_to }}"
      - delay: '00:00:02'
      - service: kodi.call_method
        data:
          method: Player.Seek
          value:
            seconds: "{{ state_attr(entity_from, 'media_position') | int - 120 }}"
          playerid: 1
          entity_id: "{{ entity_to }}"
      - service: media_player.media_pause
        data:
          entity_id: "{{ entity_to }}"
      - service: media_player.media_play
        data:
          entity_id: "{{ entity_from }}"

WHY is the variable “is_kitchen:” needed? (I think) because of having to using “service: kodi.call_method_result”.
From the AUTOMATION:

              {%- if trigger.event.data.entity_id == 'media_player.lhtpc' %}
                media_player.bhtpc
              {%- elif trigger.event.data.entity_id == 'media_player.bhtpc' %}
                media_player.lhtpc
              {% endif -%}

works fine as there is only 2 entities/media_players but adding a third causes a problem because the entity_to: variable could be 1 of 3 media_players which, due to requiring the kodi.call_method_result event to get data from the kodi api call, it needs? the variable is_kitchen: in a nested if statement work in the automation “Kodi - On get playing event”

Due to this and the source media_player, the logic if elsif else doesn’t work?

This single script will do it. Utilize wait for trigger without an automation so you can keep the context.

  pass_kodi_content_to_other_device:
    alias: "Going to any other."
    mode: single
    fields:
      player:
        description: Target another kodi player with playing content
        example: media_player.khtpc
    variables:
      players:
      - media_player.lhtpc
      - media_player.bhtpc
      - media_player.khtpc
      source: >
        {% set media_players = expand(players) | rejectattr('entity_id', 'eq', player) | selectattr('state','in',['idle', 'playing']) | list %}
        {{ media_players | first if media_players | length > 0 else none }}
    sequence:
    - condition: template
      value_template: "{{ player is defined and source is not none }}"
    - service: kodi.call_method
      target:
        entity_id: "{{ source }}"
      data:
        method: Player.GetItem
        playerid: 1
        properties:
          - file
    - wait_for_trigger:
      - platform: event
        event_type: kodi_call_method_result
        event_data:
          result_ok: true
          input:
            method: Player.GetItem
      timeout:
        minutes: 1
      continue_on_timeout: false
    - service: kodi.call_method
      target:
        entity_id: "{{ player }}"
      data:
        method: Player.Open
        item:
          file: "{{ wait.trigger.event.data.result.item.file }}"

Then make 3 scripts for each of your alexa calls

  going_to_kitchen:
    alias: "Going to kitchen"
    sequence:
    - service: script.pass_kodi_content_to_other_device
      data:
        player: media_player.khtpc

... etc ...

Thank you Petro.

The “source” variable needed to have the filter map(attribute=‘entity_id’) added to return the entity_id

{% set media_players = expand(players) | rejectattr('entity_id', 'eq', player) | selectattr('state','in',['idle', 'playing']) | map(attribute='entity_id') | list %}

There seems to be a problem with the wait_for_trigger: template.

The wait trigger template times out for some reason but the “kodi_call_method_result” is called…
I can see it the event debug:

Event 7 fired 10:29 PM:

{
    "event_type": "kodi_call_method_result",
    "data": {
        "entity_id": "media_player.bhtpc",
        "result": {
            "item": {
                "file": "nfs://storage.blah.com/export/data/tv/Severance/Season 1/Severance S01E03 In Perpetuity.mkv",
                "id": 10244,
                "label": "In Perpetuity",
                "type": "episode"
            }
        },
        "result_ok": true,
        "input": {
            "method": "Player.GetItem",
            "params": {
                "playerid": 1,
                "properties": [
                    "file"
                ]
            }
        }
    },
    "origin": "LOCAL",
    "time_fired": "2022-03-20T11:29:59.349855+00:00",
    "context": {
        "id": "adcd61992ec3b9abda277b506bcc591e",
        "parent_id": null,
        "user_id": null
    }
}

Event 6 fired 10:29 PM:

{
    "event_type": "call_service",
    "data": {
        "domain": "kodi",
        "service": "call_method",
        "service_data": {
            "method": "Player.GetItem",
            "playerid": 1,
            "properties": [
                "file"
            ],
            "entity_id": [
                "media_player.bhtpc"
            ]
        }
    },
    "origin": "LOCAL",
    "time_fired": "2022-03-20T11:29:59.342225+00:00",
    "context": {
        "id": "8c631b19ca986197590fd79efc26e364",
        "parent_id": null,
        "user_id": "6ee597e998514a70afb9ad540b632b6b"
    }
}

Terminal home_assistant.log:
2022-03-20 23:31:10 INFO (MainThread) [homeassistant.components.script.pass_kodi_content_to_other_device] pass_kodi_content_to_other_device: Executing step wait for trigger (timeout: 0:01:00)
2022-03-20 23:31:10 INFO (MainThread) [homeassistant.components.script.pass_kodi_content_to_other_device] pass_kodi_content_to_other_device: Initialized trigger
2022-03-20 23:32:10 INFO (MainThread) [homeassistant.components.script.pass_kodi_content_to_other_device] pass_kodi_content_to_other_device: Timeout reached, abort script.

If I change continue_on_timeout: false to continue_on_timeout: true is confirms the wait_for_trigger: is not working:
2022-03-20 22:30:02 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [139808871776800] Error rendering data template: UndefinedError: ‘None’ has no attribute ‘event’

subscribe to call_method and look at the timing of the script and the timing of the events. It’s possible the response is coming in before we are waiting for it.

Change the script to

  pass_kodi_content_to_other_device:
    alias: "Going to any other."
    mode: single
    fields:
      player:
        description: Target another kodi player with playing content
        example: media_player.khtpc
    variables:
      players:
      - media_player.lhtpc
      - media_player.bhtpc
      - media_player.khtpc
      source: >
        {% set media_players = expand(players) | rejectattr('entity_id', 'eq', player) | selectattr('state','in',['idle', 'playing']) | list %}
        {{ media_players | first if media_players | length > 0 else none }}
    sequence:
    - condition: template
      value_template: "{{ player is defined and source is not none }}"
    - service: kodi.call_method
      target:
        entity_id: "{{ source }}"
      data:
        method: Player.GetItem
        playerid: 1
        properties:
          - file
    - wait_for_trigger:
      - platform: event
        event_type: pass_the_file
        event_data:
          source: "{{ source }}"
      timeout:
        minutes: 1
      continue_on_timeout: false
    - service: kodi.call_method
      target:
        entity_id: "{{ player }}"
      data:
        method: Player.Open
        item:
          file: "{{ wait.trigger.event.data.result.item.file }}"

And add this automation

- alias: pass the file
  mode: parallel
  trigger:
      - platform: event
        event_type: kodi_call_method_result
        event_data:
          result_ok: true
          input:
            method: Player.GetItem
  action:
  - delay:
      milliseconds: 200
  - event: pass_the_file
    event_data:
      source: "{{ trigger.event.data.entity_id }}"
      file: "{{ trigger.event.data.result.item.file }}"
1 Like

Had to change the last service block to file: “{{ wait.trigger.event.data.file }}” to use the cariable from the custom event you created and increase the delay to 500 milliseconds(could just be my testing).

With the other above changes it works.

I wonder if you put them broken in there for the learning experience… which was enjoyable, after frustration :slight_smile:.

Thanks @petro

:rofl: no I did not, glad you figured it out though