Text bug in node red design?

Been a while.
Im exerpiencing this issue in node red :

My code in the node is :

module.exports = function (RED) {
  function rotating_machine(config) {
    //create node
    RED.nodes.createNode(this, config);

    //call this => node so whenver you want to call a node function type node and the function behind it
    var node = this;

    //fetch class
    var Machine = require("./dependencies/machine_class");

    //make new class on creation to work with.
    var machine = new Machine();

    //fetch name from node into the machine code
    machine.name              = config.name;
    machine.number            = Number(config.number);
    machine.supplier          = config.supplier;
    machine.type              = config.machine_type;
    machine.position.sync_delay  = Number(config.sync_delay);
    machine.position.startup     = Number(config.startup);
    machine.position.shutdown    = Number(config.shutdown);
    machine.position.warmup      = Number(config.warmup);
    machine.position.cooldown    = Number(config.cooldown);

    /*------------ Declare node functions -----------*/
    function update_node_state(){
      switch ( machine.mode ){ 
        //virtual operator
        case 0:
          switch ( machine.position.o_state ){
            //off
            case 0:
              node.status({ fill: "red", shape: "dot", text: "VR operator : OFF " });
              break;
            //on
            case 1:
              node.status({ fill: "green", shape: "dot", text: "VR operator : " + machine.position.set + "%" });
              break;
            //default
            default:
              machine.error.text = "no such state : " + machine.state + " in mode : " + machine.mode ;
              machine.error.state = true;

          }
          //break case 0
          break;
        
        //auto ( for now the 2 states give the same output ... open the curve however should we move write output to this part? seems to make more sense)
        case 1:
          switch ( machine.position.o_state ){
            //off
            case 0:
              node.status({ fill: "red", shape: "dot", text: "Autonomous :" + "OFF " });
              break;
            //on
            case 1:
              node.status({ fill: "green", shape: "dot", text: "Autonomous : " + machine.position.set + "%" });
              break;
            //force a machine to stay on (for example when warmup time locks the machine)
            case 2:
              node.status({ fill: "blue", shape: "dot", text: "Autonomous forced : " + machine.position.set + "%" });
              break;
            //default
            default:
              machine.error.text = "no such state : " + machine.state + " in mode : " + machine.mode ;
              machine.error.state = true ;
          }
          //break case 1
          break;

        //local operator (does almost the same as the virtual operator with soul difference that we depend on the machine to give us their position in order to calculate anything)
        case 2:
          switch (machine.position.o_state){
            //off
            case 0:
              node.status({ fill: "red", shape: "dot", text: "Local operator : OFF " });
              break;
            //on
            case 1:
              node.status({ fill: "yellow", shape: "dot", text: "Local operator : " + machine.position.set + "%" });
              break;
            //default
            default:
              machine.error.text = "no such state : " + machine.state + " in mode : " + machine.mode ;
              machine.error.state = true ;
          }
          //break case 2
          break;

      //default
        default:
          machine.error.text = "No such mode : " + machine.mode ;
          machine.error.state = true;
      }
    }

    
    function send_output(){
      let msgs = [];

      msgs[0] = { topic : ("ctrl_"+ machine.number) , payload: machine.o_flow };
      msgs[1] = { topic : "object" , payload : machine };
      msgs[2] = {
        topic: machine.name,
        payload: {
          ctrl: machine.i_ctrl,
          state: machine.state,
          flow: machine.o_flow,
          pressure: machine.i_pressure,
          power: machine.o_power,
          o_ctrl: machine.o_ctrl,
        },
        measurement: machine.name+machine.number,
      }; //output to database

      //send outputs
      node.send(msgs);
    }

    //never ending functions
    function tick(){
      machine.tick();
      update_node_state();
      send_output();
    }

    // register machine on first output this timeout is needed because of node - red stuff
    setTimeout(
      () => {
        
        /*---execute code on first start----*/
        let msgs = [];
        msgs[0] = { topic : "register_machine" , payload: machine };
        //send msg
        this.send(msgs);
      }, 
      100
    );

    //declare refresh interval internal node
    setTimeout(
      () => {
        /*---execute code on first start----*/
        var f = setInterval(function(){ tick() },1000)
      }, 
      100
    );
  
    //-------------------------------------------------------------------->>what to do on input
    node.on("input", function (msg,send,done) {      
      
      /* --------------------- input --------------------- */
      if ( msg.topic.match(/pt.*/)){
        machine.i_pressure = msg.payload;
      }

      //set current flow 
      if ( msg.topic.match(/ft.*/)){
        machine.i_flow = msg.payload;
      }

      //set current power
      if ( msg.topic.match(/et.*/)){
        machine.i_power = msg.payload;
      }


      /* --------------------- change mode  --------------------- */

      if(msg.topic == "mode_change"){
        machine.mode = msg.payload;
      }


      /* --------------------- change state  --------------------- */

      if ( msg.topic == "state_change"){
        switch( msg.payload ){
          case 1:
            //automatically switches the machine to minimum flow
            machine.switch_on();
            break;

          case 0:
            //automatically switches the machine to minimum flow
            machine.switch_off();
            break;

          default:
            //no such state
            node.error('no such state for machine');
        }
      }

      //input from user
      if(msg.topic == "i_ctrl"){
        machine.i_ctrl = msg.payload;
      }   

      //input from auto software
      if(msg.topic == "hapo_i_ctrl"){
        
        if (msg.payload[machine.number] >= 0 ) {
          if(machine.state == 0){
            machine.switch_on();
          }
          
          machine.i_ctrl = msg.payload[machine.number];
        }
        else{
          if(machine.state != 0){
            machine.switch_off();
          }
         
        }
        
        
      }   

      /*-------------------------------- Node Messaging ------------------------------*/

      done();
      
    });
  }
  RED.nodes.registerType("rotating_machine", rotating_machine);
};

is this a node red bug? The first time I run this when restarting node red the node runs like normal and the visualisation also. As soon as I deploy another change regardless where it looks like it spawns 2 the same nodes which each have their own refresh rates?

Every time a node is deployed, it is recreated. You must clean up / close down timers and other connections/resources in the nodes 'close' handler.

1 Like

Yeah I suspected as much.... Could you give me a simple example in plain java how to close this interval repeater? Im looking at the inject node in the core but to be very honest I don't understand all the strict typescript what is going on there... so anything you could give me to start with would be very much appreciated. :slight_smile:

Hi @znetsixe

There are two parts to this.

First, you need to store the value returned by setInterval - as that is the handle you have in order to stop it running later.

So where you have:

var f = setInterval(function(){ tick() },1000)

Replace it with:

node.interval = setInterval(function(){ tick() },1000)

Then you need to add a handler for the close event. Just above your node.on("input"... line, add the following:

    node.on("close", function () {
      clearInterval(node.internval)
    })
1 Like

I geuss steve allready brought me half way and looking into the core node I found like you said that storing the interval in a var (this.interval_id) and then later in node.on closing it down exactly as you specified does the trick!

Thanks both!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.