Постоянно проверять значение объекта и завершать процесс, если оно ложно

Я создаю систему управления для машины с Node на Raspberry Pi. Есть определенные процессы, которые необходимо немедленно остановить при размыкании одного из реле безопасности. Итак, мне нужно каждые 100 мс проверять, открыты ли реле безопасности, и, если они открыты, посылать сигнал о прекращении выполнения определенных функций.

В общем, будет несколько функций, которые необходимо остановить, если Relays.allClosed станет ложным.

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")
  }
}

Почему бы просто не выдать событие realyOpened, а затем дождаться его? И idlf, который действительно является «реле безопасности», я бы не стал писать код на JS.

Jonas Wilms 10.08.2018 15:17
setTimeout срабатывает только один раз, возможно, вам понадобится setInterval.
Keith 10.08.2018 15:17

@JonasWilms, можете ли вы уточнить оба момента? издавать звуки правильно, но мне нужно увидеть пример, спасибо

chuckieDub 10.08.2018 15:19

@Keith да, но решение, о котором упоминает Йонас, намного более эффективно и в принципе хорошо.

Victor 10.08.2018 15:19

Что такое //...some stuff? Не могли бы вы добавить небольшой образец?

Jonas Wilms 10.08.2018 15:21

Как вы обновляете Relays.relay1 / 2 при изменении состояния физического оборудования?

Jamiec 10.08.2018 15:21

@JonasWilms добавил образец, @Jamiec еще не зашел так далеко, но будет использовать пакет onoff: npmjs.com/package/onoff

chuckieDub 10.08.2018 15:27

А как насчет сеттера? Что-то вроде: set relay({ index, value }) { this[`relay${index}`] = value; this.check(); }, а затем вы должны вызвать: Relays.relay = { index: 1, value: true };

Jose Hermosilla Rodrigo 10.08.2018 15:42
1
8
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам следует использовать что-то вроде EventEmitter, чтобы генерировать событие, когда происходит что-то значимое. Это может быть изменение состояния вашего значения allClosed (хотя я бы сказал, что ваш метод постоянного опроса измененного состояния реле является анти-шаблоном, и вам следует использовать логику, основанную на событиях).

Но в любом случае, предполагая, что событие allClosed возникло, вы можете зафиксировать это событие и остановить свой работающий код:

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")
  }
}

Это будет отменено на следующей итерации, но если pressLoop каким-либо образом работает долго, вы должны предусмотреть остановку и его на полпути.


В приведенном ниже коде показано (с кнопками вместо физических реле), как вы можете запустить целую серию событий.

// 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>
Ответ принят как подходящий

Вместо этого вы должны использовать структуру, основанную на событиях, например:

  const EventEmitter = require('events');

  const input = new EventEmitter();

Благодаря этому вы можете генерировать события как:

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

Таким образом, вы можете прикрепить обратный вызов к реле в нескольких позициях:

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

Теперь, чтобы получить еще одно событие, когда все реле включены, достаточно просто:

 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);

Теперь при запуске тайм-аута, как в вашем примере, вы можете легко отменить его, если некоторые из них выключены:

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

Есть ли альтернатива watch, поскольку она устарела?

chuckieDub 11.08.2018 18:27

Можете поделиться ссылкой?

chuckieDub 11.08.2018 18:38

@chuckieDub отправленную ссылку?

Jonas Wilms 11.08.2018 18:39

Я не отправлял ссылку. Когда я ищу "часы" в документации, все, что я могу найти, это fs.watch nodejs.org/docs/latest/api/fs.html

chuckieDub 11.08.2018 18:41

ага, попался :) теперь имеет смысл

chuckieDub 11.08.2018 18:46

Другие вопросы по теме