I'm trying to use a mustache template inside a change (or function) node and can't get it to work

This doesn’t work. What am I doing wrong here?

Before this node msg.topic is a pet’s name. I’m trying to get that into a format that I can send to MQTT.

image

Use the call service node select mqtt publish. Then hit load example, it will give a message example. Change as necessary.

Thanks. I did that, but it seems I can’t ‘update’ the topic from inside the service call then? This is the message I tried to use. But what gets sent to MQTT is what the topic was before (just pet’s name).

{
   "topic":"/homeassistant/sensor/pethub/pet_{{topic}}/state",
   "payload":"{{payload}}"
}

Take a look at this flow

[{"id":"336bb951.7b1376","type":"inject","z":"d6a46901.ebee1","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"tom","payloadType":"str","x":590,"y":660,"wires":[["e9c9c276.80058"]]},{"id":"e9c9c276.80058","type":"api-call-service","z":"d6a46901.ebee1","name":"","server":"","version":3,"debugenabled":false,"service_domain":"mqtt","service":"publish","entityId":"","data":"{\"topic\":\"/homeassistant/hello\",\"payload_template\":\"{{ payload }} is home now\",\"qos\":2,\"retain\":1}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":990,"y":660,"wires":[[]]}]
1 Like

FYI mustache templating isn’t universal in Node RED. Mustache templates are only supported in specific places in the Home Assistant nodes and in the template node. There’s no way to use a mustache template in a change node.

Now looks like some alternatives have been presented with MQTT so your problem may be solved. But for future reference if you find yourself in a similar situation you can either drop in a template node (which then supports rendering mustache templates and storing the value in the msg) or in your change node switch to the jsonata option and do something like this:

'/homeassistant/sensor/pethub/pet_' & topic & '/state'

Or you can always use a function node since that’s just js and then something like this works:

msg.topic = `/homeassistant/sensor/pethub/pet_${topic}/state`

But probably good to get the hang of jsonata as its pretty ubiquitous throughout node red, most nodes don’t have any other option to do something like this.

1 Like

This is one of the node red idiosyncrasy where either jsonata or java is the real stable option. I have never been able to get it to work right.

According to the docs you should be able to use a change node to set an environmental variable and then recall it with $env{saved_var_name}. If I use this for the above example I wind up with

$env{pet} is home now
[{"id":"336bb951.7b1376","type":"inject","z":"d6a46901.ebee1","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"tom","payloadType":"str","x":550,"y":620,"wires":[["c97e6830.384dd8"]]},{"id":"c97e6830.384dd8","type":"change","z":"d6a46901.ebee1","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"pet","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":560,"wires":[["e9c9c276.80058"]]},{"id":"e9c9c276.80058","type":"api-call-service","z":"d6a46901.ebee1","name":"","server":"","version":3,"debugenabled":false,"service_domain":"mqtt","service":"publish","entityId":"","data":"{\"topic\":\"/homeassistant/hello\",\"payload_template\":\"$env{pet} is home now\",\"qos\":2,\"retain\":1}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":990,"y":660,"wires":[[]]}]

https://nodered.org/docs/user-guide/environment-variables

Ah, yea environmental variables are funny, I learned about that syntax only recently. The way it works is this, in any place that accepts plain ol’ text you can put ${ENV_VAR_NAME} and it will use the value of that environmental variable instead. This is most commonly used in subflows because you reference input values as environmental variables.

But I do need to clarify a couple things, the syntax is ${ENV_NAME} not $env{ENV_NAME}. Also as the linked doc notes

This only works if it replaces the entire property - it cannot be used to substitute just part of the value. For example, it is not possible to use CLIENT-${HOST}

And to my knowledge there is no way to set and then retrieve an environmental variable as part of a flow. Even in function nodes you can see they only have env.get(…) API, there is no env.set. Any values for environmental variables are set on or before deploy, I don’t believe there’s any way to modify them as part of the runtime of a flow. You can only modify data in the msg, node, flow or global contexts as part of the runtime of a flow.

1 Like