Subflows - passing payload or other properties via environment variable?

Hi folks! Here's my scenario: I'm building automations in Home Assistant, I want to create a reusable function so that any time I want to send a mobile notification, I can use the same set of nodes.

I can build this easily using a link out- create a flow that does all this work, and just use link out to link to it. It seems that on paper, reusing nodes as functions feels more like the job of a subflow, so I ported everything to a subflow. I then set environment variables such that I can pass the title of the notification, the message etc. So far so good. But I can't inject something like msg.payload into an environment variable. Why is that? Is it because it's set at compile time or similar? Basically whatever I try it doesn't seem I can set it dynamically.

Of course msg.payload flows down to the subflow anyway, so I can just call it from the other end, but from a documentation point of view it'd be nicer to have a single notification subflow node, with all the environment variables set. Otherwise I need at least 2: one to set msg.payload, then one to access the subflow.

You pass data to a subflow or a linked flow as a message. Why do you feel that environment variables are more appropriate than msg.subject, msg.to, msg.payload (etc)?

I presume that @SiDtheTurtle is talking about the use of subflow properties, which are pseudo env vars.

Quite likely, but I do wonder why s/he assumes they are more appropriate than message properties. Of course, he might be right!

I don't use subflows, only because they occupy the top of the editor palette column.
I doubt if this is a good reason to spurn them, so I'm interested to learn more.

@SiDtheTurtle, subflow properties are useful where each instance of a subflow requires a set of fixed values. If you want to pass in values that vary each time you pass a message to the subflow then use message properties, such as msg.payload.

All good points. I guess it works, it's just I'm sending half the inputs via environment variables (sorry, yes I mean subflow properties), half via messages.

Let's take an example of the front door being opened. So I set the notification title environment variable to 'Doors' and the msg.notification_message (or whatever) to "{{entity name}} has been opened!". Of course when I'm setting the notification message I could set say msg.title to 'Doors', not use any environment variables and it's be cleaner. I guess I was just hoping I could have a single node (made up of a sub node) that I could drop in, set some environment variables and it'd work.

Do you have another instance of the subflow where the title is, for example, Windows?

Can you give some examples of what entity name is?

Here's an example that might help. It's very Home Assistant specific, but I guess the question is generic:

I have two hose valves that control the soaker hose for the hedge and the pool top up. I turn these on by hand (or app), but often forget to switch them off. So I built a simple flow that triggers if the valve has been on for a set time, and switches them off:

For both hoses, I want to send a mobile notification. In the teal green node (a sub flow), I set the environment variables as follows:

Those three elements that say 'Water' are fed into the sub flow and used to build the JSON message that's pushed to the HA app. That's static, easy enough. The message however, needs to be dynamic, so I build that in the gold change node in the middle:

So now some of the fields are set by environment variable, some by msg.message. But not always, on other flows the message is static so I can use an environment variable. So in my subflow, I have a convoluted set of switches and functions to check if the environment variable has been set, if not, check the message, if not, fail.

My goal is to have a generic sub flow I can drop in everywhere, seeing as I see mobile notifications being core to my development.

I guess you could argue I need to set up all of these parameters as tags, labels etc. at source (Home Assistant), then pull them through in the payload and decode it in the sub flow?

Hey @SiDtheTurtle.

Looking at your last post.

The second picture where you have the names.... Water, Water, Water... as the title, message and channel.

In the next picture you are showing a change node.

You lost me where the change node is.
Is it in the subflow?

The line is using context.
Shouldn't it be env if it is in the subflow?

SORRY

I'm kinda confused reading it a third time.

If you have made a subflow, I am not sure it is ..... needed to have the change node just before the message goes into it.
Just do that in the subflow

For now, I'd suggest you extract all the nodes from the subflow and make sure it works at this level.
Yes, env is a bit difficult to get around.

But I'm not seeing what you want to do exactly.

Here is a test flow that may help you with using subflows and context stuff.

I had a real bad time at the start and this kind of helped.

[{"id":"480c6735eef22428","type":"subflow","name":"Get parent flow context example","info":"","category":"","in":[{"x":60,"y":80,"wires":[{"id":"0baab8933b6c881b"}]}],"out":[{"x":410,"y":80,"wires":[{"id":"0baab8933b6c881b","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"0baab8933b6c881b","type":"function","z":"480c6735eef22428","name":"parent context get","func":"msg.payload = flow.get(\"$parent.example\");\nreturn msg;\n// flow.set(\"$parent.Timer\"+x, x);","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":230,"y":80,"wires":[[]]},{"id":"bc62956f2461c1bb","type":"inject","z":"7e987ddf260bdf0d","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"A","payloadType":"str","x":110,"y":1950,"wires":[["4bc259bbc93e8c1d"]]},{"id":"1da3c7e9fc2e9311","type":"inject","z":"7e987ddf260bdf0d","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"B","payloadType":"str","x":110,"y":1990,"wires":[["4bc259bbc93e8c1d"]]},{"id":"f9e8ec3151fa7e4b","type":"inject","z":"7e987ddf260bdf0d","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":2090,"wires":[["9b854c5131989160","8e7dfd53955cbfad"]]},{"id":"4bc259bbc93e8c1d","type":"change","z":"7e987ddf260bdf0d","name":"","rules":[{"t":"set","p":"example","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":300,"y":1970,"wires":[[]]},{"id":"ed2b683cd58e129f","type":"debug","z":"7e987ddf260bdf0d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":630,"y":2090,"wires":[]},{"id":"9b854c5131989160","type":"subflow:480c6735eef22428","z":"7e987ddf260bdf0d","name":"","x":350,"y":2090,"wires":[["ed2b683cd58e129f"]]},{"id":"ef3e11816c8dc078","type":"debug","z":"7e987ddf260bdf0d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":480,"y":2150,"wires":[]},{"id":"8e7dfd53955cbfad","type":"change","z":"7e987ddf260bdf0d","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"example","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":300,"y":2150,"wires":[["ef3e11816c8dc078"]]}]

Hope it helps.

You just press the A or B node and then the timestamp node and look at the two debug nodes.

So for that example (with the hose valves), ideally what would you like to specify in the subflow properties?

This is how a lot of I/O nodes work, ref http and all sorts of other protocols. You can set URL in node property (env) as a static value, all incoming messages will use that address. Or set it dynamically in msg.url.

Your issue may be that msg props are not as obvious and less strict than the config menu of a node / subflow? I agree it would be nice to have a clear view of args, like a function signature. If done right, this info should at least be available in documentation of the node / subflow (when people care enough to explain it there).

I write a lot of subflows as easy-to-use tools. What I often end up doing for maximal flexibility is to support both dynamic msg props AND subflow config env variables. Like this:

msg.url ??= env.get("url");

If value is set dynamically in msg, use that. Otherwise use whatever set in config.