Home Assistant supports native types. That means it examines the appearance of a template’s output and infers its type. For example, this is understood to be a list and not a string:
[ 3, 6, 12 ]
In your example, the template’s output is understood to be a JSON object, not a string. However, the value for message must be a string and nothing else. That’s why it states:
template value should be a string for dictionary value @ data['message']
When you remove the leading brace, the resulting text can no longer be interpreted as a JSON object so it’s handled as a string (which is what is needed for message so that’s why there’s no error).
Although it’s possible to disable native types (in which case the output of templates is always handled as a string), it cannot be done on per template basis and applies to all templates.
{% raw %}{"temperature": {{temperature}}, "humidity": {{humidity}}}{% endraw %}
EDIT: never mind I see why that would be stupid.
How about this:
{% set temperature = states('input_number.temperature') %}
{% set humidity = states('input_number.humidity') %}
{% set out = {'temperature': temperature, 'humidity': humidity} %}
{{ out|to_json }}
Template editor likes it. But it wouldn’t be the first time that was misleading.
The technique used to infer the type doesn’t examine the template’s contents only its output.
That means it doesn’t matter if the template contains a final filter like string, int, float, etc to serve as a hint for the type we want, the conversion process only looks at the output and, based on its appearance, assigns a type.
For example, this template’s output will be handled as float regardless of the final string filter.
{{ 123.45 | string }}
With or without the final to_json the result is the same because it looks like a dictionary (dict) so its type is automatically assigned to be dict.
{% set temperature = states('input_number.temperature') %}
{% set humidity = states('input_number.humidity') %}
{% set out = {'temperature': temperature, 'humidity': humidity} %}
{{ out|to_json }}
(and also without to_json. It continues giving the same error: Failed to call service script/zz. template value should be a string` for dictionary value @data['message']
I’ve tried the message code in the developer tools → template and the output seems ok:
The output with to_json is: {"temperature": "21.0", "humidity": "34.0"}
and without to_json: {'temperature': '21.0', 'humidity': '34.0'}
The output is interpreted as being of type dict (dictionary) and not a string which is the only thing that is acceptable for message. There’s no way the JSON your template is producing will be interpreted as being a string as opposed to a dictionary (unless you disable native types which will then affect all templates).
If you have the time, look at the code for inferring the value’s type. If I recall correctly, they had to make exceptions for certain things because, when the evaluation technique was applied very strictly, it became counter-productive (kind of like in this situation).
One example that comes to mind is a string that looks like a hex value. The Sonoff RF Bridge transmits strings that sometimes can look like a hex value. However, that’s due to chance and is not meant to be converted to a numeric value.
I agree but it might be an exception. For example, try a list in the Template Sensor:
I carried out a simple experiment and escaped the meaning of the double-quotes. The following service call generates a notification without complaining that the result isn’t a string. In other words, it didn’t try to interpret the result as dict.
Here’s the resulting notification:
Therefore, try this version:
sequence:
- service: notify.file1
data:
message: >
{% set temperature = states('input_number.temperature') %}
{% set humidity = states('input_number.humidity') %}
{\"temperature\": {{temperature}}, \"humidity\": {{humidity}}}
mode: single
Well darn, I guess my use of notify.persistent_notification to test it was a bad choice. I can confirm that if I test it with notify.file1 I get the same result you did:
{ \"temperature\": 21.0, \"humidity\": 13.6 }
No error message but the escape character is passed on literally in the output.