Как использовать таймер Java, чтобы отказаться от всех задач, выполненных в быстрой последовательности, кроме последней

Если я не объяснил это должным образом, пожалуйста, помогите мне исправить мой вопрос. Мой вопрос может быть связан с таймером Java или может быть связан с решением общих проблем.

Уважаемый читатель, вам не нужно понимать, что такое OpenHAB, что такое правило OpenHAB или что делает MQTT. Но я все равно буду использовать эти термины, чтобы задать тему моего вопроса.

В OpenHAB у меня есть правило, которое отвечает на сообщения, опубликованные в теме MQTT. Когда я выключаю световой диммер, брокеру отправляется пакет сообщений MQTT «вниз». Каждое сообщение запускает правило OpenHAB, которое считывает текущее значение света и вычитает 1, а затем записывает его обратно.

Чтобы гарантировать, что правило не срабатывает одновременно в разных потоках (таким образом предотвращая затемнение света с правильной скоростью), мой коллега порекомендовал мне добавить lock.lock следующим образом:

rule "ArduinoBedroomVector"
    when
        Item Bedroomvector received update
    then
        lock.lock()
        try {
          // rules here
          var Number lightcircuit1level = BedroomCeilingLight.state as DecimalType
          switch(Bedroomvector.state) {
            case "light_1_up" : {
              lightcircuit1level = lightcircuit1level + 3
              if(lightcircuit1level>100) lightcircuit1level = 100
              sendCommand(BedroomCeilingLight, lightcircuit1level);
            }
            case "light_1_down" : {
              lightcircuit1level = lightcircuit1level -3
              if(lightcircuit1level<0) lightcircuit1level = 0
              sendCommand(BedroomCeilingLight, lightcircuit1level);
            }
          }
        }
        finally {
          lock.unlock()
        }
    end

и это сработало.

Теперь мой актуатор не пропускает сообщения «вниз».

Однако из-за того, что исполнительному механизму требуется некоторое время, чтобы ответить на каждое отдельное сообщение (он работает на частоте передачи 433 МГц, каждое сообщение радиочастотного сообщения отправляется за 0,5 секунды), команды диммирования для исполнительного механизма выстраиваются в очередь.

Поэтому мне нужно ввести способ проверки, чтобы увидеть, выполнялось ли правило в последний раз, например. 0,6 секунды. Если это так, увеличьте значение, но не отправляйте команду. Если это не так, увеличьте значение и, наконец, отправьте команду.

Например, это означает, что я могу непрерывно увеличивать и уменьшать яркость света, и пока я не остановлюсь, уровень освещенности не изменится. Затем, как только я решу остановить затемнение вверх или вниз, уровень освещенности будет доработан и установлен.

Еще лучше «правило» синхронизации, которое позволило бы мне постоянно менять уровень, но устанавливать уровень освещенности только каждые 0,5 секунды в соответствии с последним уровнем.

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


person hazymat    schedule 01.02.2015    source источник


Ответы (1)


Не будьте слишком строги к себе, это не так очевидно.

Мой подход состоит в том, чтобы сохранить отметку времени самого последнего выполнения правила и добавить оператор if перед вызовом sendCommand, чтобы проверить, прошло ли не менее 0,6 секунды.

Однако есть один пограничный случай, когда, если последнее получение команды a произошло до того, как прошло 0,6 секунды, новое значение никогда не будет отправлено, поэтому нам нужно установить таймер, чтобы опубликовать это последнее значение. Но затем нам нужно очистить таймер, чтобы он не срабатывал, если мы получили новую команду после того, как таймер был установлен, но еще не сработал. Пограничные случаи беспорядочны.

var lastExec = now.millis
var Timer timer = null

rule "ArduinoBedroomVector"
when
    Item Bedroomvector received update
then
    lock.lock()
    try {
      // rules here
      var Number lightcircuit1level = BedroomCeilingLight.state as DecimalType
      switch(Bedroomvector.state) {
        case "light_1_up" : {
          lightcircuit1level = lightcircuit1level + 3
          if(lightcircuit1level>100) lightcircuit1level = 100
          // Wait to send the new value
        }
        case "light_1_down" : {
          lightcircuit1level = lightcircuit1level -3
          if(lightcircuit1level<0) lightcircuit1level = 0
          // wait to send the new value
        }
      }

      // if more than .6 seconds have passed since the last time the value was sent
      if((now.millis - lastExec) > 600){
        // cancel the timer if one is already set
        if(timer != null) {
          timer.cancel
          timer = null
        }
        sendCommand(BedroomCeilingLight, lightcircuit1level)
        lastExec = now.millis
      }
      // its too soon to send the update, set a timer
      else {
        // cancel the timer if one is already set
        if(timer != null) {
          timer.cancel
          timer = null
        }
        // set a timer to go off in what is left of the .6 secs since the last update
        var t = now.plusMillis(600) - lastExec
        timer = createTimer(now.plusMillis(t), [|
          sendCommand(BedroomCeilingLight, lightcircuit1level)
          lastExec = now.millis 
          // beware, there could be a race condition here as the timer
          // will execute outside of the lock. If the rule executes 
          // at the same time as the timer the most recent value of
          // lastExec may be overwritten with an older value. It should 
          // happen very rarely though and may not be a problem.
        ]
      }
    }
    finally {
      lock.unlock()
    }
end
person Richard Koshak    schedule 11.06.2015