简体   繁体   中英

Constantly check for object value and end process if false

I'm building a control system for a machine with Node on a raspberry pi. There are certain processes that need to stop immediately if one of the safety relays opens. So, I need to checking every 100ms id the safety relays are open, and if they are, send a signal to stop running certain functions.

In general, there will be several functions that need to stop if Relays.allClosed becomes false.

 var Relays = { relay1: false, relay2: false, allClosed: false, checkRelays: function() { if (this.relay1 == true && this.relay2 == true) { this.allClosed = true } else { this.allClosed = false console.warn("relay open") } } } var safetyCheck = function() { //checks if safety relays are all closed every 100 ms setInterval(function() { Relays.checkRelays() }, 100) } safetyCheck() Machine.run = function(distance) { if (Relays.allClosed) { //checks before running the process if the relays are all closed for safety // if at any point while running this Relays.allClosed becomes false, function needs to stop running setTimeout(function() { console.log('advancing press'); i++; if (i < distance) { pressLoop(); } }, 1000) } else { console.log("can't run machine because one or more safety relay is open") } } 

What you should be doing is using something like EventEmitter to emit an event when something meaningful happens. This could be a change in state of your allClosed value (although I'd argue that your method of continually polling for a changed relay state is an anti-pattern and you should be used event-based logic throughout).

But in any case, assuming an allClosed event is raised you can capture that event and stop your running code:

Machine.run = function(distance) {
  if (Relays.allClosed) { //checks before running the process if the relays are all closed for safety
    // if at any point while running this Relays.allClosed becomes false, function needs to stop running
    let timer = setTimeout(function() {
      console.log('advancing press');
      i++;
      if (i < distance) {
        pressLoop();
      }
    }, 1000);

    myEventEmitter.on("allClosed", () => {
       clearTimeout(timer);
    })
  } else {
    console.log("can't run machine because one or more safety relay is open")
  }
}

This will cancel at the next iteration, but if pressLoop is in any way long-running, you should provision for stopping that midway too.


The below code illustrates (with buttons in place of physical relays) how you can run the whole thing a series of events.

 // just jQuery for mockup - ignore $('.relay').on("click", function () { $(this).toggleClass("open").toggleClass("closed"); events.emit("relayChanged", {id:$(this).data("id"), isClosed: $(this).is(".closed")}) }) function RelayMonitor(){ var relaysClosed = { "1": true, "2": true } this.init = function(events){ events.on("relayChanged", (args) => { relaysClosed[args.id] = args.isClosed; if(Object.values(relaysClosed).every(x => x)) { events.emit("allClosed"); } }); } } //const EventEmitter = require('events'); // included as cdn import here var events = new EventEmitter(); events.on("allClosed", () => console.log("all relays closed")); var monitor = new RelayMonitor() monitor.init(events); 
 .closed { background-color:green } .open { background-color:red } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/EventEmitter/5.2.5/EventEmitter.js"></script> <button data-id="1" class="relay closed">Relay1</button> <button data-id="2" class="relay closed">Relay2</button> 

You should go with an event based structure instead like:

  const EventEmitter = require('events');

  const input = new EventEmitter();

Through that, you can emit events as:

 relay1.watch((err, value) => input.emit("relay1", !!value));

That way, you can attach a callback to the relay at multiple positions:

 input.on("relay1", on => console.log(on));

Now to get another event when all relays are on its as easy as:

 let relaysCount = 0;
 function updateCount(on) {
   if(on) { 
     relaysCount++;
     if(relaysCount === 2)
       input.emit("allOn");
   } else { 
     relaysCount--;
     input.emit("someOff");
  }
 }

 input.on("relay1", updateCount);
 input.on("relay2", updateCount);

Now when starting a timeout like in your example, you can easily cancel that if some are Off:

 input.on("allOn", () => {
    const task = setTimeout(/* sth */, 1000);
    input.on("someOff", () => clearTimeout(task));
 });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM