I have simple push butons that send out an ON message on a mqtt topic and an OFF message to the same topic when they are released.
This works great for turning lights on and off with a simple rule
rule "toggle"
when
Item mqttSwitchIn2 received command ON
then
if (modbusSwitchOut1.state != ON)
modbusSwitchOut1.sendCommand(ON)
else
modbusSwitchOut1.sendCommand(OFF)
end
But now I would want to som somthing while I’m waiting for the OFF command when my rule is running.
Something like this
rule "toggle"
when
Item mqttSwitchIn2 received command ON
then
if (modbusSwitchOut1.state != ON)
while(!mqttSwitchIn2 received command ON){
dimmer.state -= 10;
Thread::sleep(100);
}
modbusSwitchOut1.sendCommand(ON)
else
modbusSwitchOut1.sendCommand(OFF)
end
First of all I’m not sure what I’m doing here is even a good design, measuring the time between 2 mqtt commands and action on it.
I would need a listener that listens for the OFF command being received, but I cannot really find something in the forums
I’d use a variable to hold the milliseconds. then make a rule for state changed from OFF to ON and safe new Date().getTime() to your variable. Then make a new rule for state changed from ON to OFF. Get the time again and substract your safed value. Now you know how many milliseconds passed between the on and off event and can act accordingly.
Sorry I’m not at home right now so i can’t provide you a proper code example but this should work.
So, I am home now and i gave it quick try this seems to work for me:
var Number millis
rule "timer on"
when
Item DummySwitch changed from OFF to ON
then
millis = now.getMillis()
end
rule "timer off"
when
Item DummySwitch changed from ON to OFF
then
var duration = now.getMillis() - millis
DummyDuration.sendCommand(duration)
end
The second rule is where your actual logic would happen. a switch case for example.
I hope this what your looking for, not sure if i correctly understood the question.
I like @hrc’s solution but there is one error case not covered: what if the OFF is lost or never comes?
To manage that I would use the Expire binding on DummySwitch to automatically set it to OFF after a long enough period of time to know that the OFF never happened or was lost.
Hey cool, i wasn’t aware that rules could have state; How is this state managed? Is this like an object and what is the lifecycle of the oject?
My pattern is a bit different since I don’t have a switch that I control, but I can create a switch just to keep the state.
I do want to update my dimmer during.
The state is kept in global vars and vals which are declared before your first rule in the file. They will be initialized when the .rules file is first loaded and remain until the file is loaded again at which time the state is lost and they get reinitialized.
Global variables are only available to rules in the same file they are declared. You cannot access a global variable defined in another .rules file.
Personally, I recommend storing state in Items most of the time because it lets you do things like:
use persistence to restore the state on a reboot or reload of the .rules files
access the state from multiple .rules files
visualize the state on your sitemap
But there are often cases where one doesn’t need the above. This is one such case. Another common case is when using Timers and ReentrantLocks.
If this is something you built yourself with Arduino or similar, I would suggest to detect this on the MCU side and send appropriate MQTT command. The onebutton library can do that for you.
At least if you ever want to go for doubleclick detection, then everything is about milliseconds and you cannot afford the network latency.
Hmm, this is interesting. I’m using a PLC as my controller. I could read everything with modbus, but this is very inefficient from an engineering standpoint (polling), this is why I’m trying to build this with mqtt that only sends a command when a button is pushed. But I want immediate feedback. This is why I’m sending an ON command when the push button is pressed and a OFF command when the button is release. So I can react when someone touches the button and start dimming right away. You are the first now that tell me to do this on the MCU side.
It just seems to be causing much overhead.
Having a switch where I need to react on, having a button to store the state (this can be my output switch), having a Number to store the time the button is pressed and applying this to a dimmer. Binding this all together with a rule. Repeating this for 20 (or so) switches.
I’ll look up some real life openhab configs that drive an entire house, perhaps this would help me to understand this better
edit:
I’m now thinking of solving it another way.
Instead of sending an ON command when someone presses a button and sending an OFF command when they release it. Perhaps this would be better (500 is just a parameter, as an example).
press single < 500ms -> send PRESSED command
press twice < 500ms -> send DOUBLE command
keep pressing >500ms -> send LONG command for each interval of 500ms
The pressed command would just be used as a toggle for a Switch
The double could be an extra command
The long press would reduce a dimmer each time
Perhaps have a look at the lib I mentioned. But AFAIR, this is basically what it does (in the sense of callback functions instead of MQTT commands, but in my case, the callbacks send the MQTT commands), with an additional LONGSTART and LONGSTOP.
I use this for a light switch with double push buttons. It is very responsive (in contrast to the single push button commercial dimmer thingy I have in another room, that is terrible.)
Left click - switch on/off
Left hold - increase brightness
Right hold - decrease brightness
Right click - toggle through lamp groups
Right doubleclick - reset to main lamp group
I got it working, the code is not very clean an can be improved at many points, but this is my base now
basically I have a timer when a button goes on and i count the edges for the time the timer is running.
Encapsulate this in a function on my plc, bind it to the different inputs and I can handle everything on openhab
pub := FALSE;
subi := FALSE;
topic := 'dev/switch/2';
(*payload:= '';*)
tx(IN:=%IX0.2,PT:=t#1000ms);
(* Q == true -> pressed *)
IF %IX0.2 THEN
IF NOT tx.Q THEN
IF CNT = 0 THEN
payload := 'long';
pub:=TRUE;
long:=TRUE;
(* need to reint the counter, still going strong! *)
tx(IN:=FALSE,PT:=t#1000ms);
tx(IN:=%IX0.2,PT:=t#1000ms);
END_IF
END_IF
ELSIF tx.Q AND edge THEN
(* found an edge!*)
cnt := cnt +1;
END_IF
IF NOT tx.Q AND cnt>0 THEN
pub:=TRUE;
payload := INT_TO_STRING(cnt);
cnt := 0;
END_IF
edge := %IX0.2;
Hello, I am trying to have a push button with mqtt in openHAB2. The functionality should be like, when I click it show ON command in MQTT and as soon as I release the click it shows me the OFF command. Can you help me with items and sitemaps file.?
Where are you clicking? An actual switch or on the screen?
If it’s on the screen, you can’t do that with a sitemap.
There may be a way with HABpanel but I don’t know how…
As I said, the publicly available library OneButton does the detection for you. Then you can decide in the callback of the respective click type what to do. I as far as I remember, I decided to send an MQTT notification to OpenHAB, but actually trigger the light action from the MCU directly in addition. Originally, I only planned that as an offline fallback but I never changed it once it worked.