Problem with creating a JSON-like string message in notify automation

Hello there!
Could you please give me a hand and tell me how to make it work?
I’m trying to make a message in json-like format format but always get an error:

"Error while executing automation automation.zapisz_zuzycie_energii_dzienne: template value should be a string for dictionary value @ data['message']"

automations.yaml:

- alias: zapisz_zuzycie_energii_dzienne
  initial_state: 'on'
  trigger:
    - platform: time
      at: '23:59:55'
  action:
    - service: notify.zapisz_energia_dzienna
      data_template: 
        message: >
          { "date": 2021, "energy": {{ states("sensor.daily_energy") }} }

What I’m trying to achieve is a string:

{ "date": 2021, "energy": 10.57 }

Thanks a lot…

Too many brackets.

service: notify.mobile_app_gphone
data:
  message: >-
    {{states['sensor.time'].state}} Air Quality is
    {{states('sensor.purpleair_description') }} at AQI
    {{states('sensor.purpleair_aqi_a')}}
service: notify.mobile_app_gphone
data:
  message: >-
    Air Quality is {{ states('sensor.purpleair_description') }} at AQI {{
    states('sensor.purpleair_aqi_a') }}

Only the sensor states are inside {}, text is in the open

He wants those brackets {} in the message.

Hello and thank you for your answer.
Yes, I wish that brackets were in the string.

I’ve tried also with replacing special chars { " and ’ with its HEX equivalent, but also without success.
In template editor most of those tries are correct, but in automation always get an error.

- alias: zapisz_zuzycie_energii_dzienne
  initial_state: 'on'
  trigger:
    - platform: time
      at: '23:59:55'
  action:
    - service: notify.zapisz_energia_dzienna
      data_template: 
        message: "{ \"date\": 2021, \"energy\": {{ states('sensor.daily_energy') }} }"

I think. But think it’s easier to use the to_json filter

- alias: zapisz_zuzycie_energii_dzienne
  initial_state: 'on'
  trigger:
    - platform: time
      at: '23:59:55'
  action:
    - service: notify.zapisz_energia_dzienna
      data_template: 
        message: "{{ {'date': 2021, 'energy': states('sensor.daily_energy')}|to_json }}"

Try this:

  action:
    - service: notify.zapisz_energia_dzienna
      data_template: 
        message: >
          {% set energy_value = states("sensor.daily_energy") %}
          {% set msg = { "date": 2021, "energy": energy_value } %}
          {{ msg }}

Thank you friends for your comments! I’m new to HA and I really apprietiate your help…

No luck so far, always get this same error.

So far the closest to answer is following code, but without the comma char after year value:

      data_template:
        message: >
          {
          "date": {{ now().year }}
          "energy": {{ states("sensor.daily_energy") }}
          }

Then I get the following, but it can’t be read as json…

{ "date": 2021 "energy": 15.43 }

I suggest you give my second snippet a try. I very much doubt it will give you the same error… In the template dev tool it works flawless :slight_smile:

I did copy-paste your code and got:

Error while executing automation automation.zapisz_zuzycie_energii_dzienne: template value should be a string for dictionary value @ data['message']
23:38:10 – Automatyzacja (ERROR)
zapisz_zuzycie_energii_dzienne: Error executing script. Invalid data for call_service at pos 1: template value should be a string for dictionary value @ data['message']
23:38:10 – Automatyzacja (ERROR)

Edit:
I found a simmilar thread, where Petro gives a solution.

After editing I got:

        message: >
          {% set d = now().year %}
          {% set v = states("sensor.daily_energy") %}
          {"date":{{d}},"y":3,"txt":"energy":{{v}}}

Above works well, but when I delete the middle and change it to simple:

        message: >
          {% set d = now().year %}
          {% set v = states("sensor.daily_energy") %}
          {"date":{{d}},"energy":{{v}}}

I get an error again!! I’m confused…

Don’t know know what’s happening, I suspect a copy-past error. I just made a simple test and it works flawless:

alias: Test
description: ''
trigger:
  - platform: homeassistant
    event: start
condition: []
action:
  - service: persistent_notification.create
    data:
      message: >-
        {{ {'date': 2021, 'energy':
        states('input_datetime.pantry_litter_box_done')}|to_json }}
      notification_id: test
mode: single

Made it in the UI which insisted on this multi-line string layout. But it’s basically the same.

Still nothing… Does it matter that the notify I use:

    - service: notify.zapisz_energia_dzienna

uses platform “file” to write string to a file?

notify:
  - platform: file
    name: zapisz_energia_dzienna
    filename: historia_energia_dzienna.txt

Using above scripts I can write to a file:

'{"date":"2021-04-09","energy":12.52}'

but no the following (same as above, but without first and last char which is single quote)

{"date":"2021-04-09","energy":12.52}

Edit:
Thank you septillion for your suggestion, I’ve added second action to this automation and make persistent notification. The result is the same as above, persistent notification works with additional single quotes at the beginning and the end, but doesnt work without it.

- alias: zapisz_zuzycie_energii_dzienne
  initial_state: 'on'
  trigger:
    - platform: time
      at: '23:59:55'
  action:
  - service: notify.zapisz_energia_dzienna
    data_template:
      message: >-
        {% set d = now().strftime("%Y-%m-%d") %}
        {% set e = states("sensor.daily_energy") %}
        '{'date':'{{d}}','energy':{{e}}}'
  - service: persistent_notification.create
    data:
      message: >-
        '{{ {'date': 2021, 'energy':
        states('sensor.daily_energy')}|to_json }}'
      title: "Zużycie energii"

I think the problem is that the Jinja2 template enging outputs a dict whenever it sees a valid json or a dict, quoted or not, so however you would create the output, Jinja2 converts it back to a dict which is evident if you test it in the template editor, and you need it to be a string to work with notify. As a last resort, you could try calling notify with a python_script instead:

energy = hass.states.get("sensor.daily_energy").state
msg = {"date": 2021, "energy": float(energy)}
hass.services.call("notify", "zapisz_energia_dzienna", service_data={"message": str(msg).replace("'",'"')})

This would send a proper json string as the message.

message always requires a string, so complex types cause issues. If it’s just a persistent notification, just add any character in front of it.

  - service: persistent_notification.create
    data:
      message: >-
        x {{ {'date': 2021, 'energy': states('sensor.daily_energy')}|to_json }}
      title: "Zużycie energii"

You can also just create a table

  message: >-
    <tr><th>attr</th><th>value</th></tr>
    <tr><td align="center">date</td><td align="center">2021</td>/<tr>
    <tr><td align="center">energy</td><td align="center">{{states('sensor.daily_energy')}}</td>/<tr>

Thank you tjntomas, this actually works fine! :slight_smile:

Great! But a real shame that we can’t get it working with a template. It would be helpful with a to_string template extension filter.

That wouldn’t make a difference because typing is handled after the template is resolved and the to_string wouldn’t be seen. Also, the | string filter already exists.

Yes, I noted that the string filter has no effect if the output is treated as any other object, such as a dict in this case.

Then I’m not sure what you meant by your

comment

Other Jinja2 implementations that I have seen has a .str function that actually outputs a string from any object, but that might not be possible to implement here.

that’s what | string does. This is what I was explaining to you. |string converts any output to a string. The problem is that value that gets passed from the template into a ‘typing resolver’ and that changes it to whatever is discovered.

1 Like