# Subflow as a function

**URL:** https://discourse.nodered.org/t/subflow-as-a-function/18017
**Category:** General
**Created:** [15 November 2019 21:22 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017 "2019-11-15T21:22:47Z")
**Posts on this page:** 17
**Page:** 1

<div class="post-metadata">

### Author: ![Noneangel](https://avatars.discourse-cdn.com/v4/letter/n/59ef9b/32.png) [@Noneangel](https://discourse.nodered.org/u/Noneangel)
#### Post date: [15 November 2019 21:22 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/1 "2019-11-15T21:22:47Z")

</div>

I try to use a node `N` that expect its input as `msg.payload`.  
It bothers me because `msg.payload` already had information when it reaches `N`.  
So I surrounded this node to save the state of `msg.payload`, and restore it after `N`. It is ugly because each time I want to use `N`, I must add the save/restore nodes.  
Maybe subflow could solve my problems?  
I created the subflow, then I set the "inputs" of the subflow (in `Properties` / `Environment Variables`).  
I need two of them:

1. The name where to store the result of `N`. It is kind of OK:
  - easy if I store it in the root msg (example: "data" to store in `msg.data`)
  - I have no idea of how to elegantly provide a Json path to allows storage outside of the `msg` root.

2. `N` require a string parameter. I would like to provide it as an input expression accessible from the subflow. Currently, the only type of "input" / `Environment Variables` are string, number, bool, json, buffer, env variable. None of them is evaluated, so no dynamic input possible.

