Node red - write a function and call it from a function

Hello,

I am learning node red and I need help to optimize a flow that I have created.

This is the flow : Node red project - Pastebin.com

To make this flow work, you need additionally to import : node-red-contrib-zigbee2mqtt-devices/scene-selector.md at master · Dirnei/node-red-contrib-zigbee2mqtt-devices (github.com)

I have smart switches installed at home with tasmota firmware. All the light are tuya based smart bulbs.

After pressing buttons on the smart switches, they send mqtt commands for which I wrote functions that routes them to appropriate action (turn on and off , dimmer up and down, cycle created scenes,etc).

I do not know if it has been made in the best way, but it works.

It is not finished yet, but it becomes more and more complex every time I add something new.

So I want to reduce and organize better the nodes and the written code, so if errors will occur it will be more easier to find a solution.

I have some questions for which I hope to receive some hints.

  1. After the node "check status light", we have "Action", "choose single" (a button of a switch is pressed once) and "choose double" (the button is pressed two times) nodes which I would like to merge them into one function called "Switch" that I started already to write. I have also another function node called "dimmer" which I would like to keep it separate, because I do not want to make these functions too long and not readable. So the idea is to call the already made function dimmer from the switch node. Honestly speaking, I do not know how to do it. Could you help me?
  2. The other thing are the scene selection nodes. If possible I do not want to use them, I will prefer to use code written by my selves. I have created 6 scenes in home assistant, two for each room. Every room has multiple smart bulbs connected to a button of a smart switch. In every room we have a default scene and a relax scene. The default one, all the bulbs have been set to white mode, while in the relax scene, the bulbs have different colours. I would like to add more scenes in the future.

It works in this way, pressing the first button switch, it turns on or off the group of lights. Pressing the first button two times, it dimmers up the light if it is on and it has 4 brightness steps afterwards it is set to the minimum brightness again. Pressing the second button switch, it cycles between the two created scenes default and relax. I want with every next button press to cycle all the created scenes.Here I want to use something written by my selves, but I do not know how to get the previous selected scenes so to set the next one. Any ideas?

Hi @ronyn77!
Welcome to this forum!
One comment upfront: For my personal taste you're relying too heavily on the Function node, but anyway...

There's a feature called context (with different levels of scope: global, flow, node, ...) in Node-RED. You could write a function and store it in the context - to call it on demand:

let f = function(text) {
  console.log(text);
}
flow.set("debug", f);

In another node:

