xoseperez / espurna

Home automation firmware for ESP8266-based devices
http://tinkerman.cat
GNU General Public License v3.0
2.99k stars 637 forks source link

Switch 'Released' and 'Pressed' events #2377

Open AlbanTic opened 3 years ago

AlbanTic commented 3 years ago

Dear All, When I press a button, I have multiple "PRESSED" events and when I release it, I have nothing. How can I do to get one event "PRESSED" and one event "RELEASED" instead ?

My hardware config is : **#define BUTTON1_PRESS BUTTON_ACTION_ON

define BUTTON1_RELEASED BUTTON_ACTION_OFF**

When I change in button.cpp : case debounce_event::types::EventReleased: { // return _buttonMapReleased( // event_emitter->getEventCount(), // event_emitter->getEventLength(), // event_delays.lngclick, // event_delays.lnglngclick // ); return button_event_t::Released; }

I have alternatively "PRESSED" and "RELEASED" events.

Best Regards

mcspr commented 3 years ago

If I understand correctly, what you want is to 'hold' the relay while the button is pressed? There is a separate button mode specifically for this, try this out instead:

#define BUTTON1_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH | BUTTON_SET_PULLUP
#define BUTTON1_CLICK BUTTON_ACTION_TOGGLE

Since 'Click' is triggered for both states, you will switch the relay when they change.

But you are correct in that the 'released' event is never triggered, since there is no button_event_t::Released and BUTTON1_RELEASED is not a valid build flag :)

AlbanTic commented 3 years ago

So that is the question, how can I detect button released ? Best Regards

AlbanTic commented 3 years ago

Can you reopen this topic ?

mcspr commented 3 years ago

So that is the question, how can I detect button released ?

Like I said, just use the switch in the config? Pushbutton in config will cause the 'released' event to map to click or multiclicks, I am not sure how you intend to interpret 'released'?

Or, do you mean to detect it programmatically (broker or otherwise)?

AlbanTic commented 3 years ago

When I use the switch in the config I have several click events when the switch is ON and nothing when I switch it OFF. I try to get only 2 events : when I switch button ON => eventOn and when I switch the button OFF => eventOff (trigger detection I think) How can I do this ?

mcspr commented 3 years ago

Just using a basic wire between GND<->GPIO5, I get exactly one 'Click' event per connection / disconnect. Could you check the wiring, perhaps?

Another thing to note, we don't actually track the default state for the switch. Meaning, if you leave the switch in a certain state and reboot the firmware, it won't try to read the 'default state' similar to pushbutton and make the click event. Something to change, idk about backwards compatibility though

AlbanTic commented 3 years ago

Ok, I better understand.... Yes I need to get the state of the switch at reboot. I think I have interferences although I increased BUTTON_DEBOUNCE_DELAY and that's why I had many click event. Thank you for your help ^^ Maybe this function in button.cpp can return the button state ? bool button_t::state() { return event_emitter->isPressed(); }

AlbanTic commented 3 years ago

Yes, perfect :) I must understand how to rebase with VsCode because I am notified that modification is pushed ^^ I still have multiple "click" due to hardware because (as you said) when it's connected to ground on a different hardware it's ok, I have a 50Hz interference I think, I must change my wiring diagrams..... With tasmota (sorry for the reference) I don't have multiple "click" so that's why I still don't understand the difference. Maybe trigger input levels are different between tasmota and espurna.

mcspr commented 3 years ago

@ksirob35 was the issue resolved via the PR? Regarding Tasmota config, what was it?

AlbanTic commented 3 years ago

Hello Mcspr, Thank you for your message, Yes when I set "SwitchDebounce 69" in tasmota config it removes multiple clicks, and it's finally ok, I have only two events ^^ But after I configured BUTTON1_DEBOUNCE_DELAY to 69 in espurna config I still have multiples clicks. After 16h running tasmota, it stops, maybe there is a stackoverflow when counter increases when multiple clicks occures (I think it's the 50hz input signal in button input which makes this). (I tried to increase DEBOUNCE_DELAY under espurna to 200 but nothing changed)

Maybe an explaination is that debounced is managed differently :

But maybe I don't really understand what's going on, I think the difference is in param name :

mcspr commented 3 years ago

Hm. See https://tasmota.github.io/docs/Commands/#switchdebounce

9 at the end of debounce time is actually interpreted as flag, so 50hz signal is interpreted in a specific way instead of just waiting on the same digitalRead per debounce interval. Tasmota code can be seen here, and the code used as a basis for it: https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/master/olimex/user/user_switch2.c https://github.com/arendst/Tasmota/blob/development/tasmota/support_switch.ino So changing BUTTONX_DEBOUNCE won't do anything useful, our debounce time is just a milliseconds time without any additional meaning.