I looked for the following in the forum (but I didn't find anything relevant to my problem):

- dynamically set a property
- jsonata as input for subflow
- change subflow (If I could get the same input interface as the `change node` it would solve my problem)
- Parameter subflow (It leads med to [this page](https://discourse.nodered.org/t/pr-subflow-instance-properties/2853) where I can see in the screen shot "item type selector" the type `expression` that could solve my problem, but the feature is marked as reach for the [1.0.0: Milestone Release](https://github.com/beevelop/docker-node-red/issues/94) (Subflow Instance properties), and there is not yet an `expression` input type in version 1.0.2).

My current solution is to add a `change` node before my subflow, but it is requiring two nodes instead of one.

Do you have an idea on how to implement point 1 and / or 2 ?

node red version: 1.0.2

---

<div class="post-metadata">

### Author: ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)
#### Post date: [15 November 2019 22:16 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/2 "2019-11-15T22:16:37Z")

</div>

Can't you just move the payload into, as you suggest, msg.data before node N and then access it from there afterwards? I don't see what the subflow is doing for you.

---

<div class="post-metadata">

### Author: ![Noneangel](https://avatars.discourse-cdn.com/v4/letter/n/59ef9b/32.png) [@Noneangel](https://discourse.nodered.org/u/Noneangel)
#### Post date: [15 November 2019 22:32 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/3 "2019-11-15T22:32:45Z")

</div>

I would like it to be more generic: one instance of the subflow read input from `msg.input1` and write output in `mgs.output1`, and another instance of the subflow read input from `msg.input2` and write output in `mgs.output2`.  
In my case, I want to get status a multiple device by chaining call to the subflow, so I need to store output in different places.  
I want the subflow to be a way to create / adapt node from other nodes.

---

<div class="post-metadata">

### Author: ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)
#### Post date: [15 November 2019 23:32 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/4 "2019-11-15T23:32:57Z")

</div>

I know I am going to shoot myself in the foot by joining in here, but I want to help all the same.

I am sort of getting what you mean, but also not quite.

Reading the post, you have _resigned_ yourself to the `change` node and it works. Kind of. Just you don't like the extra node/s.

I sort of understand that too. _Been there. Done that_ when I was learning.

Here's my take on what you need to do.

> [@Noneangel](#):
>
> In my case, I want to get status a multiple device by chaining call to the subflow, so I need to store output in different places.

I am not getting exactly what you mean there, but you could do something like this:

This is a badly written bit of code, but it is only intended to show you the idea where you can save multiple thing for multiple devices easily.

```auto
[{"id":"a74c1fb7.6ae5c8","type":"inject","z":"accbdb61.d75918","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":2500,"wires":[["8e4737db.e94bb"]]},{"id":"8e4737db.e94bb","type":"function","z":"accbdb61.d75918","name":"Construct message","func":"msg.payload = {\n device: \"device2\",\n ustatus: \"offline\",\n extra: \"and more stuff\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":2500,"wires":[["fd79a15b.414798"]]},{"id":"fd79a15b.414798","type":"function","z":"accbdb61.d75918","name":"Subflow starts with this node.","func":"// open the window fully to read all the text easier\nlet device = msg.payload.device;\nlet ustatus = msg.payload.ustatus;\nlet extra = msg.payload.extra;\n\n// This has established the variables from the payload\n\ncontext.set(device,device);\ncontext.set(device+\"status\",ustatus);\n\n\n\nreturn msg;","outputs":1,"noerr":0,"x":590,"y":2500,"wires":[[]]},{"id":"2626268a.5bccba","type":"function","z":"accbdb61.d75918","name":"Construct message","func":"msg.payload = {\n device: \"device1\",\n ustatus: \"example\",\n extra: \"more stuff\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":2450,"wires":[["fd79a15b.414798"]]},{"id":"4d2153fa.9d309c","type":"function","z":"accbdb61.d75918","name":"Construct message","func":"msg.payload = {\n device: \"device3\",\n ustatus: \"online\",\n extra: \"even more stuff\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":2550,"wires":[["fd79a15b.414798"]]},{"id":"5fd4cf0e.d12a18","type":"inject","z":"accbdb61.d75918","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":2450,"wires":[["2626268a.5bccba"]]},{"id":"a4b5f895.8061e","type":"inject","z":"accbdb61.d75918","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":2550,"wires":[["4d2153fa.9d309c"]]}]

```

Walk through:  
Click on the `subflow starts with this node` node. Open the context menu and look at the node's stuff.

Click on the first button.

That will set the context naming device1 with a status.  
(I picked this only because that is the road on which I have been)

Click the second button and you will get a new entry for the second device and its status.

This can go on "forever".

I know it isn't **the** answer to what you want to do, but I hope it helps you understand a _trick_ with how you can send a few packets to the subflow.

---

<div class="post-metadata">

### Author: ![Noneangel](https://avatars.discourse-cdn.com/v4/letter/n/59ef9b/32.png) [@Noneangel](https://discourse.nodered.org/u/Noneangel)
#### Post date: [18 November 2019 20:18 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/5 "2019-11-18T20:18:33Z")

</div>

It isn't the answer primary answer (it still requires one node before the subflow), but thank you for responding, it is a neat trick.  
PS: sorry for my poor English. I am not a native speaker.

---

<div class="post-metadata">

### Author: ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)
#### Post date: [18 November 2019 23:12 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/6 "2019-11-18T23:12:33Z")

</div>

> [@Noneangel](#):
>
> it still requires one node before the subflow

Well, it does and it doesn't.

Really it only needs what you put in it.

I'll stick my neck out.

Send me a basic idea of what you are wanting to do and I will see what I can do for you.

Say two input devices with their messages and explain what you want to do.

Up to you.

---

<div class="post-metadata">

### Author: ![Noneangel](https://avatars.discourse-cdn.com/v4/letter/n/59ef9b/32.png) [@Noneangel](https://discourse.nodered.org/u/Noneangel)
#### Post date: [20 November 2019 20:58 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/7 "2019-11-20T20:58:17Z")

</div>

Here is an example. Please see the description of each node and subflow.

```auto
[{"id":"dc1d621d.b6606","type":"subflow","name":"my subflow","info":"I use a node (api-current-state) from a library (node-red-contrib-home-assistant-websocket) that expects its argument in `payload.entity_id`. So I backup `msg.payload` into `msg.payload_backup` during the call to the node api-current-state, and restore the payload after that","category":"","in":[{"x":40,"y":40,"wires":[{"id":"359ddf85.db8608"}]}],"out":[{"x":920,"y":40,"wires":[{"id":"21d5ab1e.9f8524","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"359ddf85.db8608","type":"function","z":"dc1d621d.b6606","name":"save payload, set argument","func":"msg.backup_payload = msg.payload;\nmsg.payload = {entity_id: msg.subflowParameter};\nreturn msg;","outputs":1,"noerr":0,"x":260,"y":40,"wires":[["43e4a3ea.fa60e4"]],"info":"the next node in this sequance expect its input to be in `msg.payload`.\nSo I save the content of `msg.payload` in `msg.backup_payload`, and set `msg.payload` to be the correct input"},{"id":"21d5ab1e.9f8524","type":"function","z":"dc1d621d.b6606","name":"restore payload","func":"msg.payload = msg.backup_payload;\ndelete msg.backup_payload;\nreturn msg;","outputs":1,"noerr":0,"x":760,"y":40,"wires":[[]],"info":"restores the initial `msg.payload`, and remove the backup `msg.backup_payload`"},{"id":"43e4a3ea.fa60e4","type":"function","z":"dc1d621d.b6606","name":"node that I want to encapsulate","func":"/*fake node result*/\nmsg.data = {\n \"id\": msg.payload,\n \"output\": \"you are the best\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":530,"y":40,"wires":[["21d5ab1e.9f8524"]],"info":"This node is acctualy the node api-current-state from the\nlibrary node-red-contrib-home-assistant-websocke.\nIt expect a device id in `msg.payload`, and it stores its result in `msg.data`"},{"id":"4559e457.9135ac","type":"inject","z":"6820b1fc.837188","name":"part one of my flow","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":220,"wires":[["bd7fd1e4.38d7f8"]]},{"id":"f0b37b84.d80658","type":"inject","z":"6820b1fc.837188","name":"part two of my flow","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":280,"wires":[["270e3e23.117a42"]]},{"id":"bd7fd1e4.38d7f8","type":"function","z":"6820b1fc.837188","name":"generation of the message for part one","func":"return {\n storage: {\n deviceId: \"device1\"\n }\n};","outputs":1,"noerr":0,"x":440,"y":220,"wires":[["409ca645.a3408"]],"info":"In this part of my flow, the message has this form.\nThis function is only here to generate it.\nIt is not this node that I want to get rid of."},{"id":"270e3e23.117a42","type":"function","z":"6820b1fc.837188","name":"generation of the message for part two","func":"return {\n payload: {\n deviceId: \"device2\"\n }\n};","outputs":1,"noerr":0,"x":440,"y":280,"wires":[["592be2dc.daa08c"]],"info":"Same as above"},{"id":"409ca645.a3408","type":"change","z":"6820b1fc.837188","name":"I want to get rid of this","rules":[{"t":"set","p":"subflowParameter","pt":"msg","to":"msg.storage.deviceId\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":220,"wires":[["18248b43.2b6c05"]],"info":"This node is only here to put the input in a field expected by the subflow.\nIn the best-case scenario, I would like to have the properties rules of this `change` node in the properties rules of the subflow, or have a possibility to set an environment variable to an expression."},{"id":"592be2dc.daa08c","type":"change","z":"6820b1fc.837188","name":"I want to get rid of this too","rules":[{"t":"set","p":"subflowParameter","pt":"msg","to":"msg.payload.deviceId\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":280,"wires":[["77cbf548.9320b4"]],"info":"Same has the other change node"},{"id":"77cbf548.9320b4","type":"subflow:dc1d621d.b6606","z":"6820b1fc.837188","name":"","env":[],"x":960,"y":280,"wires":[["b6664c6.33dc5b"]]},{"id":"a23e5a3f.c36c18","type":"function","z":"6820b1fc.837188","name":"rest of the flow part one","func":"\nreturn msg;","outputs":0,"noerr":0,"x":1170,"y":220,"wires":[],"info":"After the call of `my subflow`, I have access to its output in `msg.data`."},{"id":"b6664c6.33dc5b","type":"function","z":"6820b1fc.837188","name":"rest of the flow part two","func":"\nreturn msg;","outputs":0,"noerr":0,"x":1170,"y":280,"wires":[],"info":"Same as above node."},{"id":"18248b43.2b6c05","type":"subflow:dc1d621d.b6606","z":"6820b1fc.837188","name":"","env":[],"x":960,"y":220,"wires":[["a23e5a3f.c36c18"]]}]

```

Again, thank you very much for the time you spend for me.

---

<div class="post-metadata">

### Author: ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)
#### Post date: [21 November 2019 02:50 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/8 "2019-11-21T02:50:53Z")

</div>

No problem.

The flow you posted works, but I think there is a lot of stuff _lost in translation_ here. Nothing against you not speaking English. It is a phrase used to indicate a failure of communications.

It isn't I want to drag you through this only for the sake of being difficult. Rather I want to help you get what you want done to get done.

I appreciate this is a "basic view" of the flow. But let's pull it down/apart:  
A message is created. (First function node)  
It sends:

```auto
return {
    storage: {
        deviceId: "device1"
    }
};

```

Fair enough.

The `change` node is: **I want to get rid of this**  
Which simply moves things around in the message structure.

Basically what was in the message is now in `msg.subflowParameter`. Again fair enough.

Now we go into the `subflow`.

Node1:

```auto
msg.backup_payload = msg.payload;
msg.payload = {entity_id: msg.subflowParameter};
return msg;

```

Ok, you _backup_ the `msg.payload` to `msg.backup_payload`. I'll get back to this soon.  
You then set `msg.payload` to `msg.subflowParameter`. Yeah, ok. Confused.

Node2:

```auto
/*fake node result*/
msg.data = {
    "id": msg.payload,
    "output": "you are the best"
}
return msg;

```

Line 1. Ok, this is "fake node result". Which part exactly?

I can't work on it if I don't know what is _real_ and which is _faked_.

Sorry.

I'm not seeing where you need to preserve data from messages

> [@Noneangel](#):
>
> It bothers me because `msg.payload` already had information when it reaches `N` .  
> So I surrounded this node to save the state of `msg.payload` , and restore it after `N` . It is ugly because each time I want to use `N` ,

Can you elaborate a bit more on that please?  
Putting aside _`msg.payload` is already in use (etc)_

You seem to be tripping over things which may (or not) really be problems, and only thinking they are problems thus making your options more difficult than they need to be.

`msg.payload` should be (between nodes) only carrying information you want.  
(I say should. That is all it can do really - well let's not get bogged down in semantics about that.)

You have a flow.  
Node 1: Does what ever it needs to do. `msg.payload` is constructed ready to send to the next node.  
Node 2: Receives `msg.payload` and acts on that. A new `msg.payload` is created and is made ready to send to the next node.  
And so on.

How are you wanting to access this information which is stored in the `subflow`?  
Does it need to be accessed by anything else or is it just you are wanting to optimise using this piece of code in multiple parts of the flow?

I would suggest you write a flow which does what you want.  
Indicate where the _subflow_ starts and ends with `comment` nodes.

Something like this:

 ![Screenshot%20from%202019-11-21%2013-45-29](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/f/f7a25e052752bb7e38fd6e366cc77538b241cc36.png)

Given the first `function node` creates the message (if not possible in the `inject` node).  
The second, third and fourth (as per your example) are the nodes doing what you want, and the `output` node signals the end of what you want to do and shows the user what the `msg` should look like.

Hoping to hear back soon.

---

<div class="post-metadata">

### Author: ![Noneangel](https://avatars.discourse-cdn.com/v4/letter/n/59ef9b/32.png) [@Noneangel](https://discourse.nodered.org/u/Noneangel)
#### Post date: [23 November 2019 16:13 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/9 "2019-11-23T16:13:06Z")

</div>

Here is the full context:  
My flow can be triggered by two remotes (R1, R2), each one controlling a specific light (real light RL1, real light RL2).

Each light has two id (one for day mode (L1 or L2), and one for night mode (L1N or L2N)), each id correspond to devices in home assistant.

L1 is mutually exclusive from L1N (and L2 is mutually exclusive from L2N). By mutually exclusive, I mean that if the latest instruction received by home assistant was `turn on L1`, then RL1 is in day mode. To know which mode is active for RL1, I need to get state of both L1 and L1N, and find out which one was the latest to receive a `turn on` instruction.  
I would like to have a single flow for both R1 and R2, and I try to use a sub flow to warp the `get state` node call.  
My subflow needs to get its parameter (L1, L2, L1N or L2N), and output the last date at which the device received a `turn on` instruction, and save it somewhere.

Here is the flow. It still needs a node before each call to the subflow to set the destination of the subflow result, and to set the input correctly (correctly = the way `node that I want to encapsulate` = `get state` expects its input).

```auto
[{"id":"af2298fb.54c768","type":"inject","z":"830c2a2d.0b8f5","name":"remote 1","topic":"","payload":"R1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":340,"y":920,"wires":[["3450799a.69e726"]]},{"id":"6405cdae.d1b0bc","type":"inject","z":"830c2a2d.0b8f5","name":"remote 2","topic":"","payload":"R2","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":340,"y":1000,"wires":[["3450799a.69e726"]]},{"id":"3450799a.69e726","type":"function","z":"830c2a2d.0b8f5","name":"map remote to device","func":"switch (msg.payload) {\n case \"R1\":\n msg.payload = {\n remote: \"R1\",\n device: \"L1\",\n };\n break;\n case \"R2\":\n msg.payload = {\n remote: \"R2\",\n device: \"L2\"\n };\n break;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":960,"wires":[["4ac8f332.e7156c"]]},{"id":"a8be76a9.47c79","type":"function","z":"830c2a2d.0b8f5","name":"restore payload","func":"msg.payload = msg.backup_payload;\nmsg[msg.subflowReturnField] = msg.data\ndelete msg.backup_payload;\ndelete msg.data;\nreturn msg;","outputs":1,"noerr":0,"x":1800,"y":960,"wires":[["957adc8d.18afd8"]],"info":"restores the initial `msg.payload`, and remove the backup `msg.backup_payload`"},{"id":"63055c6b.ce0374","type":"function","z":"830c2a2d.0b8f5","name":"node that I want to encapsulate","func":"function randomDate(start, end) {\n return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));\n}\n\nrandomDate(new Date(2012, 0, 1), new Date())\n\nmsg.data = {\n \"entity_id\": msg.payload,\n \"last_updated\": randomDate(new Date(2012, 0, 1), new Date()).valueOf()\n}\nreturn msg;","outputs":1,"noerr":0,"x":1550,"y":960,"wires":[["a8be76a9.47c79"]],"info":"`msg.data` should be a output of an http call to\nmy home assistant server with `entity_id` as parametter.\nI don't know in advence whate `last_updated` will be, so I affect it a random value for this example.\n`entity_id` is the same as the value msg.payload at\nthe start of the subflow."},{"id":"1f1826cc.01e829","type":"function","z":"830c2a2d.0b8f5","name":"save payload, set argument","func":"msg.backup_payload = msg.payload;\nmsg.payload = {entity_id: msg.subflowParameter};\nreturn msg;","outputs":1,"noerr":0,"x":1260,"y":960,"wires":[["63055c6b.ce0374"]],"info":"the next node in this sequance expect its input to be in `msg.payload`.\nSo I save the content of `msg.payload` in `msg.backup_payload`, and set `msg.payload` to be the correct input"},{"id":"7002de7.126f5a","type":"function","z":"830c2a2d.0b8f5","name":"restore payload","func":"msg.payload = msg.backup_payload;\nmsg[msg.subflowReturnField] = msg.data\ndelete msg.backup_payload;\ndelete msg.data;\nreturn msg;","outputs":1,"noerr":0,"x":3240,"y":960,"wires":[["6b8cd7a2.0e92f8"]],"info":"restores the initial `msg.payload`, and remove the backup `msg.backup_payload`"},{"id":"71e4eec4.29f4f8","type":"function","z":"830c2a2d.0b8f5","name":"save payload, set argument","func":"msg.backup_payload = msg.payload;\nmsg.payload = {entity_id: msg.subflowParameter};\nreturn msg;","outputs":1,"noerr":0,"x":2700,"y":960,"wires":[["acd7003f.df365"]],"info":"the next node in this sequance expect its input to be in `msg.payload`.\nSo I save the content of `msg.payload` in `msg.backup_payload`, and set `msg.payload` to be the correct input"},{"id":"5b22834e.ad5dfc","type":"comment","z":"830c2a2d.0b8f5","name":"preprocessing","info":"","x":690,"y":900,"wires":[]},{"id":"4ac8f332.e7156c","type":"function","z":"830c2a2d.0b8f5","name":"set subflowParameter for day device","func":"msg.subflowParameter = msg.device\nmsg.subflowReturnField = \"day\";\nreturn msg;","outputs":1,"noerr":0,"x":870,"y":960,"wires":[["1f1826cc.01e829"]],"info":"I want to get rid of this node"},{"id":"957adc8d.18afd8","type":"function","z":"830c2a2d.0b8f5","name":"set subflowParameter for night device","func":"msg.subflowParameter = msg.device + \"N\"\nmsg.subflowReturnField = \"night\";\nreturn msg;","outputs":1,"noerr":0,"x":2210,"y":960,"wires":[["71e4eec4.29f4f8"]],"info":"I want to get rid of this node"},{"id":"e649b617.703a2","type":"comment","z":"830c2a2d.0b8f5","name":"subflow start","info":"","x":1090,"y":900,"wires":[]},{"id":"991edf4e.a7aee","type":"comment","z":"830c2a2d.0b8f5","name":"subflow start","info":"","x":2470,"y":900,"wires":[]},{"id":"de8d9fa4.e5f078","type":"comment","z":"830c2a2d.0b8f5","name":"subflow end","info":"","x":1990,"y":900,"wires":[]},{"id":"da8c608c.f548e","type":"comment","z":"830c2a2d.0b8f5","name":"subflow end","info":"","x":3430,"y":900,"wires":[]},{"id":"acd7003f.df365","type":"function","z":"830c2a2d.0b8f5","name":"node that I want to encapsulate","func":"function randomDate(start, end) {\n return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));\n}\n\nrandomDate(new Date(2012, 0, 1), new Date())\n\nmsg.data = {\n \"entity_id\": msg.payload,\n \"last_updated\": randomDate(new Date(2012, 0, 1), new Date()).valueOf()\n}\nreturn msg;","outputs":1,"noerr":0,"x":2990,"y":960,"wires":[["7002de7.126f5a"]],"info":"same has above"},{"id":"6b8cd7a2.0e92f8","type":"debug","z":"830c2a2d.0b8f5","name":"output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"{\t \"device\": $join([msg.payload.device, msg.day.last_updated > msg.night.last_updated ? \"\" : \"N\"]),\t \"remote\": msg.payload.remote\t}","targetType":"jsonata","x":3610,"y":960,"wires":[]}]

```

The message expected at the last node might be

```json
{
"device": "L1N",
"remote": "R1"
}

```

Here is another one. It is almost ok (I used your first idea):

```auto
[{"id":"5da3cfd8.8dcb18","type":"inject","z":"33e08bf7.43f924","name":"remote 1","topic":"","payload":"R1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":340,"y":340,"wires":[["eb69b5a4.bbb268"]]},{"id":"4211ca7f.1531c4","type":"inject","z":"33e08bf7.43f924","name":"remote 2","topic":"","payload":"R2","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":340,"y":420,"wires":[["eb69b5a4.bbb268"]]},{"id":"eb69b5a4.bbb268","type":"function","z":"33e08bf7.43f924","name":"map remote to device","func":"switch (msg.payload) {\n case \"R1\":\n msg.payload = {\n remote: \"R1\",\n day: \"L1\",\n night: \"L1N\"\n };\n break;\n case \"R2\":\n msg.payload = {\n remote: \"R2\",\n day: \"L2\",\n night: \"L2N\"\n };\n break;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":380,"wires":[["23fb61a8.a47bc6","2cf6e8ab.9546d8"]]},{"id":"bfddf808.172ba8","type":"function","z":"33e08bf7.43f924","name":"restore payload","func":"msg.payload = msg.backup_payload;\ndelete msg.backup_payload;\nreturn msg;","outputs":1,"noerr":0,"x":1940,"y":300,"wires":[["a0f46ae.a907d18"]],"info":"restores the initial `msg.payload`, and remove the backup `msg.backup_payload`"},{"id":"8722a499.b0184","type":"function","z":"33e08bf7.43f924","name":"node that I want to encapsulate","func":"function randomDate(start, end) {\n return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));\n}\n\nrandomDate(new Date(2012, 0, 1), new Date())\n\nmsg.data = {\n \"entity_id\": msg.payload,\n \"last_updated\": randomDate(new Date(2012, 0, 1), new Date()).valueOf()\n}\nreturn msg;","outputs":1,"noerr":0,"x":1710,"y":300,"wires":[["bfddf808.172ba8"]],"info":"`msg.data` should be a output of an http call to\nmy home assistant server with `entity_id` as parametter.\nI don't know in advence whate `last_updated` will be, so I affect it a random value for this example.\n`entity_id` is the same as the value msg.payload at\nthe start of the subflow."},{"id":"c406d9b4.6c635","type":"function","z":"33e08bf7.43f924","name":"save payload, set argument","func":"msg.backup_payload = msg.payload;\nmsg.payload = msg.subflowParameter;\nreturn msg;","outputs":1,"noerr":0,"x":1440,"y":300,"wires":[["8722a499.b0184"]],"info":"the next node in this sequance expect its input to be in `msg.payload`.\nSo I save the content of `msg.payload` in `msg.backup_payload`, and set `msg.payload` to be the correct input"},{"id":"a93a1cb5.4396c8","type":"function","z":"33e08bf7.43f924","name":"restore payload","func":"msg.payload = msg.backup_payload;\ndelete msg.backup_payload;\nreturn msg;","outputs":1,"noerr":0,"x":1940,"y":460,"wires":[["a0f46ae.a907d18"]],"info":"restores the initial `msg.payload`, and remove the backup `msg.backup_payload`"},{"id":"a5023a2a.1d749","type":"function","z":"33e08bf7.43f924","name":"save payload, set argument","func":"msg.backup_payload = msg.payload;\nmsg.payload = msg.subflowParameter;\nreturn msg;","outputs":1,"noerr":0,"x":1440,"y":460,"wires":[["e63eeae.e151518"]],"info":"the next node in this sequance expect its input to be in `msg.payload`.\nSo I save the content of `msg.payload` in `msg.backup_payload`, and set `msg.payload` to be the correct input"},{"id":"73206fda.be91b","type":"comment","z":"33e08bf7.43f924","name":"preprocessing","info":"","x":710,"y":260,"wires":[]},{"id":"23fb61a8.a47bc6","type":"function","z":"33e08bf7.43f924","name":"set subflowParameter for day device","func":"msg.subflowParameter = msg.payload.day\nreturn msg;","outputs":1,"noerr":0,"x":910,"y":300,"wires":[["c406d9b4.6c635"]]},{"id":"2cf6e8ab.9546d8","type":"function","z":"33e08bf7.43f924","name":"set subflowParameter for night device","func":"msg.subflowParameter = msg.payload.night\nreturn msg;","outputs":1,"noerr":0,"x":910,"y":460,"wires":[["a5023a2a.1d749"]]},{"id":"7fa94eb3.08a3","type":"comment","z":"33e08bf7.43f924","name":"subflow start","info":"","x":1190,"y":260,"wires":[]},{"id":"80f6fd4c.588cf8","type":"comment","z":"33e08bf7.43f924","name":"subflow start","info":"","x":1190,"y":420,"wires":[]},{"id":"1abfd28f.5440c5","type":"comment","z":"33e08bf7.43f924","name":"subflow end","info":"","x":2130,"y":240,"wires":[]},{"id":"9844b3ca.7f67b","type":"comment","z":"33e08bf7.43f924","name":"subflow end","info":"","x":2130,"y":400,"wires":[]},{"id":"e63eeae.e151518","type":"function","z":"33e08bf7.43f924","name":"node that I want to encapsulate","func":"function randomDate(start, end) {\n return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));\n}\n\nrandomDate(new Date(2012, 0, 1), new Date())\n\nmsg.data = {\n \"entity_id\": msg.payload,\n \"last_updated\": randomDate(new Date(2012, 0, 1), new Date()).valueOf()\n}\nreturn msg;","outputs":1,"noerr":0,"x":1710,"y":460,"wires":[["a93a1cb5.4396c8"]],"info":"same has above"},{"id":"ef835aaf.89ac9","type":"function","z":"33e08bf7.43f924","name":"output","func":"if(msg.data[0].last_updated > msg.data[1].last_updated)\n return msg.data[0];\nelse\n return msg.data[1];\n","outputs":1,"noerr":0,"x":2450,"y":360,"wires":[["408329b0.f56af"]]},{"id":"408329b0.f56af","type":"debug","z":"33e08bf7.43f924","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":2640,"y":360,"wires":[]},{"id":"a0f46ae.a907d18","type":"join","z":"33e08bf7.43f924","name":"","mode":"custom","build":"array","property":"data","propertyType":"msg","key":"topic","joiner":"[\\n","joinerType":"str","accumulate":false,"timeout":"1","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":2290,"y":360,"wires":[["ef835aaf.89ac9](file://\\n","joinerType":"str","accumulate":false,"timeout":"1","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":2290,"y":360,"wires":[["ef835aaf.89ac9)"]]}]

```

The message expected at the last node might be

```json
{
"entity_id": "L1",
"last_updated": 1532152341151
}

```

There is still one problem:

- The subflow expects its input to be at a fixed location (`msg.subflowParameter`), and since the result is in a fixed place (`msg.data`), I must run the two calls of the subflow in parallel and cannot do it in sequence.

I could merge it with the node `map remote to device` in this case (two calls close to each other), but I want to be able to use the subflow somewhere else in the flow, and then, I will need to also add a node to set the input.

I would like the subflow interface to accept an input (for example an expression, or a path in the msg (for example `msg.payload.day` in the last flow), and an output (for example `msg.day`). Some this like that:  
(Jsonata is not available in the input type of an environment variable, I had to edit the html page for the screenshot).  
Also, `day` as a string allows storing the result in `msg.day` and not in `msg.data.device.day` for example.  
 ![interface](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/1/1be60aadb7d933ad76f7b25f97bb73575c5f50c0.png)

> [@Trying\_to\_learn](#):
>
> Node1:
> 
> ```auto
> msg.backup_payload = msg.payload;
> msg.payload = {entity_id: msg.subflowParameter};
> return msg;
> 
> ```
> 
> Ok, you _backup_ the `msg.payload` to `msg.backup_payload` . I'll get back to this soon.  
> You then set `msg.payload` to `msg.subflowParameter` . Yeah, ok. Confused.

I use `msg` to accumulate information during the sequence, so I want to keep what is in payload. The node that is encapsulated in the subflow expects `msg.payload.entity_id` to contain the device id (L1N for example in my example flow). So I backup everything from `msg.payload`, set the argument for my `node that I want to encapsulate` = `get state`, and once the node `get state` called, I restore my initial payload.

> [@Trying\_to\_learn](#):
>
> Node2:
> 
> ```auto
> /*fake node result*/
> msg.data = {
> "id": msg.payload,
> "output": "you are the best"
> }
> return msg;
> 
> ```
> 
> Line 1. Ok, this is "fake node result". Which part exactly?
> 
> I can't work on it if I don't know what is _real_ and which is _faked_ .

I hop it is clearer in my new flow example. In the first example, `msg.data` is fake. In my real flow, the `get-state` node generates `msg.data` with an http request to my home assistant server (using `msg.payload.entity_id` as parameter to get the state (on or off) of the light whose id is the value contained in `msg.payload.entity_id`)

> [@Trying\_to\_learn](#):
>
> I'm not seeing where you need to preserve data from messages

It doesn't show in my example, but I may need information that was in the initial payload (the remote name for example). It is not revalent with the last example (in parallel), but for the sequential example, I construct the `entity_id` from the initial `msg.payload.device` twice (first time it is L1, then its L1D). I could store the information somewhere else (like `mst.data`).

> [@Trying\_to\_learn](#):
>
> How are you wanting to access this information which is stored in the `subflow` ?

At the end of the sequence (not in my examples), I use the data generated by the subflow.

> [@Trying\_to\_learn](#):
>
> Does it need to be accessed by anything else or is it just you are wanting to optimize using this piece of code in multiple parts of the flow?

I want to optimize using this piece of code in multiple parts of the flow.

> [@Trying\_to\_learn](#):
>
> Given the first `function node` creates the message (if not possible in the `inject` node).

In my example, the `inject` nodes / remote does create the initial payload.

---

<div class="post-metadata">

### Author: ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)
#### Post date: [23 November 2019 22:07 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/10 "2019-11-23T22:07:22Z")

</div>

Wow.

Thanks.

I shall look at it.

I have imported the first one and am looking at it.

I won't waste too much time now replying as I read your post. I'll get into reading what you said and try to work out how to do it.

The second flow which you say is based on what I suggested doesn't load. There is a syntax error in there and so I can't import it as code. (NR won't let it load.)

I have sort of bitten off a lot as I am not up to speed with what  
`msg.payload = {entity_id: msg.subflowParameter};`  
means.  
My bad. But I will investigate.

I won't waste too much time in this reply. I will sit down and read what you said.

Running your first flow, a slight problem happened with R2 in that with the first two pressed I get/got `L2N` as the output. Then it started to toggle as it did with R1.

But that's a small thing. Don't worry.

I hope to get back to you soon.

(Sorry, late addition)  
So, if I send two inputs of `remote 1`, the output is supposed to toggle from:  
`{"device":"L1N","remote":"R1"}`  
to  
`{"device":"L1","remote":"R1"}`

But if I send the signal too quickly it doesn't always toggle.  
Is the pause supposed to imply a change from daytime to night?

---

<div class="post-metadata">

### Author: ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)
#### Post date: [23 November 2019 23:32 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/11 "2019-11-23T23:32:25Z")

</div>

Ok, no promises.

Here are two flows which do what I think you want to do.

I put them together in one import only because two posts of the flow seems silly with how small they are.

```auto
[{"id":"67f696df.eefdf","type":"inject","z":"cd24bca6.19d15","name":"remote 1","topic":"","payload":"R1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":700,"wires":[["3fa36ebd.c201ca"]]},{"id":"f9059d78.f6817","type":"inject","z":"cd24bca6.19d15","name":"remote 2","topic":"","payload":"R2","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":780,"wires":[["3fa36ebd.c201ca"]]},{"id":"3fa36ebd.c201ca","type":"function","z":"cd24bca6.19d15","name":"map remote to device","func":"switch (msg.payload) {\n case \"R1\":\n msg.payload = {\n remote: \"R1\",\n device: \"L1\",\n };\n break;\n case \"R2\":\n msg.payload = {\n remote: \"R2\",\n device: \"L2\"\n };\n break;\n}\n\nmsg.subflowParameter = msg.device\nmsg.subflowReturnField = \"day\";\n\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":740,"wires":[["4d195895.519b9"]]},{"id":"4d195895.519b9","type":"function","z":"cd24bca6.19d15","name":"This node is the subflow","func":"let remote = msg.payload.remote;\nlet device = msg.payload.device; // should not be needed/used.\n\n//node.warn(\"Name \" + device);\n\nlet device_state = device + \"state\";\ndevice_state = context.get('state') || 0; // Set to 0 if not assigned.\n\n//node.warn(\"State \" + device_state);\n\ndevice_state = (device_state + 1) % 2; // Toggle between 0 and 1\ncontext.set('state',device_state);\n\nmsg = {\"payload\":device,\"state\":device_state};\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":740,"wires":[["e93c21ff.41e2b8"]]},{"id":"e93c21ff.41e2b8","type":"debug","z":"cd24bca6.19d15","name":"C","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":780,"y":740,"wires":[]},{"id":"fa655930.c7819","type":"inject","z":"cd24bca6.19d15","name":"remote 1","topic":"","payload":"R1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":840,"wires":[["6ce037ec.d379b8"]]},{"id":"cafdce.ab2c9a3","type":"inject","z":"cd24bca6.19d15","name":"remote 2","topic":"","payload":"R2","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":920,"wires":[["27f0c7fa.4df47"]]},{"id":"6ce037ec.d379b8","type":"function","z":"cd24bca6.19d15","name":"map remote to device","func":"msg.payload = {\n remote: \"R1\",\n device: \"L1\",\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":840,"wires":[["439334aa.9bf1cc"]]},{"id":"439334aa.9bf1cc","type":"function","z":"cd24bca6.19d15","name":"This node is the subflow","func":"let remote = msg.payload.remote;\nlet device = msg.payload.device; // should not be needed/used.\n\n//node.warn(\"Name \" + device);\n\nlet device_state = device + \"state\";\ndevice_state = context.get('state') || 0; // Set to 0 if not assigned.\n\n//node.warn(\"State \" + device_state);\n\ndevice_state = (device_state + 1) % 2; // Toggle between 0 and 1\ncontext.set('state',device_state);\n\nmsg = {\"payload\":device,\"state\":device_state};\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":880,"wires":[["1033c8e9.12b9af"]]},{"id":"1033c8e9.12b9af","type":"debug","z":"cd24bca6.19d15","name":"C","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":780,"y":880,"wires":[]},{"id":"27f0c7fa.4df47","type":"function","z":"cd24bca6.19d15","name":"map remote to device","func":"msg.payload = {\n remote: \"R2\",\n device: \"L2\",\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":920,"wires":[["439334aa.9bf1cc"]]},{"id":"ed407d42.2e145","type":"comment","z":"cd24bca6.19d15","name":"One","info":"","x":430,"y":690,"wires":[]},{"id":"b6d35568.0ead18","type":"comment","z":"cd24bca6.19d15","name":"Two","info":"","x":430,"y":800,"wires":[]}]

```

Now, before you say _NO!_ (wink) from looking at the flow/s please indulge me in reading this.

Yes, I am not fully understanding what you mean. That's just how it is. Neither of us are to blame.

Also please don't be put off by how few nodes I use.  
I too am guilty of over complicating things which don't need to be.

Flow ONE:  
Press the `remote1` button once, see the output.  
Press it again. See how the output has changed.  
Press it a third time and it will go back to the first output.  
(Nominal press it again if you want.)

Now press `remote2` button and see how it also changes with subsequent presses.

Both outputs are independent of each other. You can have either in either state and the other one has no effect on it.

Flow TWO:  
This is just an alternative way of doing it.  
The `function` node you used to assign the _remote_ to the _device_ isn't really needed.  
The flow (upstream/before) there can construct the message.  
Sure it may mean another node (as shown) for each input, but all in all, I don't see much advantage in having a dedicated node to _assign the device to the remote_ because I am sure there would be space in the code to add the line/s needed anyway.

I know in the flow/s (this node is the subflow) I say:

> let remote = msg.payload.remote;  
> let device = msg.payload.device; // should not be needed/used.

And I then go and use the `device` name, it is only to honour how you wrote the code.  
There is an advantage (I now see) that using the `device` name rather than the remote, it allows more than one remote to control one device.

But as I don't know all the things at your end, I wrote it as I did.

So you maybe could get rid of the `remote` part.

Up to you.

Hope that helps.

---

<div class="post-metadata">

### Author: ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)
#### Post date: [24 November 2019 21:50 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/12 "2019-11-24T21:50:02Z")

</div>

Just to add:  
Yes, the outputs are not exactly what you posted.

The formatting of the output message is relativily easy to do. Just if it is doing what you want.

---

<div class="post-metadata">

### Author: ![Noneangel](https://avatars.discourse-cdn.com/v4/letter/n/59ef9b/32.png) [@Noneangel](https://discourse.nodered.org/u/Noneangel)
#### Post date: [25 November 2019 20:33 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/13 "2019-11-25T20:33:10Z")

</div>

Thanks,  
First of all, sorry for the time you spend on this. Unfortunately, I was not exhaustive enough.  
Indeed, multiple remotes may command one light. Your idea of storing the state is good, _but_ some of the remotes are not connected to node-red. That means the state of one device / light may change without node-red being notified. The node that I use in the subflow is meant to get the state of the device thanks to an api call to home assistant made through a specific node. In my example, I just generated random data instead of static one to show you that you cannot rely on the output of this node. It was not clear, I am sorry for that.

It seems that what I want is not (yet) possible. I want to provide a subflow with a different input type that the ones available. Currently, the inputs of a subflow are static i.e. you can provide a value, but not an expression. I have a programmer background, and I wanted to use sublow like a function. For instance (the add function would be a subflow in a read life use):  
Example 1 (what I try to do)

```javascript
let msg = {
    "payload": {
        "a": 1,
        "b": 2,
        "c": 3
    }
};
function add(arg1, arg2) {
    return arg1 + arg2;
}
msg.result1 = add(msg.payload.a, msg.payload.b);
msg.result1 = add(msg.payload.a, msg.payload.c);

```

But it seems that subflow can only be with static or with predefined input location like this:  
Example 2 (limitation of a subflow)

```javascript
let msg = {
    "payload": {
        "a": 1,
        "b": 2,
        "c": 3
    }
};
function add(msg) {
    msg.result = msg.payload.a, msg.payload.b;
}
add(msg);

```

So I have to add a node in so that the msg is properly formated.  
Example 3 (do Example 1 with limitation of a subflow)

```javascript
let msg = {
    "payload": {
        "a": 1,
        "b": 2,
        "c": 3
    }
};
function add(msg) {
    msg.result = msg.payload.a, msg.payload.b;
}
add(msg); // call to the subflow
// put the result in result1 and set the payload for the next call (the tree next lines are one node)
msg.backup_payload = msg.payload;
msg.result1 = msg.result;
msg.payload.b = msg.payload.c;
add(msg); // call to the subflow with the next set of argument (a and c)
// put the result in result2, restore payload (the tree next lines are one node)
msg.result2 = msg.result
msg.payload = msg.backup_payload;
delete msg.backup_payload;

```

PS:

> [@Trying\_to\_learn](#):
>
> I have sort of bitten off a lot as I am not up to speed with what  
> `msg.payload = {entity_id: msg.subflowParameter};`  
> means.  
> My bad. But I will investigate.

In javascript you can remove the `"` around the key of a property. It is equivalent to  
`msg.payload = {"entity_id": msg.subflowParameter};`

---

<div class="post-metadata">

### Author: ![bakman2](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bakman2/32/6207_2.png) [@bakman2](https://discourse.nodered.org/u/bakman2)
#### Post date: [25 November 2019 21:20 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/14 "2019-11-25T21:20:07Z")

</div>

This topic reads like there is a quantum physics book being written.  
Instead of creating overly complicated functions, did you try to draw the actual flow from a to z (on paper) ?

---

<div class="post-metadata">

### Author: ![Noneangel](https://avatars.discourse-cdn.com/v4/letter/n/59ef9b/32.png) [@Noneangel](https://discourse.nodered.org/u/Noneangel)
#### Post date: [25 November 2019 21:41 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/15 "2019-11-25T21:41:39Z")

</div>

> [@bakman2](#):
>
> did you try to draw the actual flow from a to z (on paper) ?

Yes. It only takes two _extra_ nodes per subflow call: one for setting the payload correctly for the subflow, one for moving the result of the sublow graph to the location I want. By _extra_, I mean that I would prefer to get ride of them if possible.

That is not a big deal, I just wanted to know if it was possible / easy to do.

---

<div class="post-metadata">

### Author: ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)
#### Post date: [25 November 2019 21:48 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/16 "2019-11-25T21:48:34Z")

</div>

Not a problem.

Ok, so you have an API (external thingy) that allows "external" control of the switches also.

So, this "thing" reads the state of the switches/devices and can send this to NR.

It also allows external control of the switches/devices outside NR's control/purview (scope).

**New attack:**

Node-red ONLY sends commands to turn switches on/off. It does NOT store states of switches.

Any time a switch/device changes I would guess that the API sends a message.

If so, read the message from the API and use that to display the states.

Not that complicated.

Ok, reading a bit more of what you said, you may need to send a pulse to the node that reads the home assistant state....  
(from)

> [@Noneangel](#):
>
> That means the state of one device / light may change without node-red being notified. The node that I use in the subflow is meant to get the state of the device thanks to an api call to home assistant made through a specific node.

Possible?

---

<div class="post-metadata">

### Author: ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)
#### Post date: [27 November 2019 06:12 UTC](https://discourse.nodered.org/t/subflow-as-a-function/18017/17 "2019-11-27T06:12:47Z")

</div>

If you want, post the part of the flow which has the API in it and I will see what I can do for you with it.
