Listening to config node events

Hi folks,

I'm a bit stuck with my node-red-contrib-onvif-nodes developments, which allows you to control an Onvif compliant IP camera from a Node-RED flow.

  • An Onvif camera 'can' offer 1 or more different Onvif services (PTZ, recording, events, ...), so I have implemented multiple Onvif nodes. This means you can have multiple nodes in the flow, controlling the SAME camera.
  • To avoid having to repeat the IP address, username, password ... over and over again in these nodes, I have introduced an Onvif config node. This way the configuration is entered once in the config node, and all other Onvif nodes can share the same config node. So far so good ...
  • Now I want to refactor my code, so only the config node communicates with the camera. Otherwise all nodes need to request the entire Onvif configuration from the IP camera, resulting in a lot of useles communication overhead.

Summarized this should be the end result:

image

Since the communication coding would be inside my config node, the config node status will change in time (disconnected, connected, error, ...). Since I want to display this status in all my other nodes, all my nodes need to keep track of the config node status.

Is it correct if I implement this like this:

  1. My config node is an event emitter, which generates 'status' events (every time the status changes).
  2. All my other nodes start listening for those status events, as soon as those nodes are starting.
  3. All my other nodes unregister their listener, as soon as a node 'close' event occurs.

Or is it perhaps not allowed to have an event-listener mechanism between nodes in a flow? Of course this way I have some kind of communication between nodes, without a visual wire in the flow editor. But on the other hand, it is only a config node...

Or could I introduce some kind of problems (after a partial?? deploy). For example the config node listener collection becomes empty (without my other nodes knowing it), or that my nodes are removed but the config node is still calling their listeners. But perhaps this kind of situations are not possible???

Thanks!
Bart

yes - as you have it - the config node can create events that your other nodes can register to... eg see serialport 25-serial.js line 48 etc

Hi Dave (@dceejay),
Awesome. Just what I need. Thanks a lot!!
Had been looking for an example in all kind of config nodes with centralized logic (like mqtt brokers, DB connections, ...) but for some reason I couldn't find it...

I'm going to try it tomorrow evening. Just had a quick look at that 25-serial.js file. I would expected in the on-close event handler a node.port.removeListener(...), but don't see any? Isn't this a problem when this node is removed, and the config node remains in the flow. Would expect that the config node then keeps emitting events to a listener from a removed node. And that the removed node cannot be removed by the garbage collector, since there is still a listener referring to it? And as a result the removed node will be kept in memory, and so it will keep processing those events send to it.

Or am I just getting paranoia from those pink pilules that I swallowed by accident :roll_eyes:

as usual it depends where it is attached ... in this case when we delete the connection (line 415) - that will delete / remove any attached listeners.... but yes they do need to be cleaned up somehow.

1 Like

Had you looked at the core mqtt nodes that do exactly that? The mqtt-broker config node holds the client connection to the broker. The in/out nodes register (and unregister) themselves with their broker config node, which does all the heavy lifting.

1 Like

@dceejay, @knolleary,
Both examples were very illuminating (also the 10-mqtt.js file)!

Since I wanted to play with NodeJs event emitter, I added an emitter/addListener/... to my config node. However had some strange results, and it appeared that my config node already contained all this functionality. Which might be logical, since we already handle events in our nodes :thinking:

So I re-used the available functionality to add my own onvif_status event:

function OnVifConfigNode(config) {
    RED.nodes.createNode(this, config);
    
    var node = this;
      
    // Somewhere in some asynchronous code I emit my event ...
    node.emit('onvif_status', "some status value");
} 

Then I can start listening to those events in my other nodes (which use above config node):

function OnVifPtzNode(config) {
    RED.nodes.createNode(this, config);
       
    var node = this;
        
    // Retrieve the config node
    var myConfigNode = RED.nodes.getNode(config.deviceConfig);
        
    if (myConfigNode ) {
          // Start listening for Onvif config nodes status changes
          myConfigNode.addListener("onvif_status", function(onvifStatus) {
              // Do something when the Onvif status changes ...
          });
    }
}

And that seems to be working fine!!!
But it is conspicious simple...
And you know "if it is too good to be true, then it is not true" :wink:
Is this a bad design for some reason?

looks good so far :slight_smile: just need to make sure it cleans up on close

1 Like

I am using the above code to create a listener in my module. All works great, except it adds a new listener anytime I edit one of the listener nodes (the listener stays in memory). I assume I need to remove the listener when the module closes. However, I am not clear how to get the appropriate listener.

node.removeListener("update", listenerx) ------ what do I use for listenerx.

You need to keep a reference of the listener function in your node, so you can remove it in your node's close event.

Hey Bert (@bertmartin),
When the node closes you have to remove the listener (which you have added when the node starts):

        node.on("close",function() { 
            if (node.listener) {
                node.deviceConfig.removeListener("onvif_status", node.listener);
            }
        });

You can see my code here. You can see there that I remember my listener in the node.listener variable, otherwise you indeed don't know which listener you have to remove ...

1 Like