let f = flow.get("debug);
f("hello");

Yet ... well, as I said: That's usually not necessary with Node-RED. You should compose your functionality with nodes & then use either Subflows or LinkCall / LinkIn / LinkOut nodes to reuse parts of a flow.

This is almost the same pattern: You may use as well a context to store the current scene & retrieve it at the next cycle.

Enjoy working with Node-RED!

Thank you for the hint. But I am a newbie and it would be more clear with an example.
This is what I have done :

In test I put the code you wrote in the first batch of rows, while in test the second batch.
Of course it returns error.
I do not need this node "test" to be called from other places than in this specific flow. It is just for avoiding to write complex functions with hundreds of rows.

It is not clear for me how to use the context storage, honestly speaking.

Thats why I posted you a link to the documentation of Node-RED (click on the word context in the post above or the quote here below to get there!) that introduces you to this feature:

Now, I have understood what you mean...actually I've seen that there was a flow.set command, but I wasn't paying attention to it.
Anyway, in order to work, I've added an inject node to the function, and after inject it, it worked.

I have other two questions in regards :

  1. you defined a function called "f"..why do you also put "debug" into the flow.set? Then, you recalled the function using "debug" and not f. I cannot understand why and I cannot understand why you put both "variables"; Probably I have understood....."debug" is the variable name, while f is its value....is it correct?
  2. If I not press the inject button at least once, it will not work. If I restart node red and I do not press inject, it will not work....how to do it so it can automatically run once?
  1. The function is called f, the context that it is saved in is called 'debug' - did you read the documentation on context?

  2. If you set the inject node to inject once it automatically injects whatever you have asked it to whenever Node-red starts or you restart flows etc.

image

You should probably watch the short videos about Node-red on u-tube.

The Function node has a tab labeled On Start. If you place your code to initialize the function there, it will always be called when this node starts.

And once again:

  • This is not the way things are usually done in Node-RED.
  • Please get yourself familiar with the Node-RED features, either reading thoroughly through the documentation or by watching the provided videos!

Enjoy working with Node-RED!

Ok, but if I put an inject node before and I configured it as Buckskin told...will it be the same or not?
If a function node is part of a flow, could you make me an example where it will not be called if it is not 'on start'?

You are not the first one you are telling me that this is not the way things are usually done in Node-Red. What exactly do you mean? To use more the existing nodes and avoid programming too complex function in javascript? Or what?

The proposal of @Buckskin is fully valid - yet not necessary to meet your requirements: The Function node has a build in feature to run code when the node is started - for exactly the use case you have: Initialize something that is necessary later, when the node runs regularly.
As always, there're several ways to reach a target; I propose to operate on the one with the least effort - using a built-in feature.

In short: Yes.
With a few more words - based on the example of your first function node labeled Switch case:

  • Your function node is - as the label says - a giant switch case. There's a node dedicated to do this, the Switch node.
  • Then you're setting some parameters based on which button was pressed. This is what the Change node was made for.
  • One benefit of using nodes vs. a function: You can see what's happening - without a lot of additional comments:

Compare this ...

versus this (not completely designed yet):

I propose to optimize as well the msg data structure... to easier handling...
Hope this helps a bit.

Thank you very much for the given help/hints.

I will start to follow your suggestion and in a second moment, I will try to rewrite my flows as intended.
In the past I was a programmer, so for me it was natural to write codes instead of using already made functions/nodes, because in this way I can personalize everything in the way I want.
The other point was to avoid doing so big flows with many nodes and simplify the flow using some functions which combines more nodes at once. Probably the best is to find a compromise between the two, but for now I am learning and in the future when I will have more experience I will evaluate better how to do it.

I have some other questions and I would be grateful if you could answer me.

  1. I look at the pictures you posted. They are visualized in the right way and they fit in the square of the post. These pictures attached by me, using a link, they do not look good until you press on them. What should I do to post the pictures in the way you made it?
  2. You build the flow in a way that I am sure you looked at the code written by me. So, returning to my switch node, I put in many places a debug function like node.warn("tasmota_camera:something went wrong") where "tasmota_camera" identify one of the switches around my house. The idea was to catch an error that sometimes I have "input error" and I cannot understand why. It is not a good solution to do it in this way for many reasons but mainly because I need to keep open and look at the debug view of node red. The second thing is that I want only to see the error message and not all the messages. The third thing I would like to see is the entire object when the error occurs. So in this way I can correct better the logic.
  3. returning again to my flow and looking into the choose single or double function that I made. If I want to change this simple function using only node red nodes, first I have to put a switch node followed by a change node, is it correct? Or there is a better way in which I can use only one node? The other question I have regarding the switch node...if I have multiple conditions to met how should I use it? eg. IF (a==x || b==y &&c!==z)

You may paste directly from the clipboard into the editor. This uploads the pics & even provides a tiny interface to size them.

This is done with Debug nodes. When developing, you usually have a lot of them wired to the acting nodes to understand whats happening...

None but you can answer this - as we've only seen a sniplet of the code & not (!) the payload of the msg. Node-RED is all about manipulating the msg object.

The core nodes do not support this (AFAIK) - and there are a lot (about 4000) contributed nodes, that are at hand to solve most of the other topics. Check the flow library; with a bit of luck, you'll find a node that acts as you need it...

I know this and I have already done it while developing it. So far, it seemed to work. A couple of days ago when I start to optimize the code while the flow was still running, I noticed that sometimes it generated some errors in the debug window, but I didn't manage to catch it or to understand the error, because it was only an error message like "input error". I do not know how to replicate it so to generate the error again and catch it. This is why I am looking for another solution....I cannot stay in front of the monitor and wait until the error occurs again. So the best solution for me is to save this information in a file as log and to write to this log only if an error occurs with the info of the entire msg. If I know how to do it, I will place and run this command from inside the function...if there is any other way, it would be also ok for me...no matter which would be the way, the important is to catch the error, so I can modify the function.

If it's not happening, you don't need to care. If it's of relevance, it will happen so often that you'll be able to folow it via the debug sidepanel.

There's an advantage doing it this way: Node-RED displays additional information, e.g. which node is throwing. You can achieve this (of course) as well by investing additional effort into programming work...

I have already told you that any message in in the debugger pane that is an error message from a node will be written to the node-red log, so you can search that log for the errors. Where that log is and how to access it depends on your OS and how you are running node-red.