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.