Quick help with Notify and data_template (passing variables, Kodi)

So let’s make it real simple (i.e., get rid of templating) and see if it still works:

script:
  kodi_notification:
    sequence:
    - service: notify.kodi__atv
      data:
        title: "title"
        message: "message"
        data: {icon: "error", displaytime: 20000}

And if that fails:

script:
  kodi_notification:
    sequence:
    - service: notify.kodi__atv
      data:
        title: "title"
        message: "message"
        data:
          icon: "error"
          displaytime: 20000

Hmm, wait a sec! Reading the kodi notification doc page more closely, it says icon can be error, but you had error!. I wonder if that is what’s giving it a heartache???

Oh, never mind. Looks like you did have error the last time.

Yeah I noticed the ! so deleted it before I ran,

These two both worked fine though:

https://hastebin.com/ebijidinav.xml

https://hastebin.com/onebavikil.pl

(I changed the automation to ‘warning’ as well to avoid any issues and the notification showed the text from the script rather than the auto)

So it’s starting to sound like maybe the templating is the problem. E.g., notice this line from a previous log:

2018-07-12 19:30:20 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: domain=notify, service=kodi__atv, service_data=title=Xiaomi Cube Says, message=Ouch!, data=icon=error, displaytime=20000, service_call_id=1972992272-25>

But then just below:

2018-07-12 19:30:20 ERROR (MainThread) [homeassistant.core] Error executing service <ServiceCall notify.kodi__atv: title=<homeassistant.helpers.template.Template object at 0x73073870>, message=<homeassistant.helpers.template.Template object at 0x73073dd0>, data=icon=error, displaytime=20000>

Notice how title & message are pointing to template objects instead of the resulting strings (which showed up in the service call event line above)? Hmm.

How does this work (i.e., only use templates with title & message, and drop icon & displaytime for now):

script:
  kodi_notification:
    sequence:
    - service: notify.kodi__atv
      data_template:
        title: "{{ title }}"
        message: "{{ message }}"

Thats what I had when I first started playing with it :smiley:

Script: (working)
    kodi_notification:
      sequence:
      - service: notify.kodi__atv
    data_template:
        title: "{{ title }}"
        message: "{{ message }}"

Auto: (working)
action:
  service: script.turn_on
  entity_id: script.kodi_notification
  data:
    variables:
      title: 'Xiaomi Cube Says'
      message: 'Ouch!' 

I was hoping to be able to pull the icon and displaytime through the same way. Then I could quickly add a notify event to any automation and customize it directly in the automation itself,. Then send it through to a single Kodi notification script.

Was an idea I had and ran with, single script pulling in variables :slight_smile:

Ok, if that worked, then I’m pretty much stumped. data: {icon: "{{ icon }}", displaytime: "{{ displaytime}}"} should have worked, and in some ways it seemed to (in the logs you can see the values were substituted, and the result looked the same in the log entry for the service call as it did when icon & displaytime were hardcoded.)

Actually, I think the root cause of the problem is that you used “quick help” in the title of this topic! :wink:

Yeah, I noticed the same when I was a testing random stuff before properly logging them. That lead me down the ‘must be syntax’ line of thinking but saw the same with a fresh pair of eyes on it.

Maybe its just the Kodi notify component thats a little wonky, I might try and set another notify up on a different service and see if I can replicate.

1 Like

Just thinking outside the box:

Is there a service that I can run in a separate script to read the variables set in the automation as just ‘variables’ , which then the notify script can pull in from that that script?

ie:

Auto
...
    action:
      service: script.turn_on
      entity_id: script.kodi_notification_setup
      data:
        variables:
          title: 'Xiaomi Cube Says'
          message: 'Ouch!'
          icon: 'warning'          
          displaytime: 500



kodi_notification_setup:
    sequence:
    - service: **"Something that will read the variables passed from the automation"**
      data_template:
        title: "{{ title }}"
        message: "{{ message }}"
        icon: "{{ icon }}"
        displaytime: "{{ displaytime }}"

kodi_notification:
    sequence:
    - service: notify.kodi__atv
      data_template: < Pulls from kodi_notification_setup
        title: "{{ title }}"
        message: "{{ message }}"
        icon: "{{ icon }}"
        displaytime: "{{ displaytime }}"

Might bypass the issue as we know the script will send out the info if its not pulling the variable form the data in the automation?

I think you’re going to suffer from the same problem. When you call the notify service, you’ll still have to use templates to get the data. It doesn’t matter if you’re referencing variables of the script, or pulling the state of something from the state machine. And, BTW, you still need to have icon & displaytime under another data item.

FWIW, I looked at the docs for every notify platform, as well as various general examples, and I didn’t find one that used data_template where the values under data (as in data_template -> data -> xxx) used templates. Hmm.

If you’re feeling brave, you might try making a minor modification to the kodi notification platform code that will output more useful info to the log. This is what I’d do. E.g., copy kodi.py from the HA notify directory into a directory under your HA configuration directory. To be specific, copy:

/usr/lib/python3.6/site-packages/homeassistant/components/notify/kodi.py

to:

your_config_dir/custom_components/notify/kodi.py

where “your_config_dir” is the directory containing your configuration.yaml file.

Modify the following function at the end of the file:

    @asyncio.coroutine
    def async_send_message(self, message="", **kwargs):
        """Send a message to Kodi."""
        import jsonrpc_async
        try:
            data = kwargs.get(ATTR_DATA) or {}

            displaytime = data.get(ATTR_DISPLAYTIME, 10000)
            icon = data.get(ATTR_ICON, "info")
            title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
            yield from self._server.GUI.ShowNotification(
                title, message, icon, displaytime)

        except jsonrpc_async.TransportError:
            _LOGGER.warning("Unable to fetch Kodi data. Is Kodi online?")

by inserting a call to _LOGGER.debug right before the call to ShowNotification(). I.e.:

    @asyncio.coroutine
    def async_send_message(self, message="", **kwargs):
        """Send a message to Kodi."""
        import jsonrpc_async
        try:
            data = kwargs.get(ATTR_DATA) or {}

            displaytime = data.get(ATTR_DISPLAYTIME, 10000)
            icon = data.get(ATTR_ICON, "info")
            title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
            # Dump parameters to log...
            _LOGGER.debug('title="{}", message="{}", icon="{}", displaytime={}'.format(
                title, message, icon, displaytime))
            yield from self._server.GUI.ShowNotification(
                title, message, icon, displaytime)

        except jsonrpc_async.TransportError:
            _LOGGER.warning("Unable to fetch Kodi data. Is Kodi online?")

After you’re done using this you can just delete this file (or the whole your_config_dir/custom_components/notify directory if you’re not using it for anything else.)

So, started looking at the code shown in the exceptions. Specifically, jsonrpc_async/jsonrpc.py and jsonrpc_base/jsonrpc.py. Here is an interesting part of the exception:

{'message': 'Invalid type string received', 'name': 'displaytime', 'type': 'integer'}

Seems like the server is saying that it expected an integer for displaytime, but it got a string. Hmm. That’s a problem for jinja, I think. Although it can operate with numbers, its final output (i.e., what comes out of "{{ ... }}") is going to be a string every time. At least, I think.

Maybe modify that kodi.py file like this:

    @asyncio.coroutine
    def async_send_message(self, message="", **kwargs):
        """Send a message to Kodi."""
        import jsonrpc_async
        try:
            data = kwargs.get(ATTR_DATA) or {}

            displaytime = int(data.get(ATTR_DISPLAYTIME, 10000))
            icon = data.get(ATTR_ICON, "info")
            title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
            yield from self._server.GUI.ShowNotification(
                title, message, icon, displaytime)

        except jsonrpc_async.TransportError:
            _LOGGER.warning("Unable to fetch Kodi data. Is Kodi online?")

I.e., force displaytime to be an integer.