Can you try adding this code to log the button digital reads (replace the X down below) and see what it shows when idle and after changing switch position? And note to remove BUTTON1_PIN X or replace it with GPIO_NONE to avoid additional log spam

diff --git a/code/espurna/system.cpp b/code/espurna/system.cpp
index 0654f64c..865dc109 100644
--- a/code/espurna/system.cpp
+++ b/code/espurna/system.cpp
@@ -258,8 +258,32 @@ void _systemSetupSpecificHardware() {

 }

+void _systemSampler(int pin) {
+    pinMode(pin, INPUT);
+
+    static Ticker sample;
+    sample.attach_ms(2, [pin]() {
+        constexpr auto interval = microsecondsToClockCycles(1000ul * 1000ul);
+        static auto count = 0ul;
+        static auto last = ESP.getCycleCount();
+
+        auto current = ESP.getCycleCount();
+        if (current - last >= interval) {
+            DEBUG_MSG_P(PSTR("[sample] offset=%u value=%u\n"), (current - last) - interval, count);
+            last = current;
+            count = 0;
+        }
+
+        if (1 == digitalRead(pin)) {
+            ++count;
+        }
+    });
+}
+
 void systemSetup() {

+    _systemSampler(X);
+
     #if SPIFFS_SUPPORT
         SPIFFS.begin();
     #endif
AlbanTic commented 3 years ago

Thank you for your reply :) Great, it is reliable now : value = 250 when switch is Off and value = 500 when it is on ^^ So I will be able to connect it, many thanks :) It's perfect :))))

AlbanTic commented 3 years ago

Ahhhh, for a push button it works, but when I declare a second button, the first one stops working ^^ I don't really understand how the ticker works, maybe that's why I can't see how ..... Is it possible to connect two push buttons (and declare two tickers ?) :)

mcspr commented 3 years ago

I don't think you mentioned this, is this a custom device or some kind of consumer device like mentioned in the Tasmota code (i.e. Moes, Olimex, etc.)?

Ticker example was only meant to showcase the single pin :) and is actually a bad example for multiple ones. tldr - you need to get rid of 'static' vars altogether, because the way it is right now:

Although, I guess it might be better to do the work using a single timer and store some kind of arrays of pins & timestamps?

AlbanTic commented 3 years ago

Yes it is a custom device, I printed the printed circuit but I do not think it is a good idea after all, I had planned to set up my company and it will not be profitable lol, snfff ^^ Ok, yes I agree, it's better to use a single timer for performance ^^ Thank you very much for this code, very nice. It remember me when I was a coder, today I see that I forgot little things

mcspr commented 3 years ago

Cool :) Would you mind sharing the resulting code if / when it is complete? As a patch text here or PR

Notably, Tasmota implementation does another strange thing by ignoring first 4secs of button events on boot. Why I inserted the offset=... above, which we can use to detect if system spent too much time doing other stuff. You may notice it spends exactly 1sec doing the WiFi-related things, for example, or any time we have any network traffic it might spike up as well (not as big of the delay to expect though, but nonetheless)

AlbanTic commented 3 years ago

Yes, I don't know why Tasmota do this and I spent too much time trying to resolve their stack overflow problems. I did not succeed to use two pushbutton with Espurna and I must have callback informations on my server and I don't really know how to do. I will try to use other modules I have found on Amazon (Mini - Sonoff) because it can be locally managed. Do you know how to send callback ? if I want to send callback when I push a button to http://11.10.1.1/topic/shutterPosition how can I do ?

mcspr commented 3 years ago

You might want to look at HTTPClient from the Core library? https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266HTTPClient/examples/

Button events are shared as callbacks: https://github.com/xoseperez/espurna/blob/85969e494536c6734eaad0a981026e91808de390/code/espurna/button.cpp#L426 To receive them:

ButtonBroker::Register([](unsigned char id, button_event_t event) {
    ...http client stuff...
});

I also remember writing about http client here: https://github.com/xoseperez/espurna/wiki/3rd-Party-Plugins#timers schedule_function and / or Ticker's once_scheduled() might be useful

AlbanTic commented 3 years ago

Thank you for your reply mcspr, I though it was a good idea to use HTTP but after reflexion, why don't use MQTT, it works well and it is already developped ^^ With Tasmota it works fine but with Espurna it is frequently disconnected, do you know why ? (I really think that MQTT is better because QOS is higher)

mcspr commented 3 years ago

it's getting really OT here :) MQTT issues might just be a symptom for something else, and heavily depends on the version you are trying to use (e.g. if you still trying to use builds back from march), check out info terminal command output on the board in question.

Also note that MQTT qos stuff is related to the broker behaviour, not the client itself. e.g. with buttons, we would not queue the button event message while we are disconnected. edit: and, technically, we also don't really want qos to make it so we receive button event after 1h? Which it will happily do :) mqtt5 fixes that stuff, but that is also another issue altogether