0

これを適切に説明していない場合は、質問を修正するのを手伝ってください。私の質問は、Java タイマーに関連している可能性があります。または、一般的な問題解決に関連している可能性があります。

親愛なる読者の皆様、OpenHAB とは何か、OpenHAB ルールとは何か、実際に MQTT が何をするのかを理解する必要はありません。しかし、とにかくこれらの用語を使用して、質問の場面を設定します。

OpenHAB には、MQTT トピックに発行されたメッセージに応答するルールがあります。照明の調光器を下げると、「ダウン」MQTT メッセージのバーストがブローカーに送信されます。各メッセージは、ライトの現在の値を読み取り、1 を引いてから書き戻す OpenHAB ルールを起動します。

ルールが異なるスレッドで同時に起動しないようにする (したがって、ライトが正しい速度で暗くなるのを防ぐ) ために、私の同僚は次のように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

そしてこれは御馳走でした。

これで、私のアクチュエーターは「ダウン」メッセージを見逃すことはありません。

ただし、アクチュエータは個々のメッセージに応答するのに少し時間がかかるため (アクチュエータは 433MHz の RF 送信で実行され、各 RF メッセージ メッセージの送信には 0.5 秒かかります)、アクチュエータへの調光コマンドが待ち行列に入れられます。

そのため、ルールが最後のたとえば 0.6 秒で実行されたかどうかを確認する方法を導入する必要があります。その場合、値を増やしますが、コマンドは送信しません。そうでない場合は、値を増やして、最後にコマンドを送信します。

たとえば、これは、ライトを連続的に暗くしたり、暗くしたりしても、停止しない限り、光のレベルが変わらないことを意味します。次に、調光のアップまたはダウンを停止することを決定するとすぐに、光レベルが確定されて設定されます。

さらに良いのは、レベルを継続的に変更できるが、最新のレベルに応じて 0.5 秒ごとに光レベルを設定できるタイミング「ルール」です。

これは、ルールの実行時にチェックされるタイマーを作成する場合にすぎないと確信していますが、タイマーをいつ作成してチェックする必要があるのか​​ わかりません。これはおそらく多くの人にとって盲目的に明らかです。

4

1 に答える 1

0

自分に厳しくなりすぎないでください。

私のアプローチは、ルールの最新の実行のタイムスタンプを保持し、sendCommand を呼び出す前に if ステートメントを追加して、少なくとも 0.6 秒が経過したかどうかを確認することです。

ただし、a コマンドの最後の受信が 0.6 秒経過する前である場合、新しい値が送信されないというエッジ ケースが 1 つあります。そのため、最後の値を公開するためにタイマーを設定する必要があります。ただし、タイマーが設定された後に新しいコマンドを受け取ったが、まだ起動されていない場合は起動しないように、タイマーをクリーンアップする必要があります。エッジケースは厄介です。

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
于 2015-06-11T16:10:19.337 に答える