I think you had it pretty close, but the real isssue is probably this: {'message': 'Invalid type string received', 'name': 'displaytime', 'type': 'integer'}.

I’m guessing that the service expects displaytime to be an integer, but the template will always render it as a string. You could try something like displaytime: "{{ displaytime | int }}" to try to get it to be passed as an integer, but I’m not entirely sure if that will work.

1 Like

LOL! I agree, it won’t wok. But I think my suggestion of changing the code might. Maybe this is something that should be done in the released code, but not sure how to even suggest that.

Looks like we noticed the same thing at the same time. On https://github.com/home-assistant/home-assistant/issues/8977#issuecomment-337370781 I mentioned a workaround for passing an array to a different notify platform. For whatever reason, passing it through an intermediate script allowed it to be properly treated as an array.

Something like this:

script:
  kodi_notification:
    sequence:
    - service: script.send_kodi_notification
    data_template:
      title: "{{ title }}"
      message: "{{ message }}"
      data:
        icon: "{{ icon }}"
        displaytime: "{{ displaytime }}"

  send_kodi_notification:
    sequence:
    - service: notify.kodi__atv

automation:
  action:
    service: script.turn_on
    entity_id: script.kodi_notification
    data:
      variables:
        title: 'Xiaomi Cube Says'
        message: 'Ouch!'
        icon: 'error'
        displaytime: 20000

The automation sends the variables to kodi_notification which then renders the templates and forwards them to send_kodi_notification which then sends the notification. At the time I tried this, any variables from one script automatically got passed on to another, so the second script didn’t need to include them. I’m not sure if that’s still the way it works though.

This was the way my thinking was headed.

Got it all written up but stupidly decided to flash my Pi3b+ with HassOS and have to revert back to my Pi3 as not everything is working right yet and dont have the time tonight to play :expressionless:

Will have to have a crack tomorrow when Pi3 is back up and running.

That’s very interesting. If it works then it’s by “magic.” I mean there must be some unexpected, undocumented feature. I really can’t see how a script having variables automatically makes them part of a service call, exactly how it needs to be.

So, the below is working nicely. I can pass title, message and icon through no problem. The issue is definately the displaytime.

Auto:
  - alias: Cube Fall - Notify (xcubebedroom)
    trigger:
      platform: mqtt
      topic: 'zigbee2mqtt/xrb1bedroom'
    condition:
      condition: template
      value_template: "{{ 'single' == trigger.payload_json.click }}"
    action:
      service: script.turn_on
      entity_id: script.kodi_notification_setup
      data:
        variables:
          title: 'Xiaomi Cube Says'
          message: 'Ouch!'
          icon: 'error'          
          displaytime: 5000

Script1:
kodi_notification_setup:
   sequence:
    - service: script.kodi_notification
      data_template:
        title: "{{ title }}"
        message: "{{ message }}"
        icon: "{{ icon }}"
        #displaytime: "{{ displaytime | int }}"

Script2:
kodi_notification:
    sequence:
    - service: notify.kodi__atv
      data_template:
        title: "{{ title }}"
        message: "{{ message }}"
        data:
          icon: "{{ icon }}"
          #displaytime: "{{ displaytime | int }}"

Ive tried several formats (string, int etc) on every part of it all but I always get:

{‘message’: ‘Invalid type string received’, ‘name’: ‘displaytime’, ‘type’: ‘integer’}}, ‘message’: ‘Invalid params.’}

So, does that mean that the displaytime is being passed as an integer or is it expecting an integer and getting a string?

No matter what you do, a jinja template is always going to output a string, period. The reason it works (i.e., the string is converted to a number) in some cases is because of schemas in the code. They can coerce a string into a number. But in this case, there’s no schema to do that.

That is why I suggested modifying the code itself. Specifically in this message:

BTW, that means the kodi server is getting a command that contains a value for displaytime that is a string when it wants an integer.

That’s brill, sorry I did read that last night and forgot!

At least we know where the issue lies!

I might have a play with the code over the weekend but for now being able to pass most of the notification detail through is awesome :slight_smile: