pulsante due stati

scusate la banalita' della domanda, ma e' tutto il pomeriggio che mi fa impazzire, ho bisogno che un pulsante pull_down ad ogni pressione cambi lo stato di pubblicazione su MQTT una volta sola, mentre a me esegue sempre tutte e due le condizioni:

  int valoreTastoQ = digitalRead(FEED);
   { 
   if (valoreTastoQ == HIGH && flag == HIGH){   
           digitalWrite(relayPin, HIGH);
           delay(togDelay);
           digitalWrite(relayPin, LOW);          
           feed.publish ("ON");                   
           }
        flag=LOW;
     if (valoreTastoQ == HIGH && flag ==LOW){
           digitalWrite(relayPin, LOW);
           delay(togDelay);
           digitalWrite(relayPin, LOW);          
            feed.publish ("OFF");
                      
            }
         flag=HIGH;
   }

ovviamente ho messo prima del setup :

boolean flag = HIGH;

grazie per l'aiuto

se dopo aver scritto/copiato un programma si premono i tasti ctrl+t (dentro all'ide di arduino) il testo viene "formattato" in modo corretto in questo modo

int valoreTastoQ = digitalRead(FEED);
{           //<---questa non serve
  if (valoreTastoQ == HIGH && flag == HIGH) {
    digitalWrite(relayPin, HIGH);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish ("ON");
  }
  flag = LOW;
  if (valoreTastoQ == HIGH && flag == LOW) {
    digitalWrite(relayPin, LOW);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish ("OFF");

  }
  flag = HIGH;
}           //<---questa non serve

da cui si evince

  1. la prima e l'ultima parentesi graffa non servono a nulla

  2. la variabile flag viene impostata al di fuori degli if per cui all'inizio l'hai impostata come vera
    region per cui entra nel primo if e lo esegue
    uscito dall'if cambi la variabile in falso
    regione per cui entra nel secondo if
    e all'uscita da questo la ricambi e al prossimo ciclo rientrerà nel primo if...
    prova così

void loop() {
  int valoreTastoQ = digitalRead(FEED);
  if (valoreTastoQ == HIGH && flag == HIGH) {
    digitalWrite(relayPin, HIGH);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish ("ON");
    flag = LOW;
  }

  if (valoreTastoQ == HIGH && flag == LOW) {
    digitalWrite(relayPin, LOW);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish ("OFF");
    flag = HIGH;
  }
  delay(1000); // attendo un secondo prima di ripetere il loop
}

ovviamente.... per non avere una ripetizione dei vari eventi in modo imprevedibile serve il debounce del tasto FEED

Patrick_M:
prova così

void loop() {

int valoreTastoQ = digitalRead(FEED);
  if (valoreTastoQ == HIGH && flag == HIGH) {
    digitalWrite(relayPin, HIGH);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish ("ON");
    flag = LOW;
  }

if (valoreTastoQ == HIGH && flag == LOW) {
    digitalWrite(relayPin, LOW);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish ("OFF");
    flag = HIGH;
  }
  delay(1000); // attendo un secondo prima di ripetere il loop
}




ovviamente.... per non avere una ripetizione dei vari eventi in modo imprevedibile serve il debounce del tasto FEED

magari così funziona meglio, credo

void loop(void)
{
    if (digitalRead(FEED))
    {
        if (flag = !flag)
        {
            digitalWrite(RELAY, HIGH);
            delay(togDelay);
            digitalWrite(RELAY, LOW);
            feed.publish("ON");
        }
        else
        {
            digitalWrite(RELAY, LOW);
            delay(togDelay);
            digitalWrite(RELAY, LOW);
            feed.publish("OFF");
        }
    }

    delay(1000); // attendo un secondo prima di ripetere il loop
}

tutti e due i piedini usati sono delle define, non ha senso usare una define e una variabile
testo una volta sola il piedino, e lo uso direttamente
aggiorno immediatamente la variabile di appoggio che conserva lo stato
a seconda dello stato eseguo una delle due azioni necessarie
per come lo avevi messo tu non credo che andasse
comunque non credo sia necessario un de-bounce HW, con 1000 ms di attea tra un azionamento e l'altro
Come vedi io uso una convenzione differente per l'indentazione e l'auto formattazione, ma come dico sempre io: non importa che convenzione si segue, l'importante è farlo
Sto seriamente pensando di non assistere più chi non formatta il codice, è tanto che ci penso e lo ho già detto mesi fa, ma mi sa che per Natale me lo regalo.........

Piatto ricco mi ci ficco, perdonatemi il doppio post
ma ho viso il caso di togliere ancora qualcosa:

void loop(void)
{
    if (delay(1000), digitalRead(FEED))
    {
        digitalWrite(RELAY, flag = !flag;);
        delay(togDelay);
        digitalWrite(RELAY, LOW);
        feed.publish(flag ? "ON", "OFF");
    }
}

che mi sembra bello compatto, e mette in opera una serie di "caratteristiche" del 'C' che, a mio parere, vanno (VANNO) sapute

:sunglasses:

Patrick_M:
:sunglasses:

mi è toccato andare a chiedere al santo per sapere cosa significa, sono proprio della generazione sbagliata...
che dire.... Grazie!

Ho provato le vostre soluzioni, ma non funzionano, e forse l'errore e' il mio che non ho pubblicato l'intero sketch e mi sono spiegato male.
Lo sketch serve per gestire un rele comandato sia da OpenHab che da un pulsante. MQTT mi serve per la notifica su OpenHab per lo stato ON/OFF
Ecco lo sketch completo e formattato con ctrl+T dalla IDE (non sapevo che andasse fatto, ma si impara sempre qualcosa :wink:

grazie in anticipo per il vostro aiuto
Davide

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <IRremoteESP8266.h>
#include <WiFiUdp.h>
#include <Adafruit_MQTT.h>
#include <Adafruit_MQTT_Client.h>

IPAddress staticIP(xxx, xxx, xxx, xxx); //ESP static ip
IPAddress gateway(xxx, xxx, xxx, xxx);   //IP Address of your WiFi Router (Gateway)
IPAddress subnet(255, 255, 255, 0);  //Subnet mask
IPAddress dns(8, 8, 8, 8);  //DNS

#define wifi_ssid  "xxxxx"
#define wifi_password  "xxxx"

/************************* MQTT Broker Setup *********************************/
#define mqtt_server      "xx.xx.xx.xx"
#define mqtt_serverport  1883                   // use 8883 for SSL
#define mqtt_username    "xxxxx"
#define mqtt_password    "xxxxx"

/************************* Constants, Variables, Integers, etc *********************************/

const int BLINK   = D3; //D3
const int FEED = D6;
const int relayPin = D1;// D1
int value = 0;
int relayState = LOW;
const long togDelay = 100;  // pause for 100 milliseconds before toggling to Open
const long postDelay = 200;
boolean flag = HIGH;
int  ValueQ     =  0;
long Tempo1     =  0;
long Tempo2     = 50;
int  ValueCombQ =  5;

/**********************MQTT*****************************************************/
Adafruit_MQTT_Client mqtt(&client, mqtt_server, mqtt_serverport, mqtt_username, mqtt_password);
Adafruit_MQTT_Subscribe Robo500 = Adafruit_MQTT_Subscribe(&mqtt, "openhab/out/Robo500/command");
Adafruit_MQTT_Publish feed = Adafruit_MQTT_Publish(&mqtt,  "openhab/in/Robo500/state");
void MQTT_connect();

WiFiClient client;

//==============================================================
//                  SETUP
//==============================================================
void setup() {

  Serial.begin(115200);
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);
  WiFi.begin(wifi_ssid, wifi_password);
  WiFi.config(staticIP, subnet, gateway, dns);
  WiFi.mode(WIFI_STA);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("WiFi connected at IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(BLINK,    OUTPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(FEED, INPUT);
  mqtt.subscribe(&Robo500);

  // Begin OTA
  ArduinoOTA.setPort(8266); // Port defaults to 8266
  ArduinoOTA.setHostname("xxxxxx");   // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setPassword((const char *)"xxxxx");   // No authentication by default

  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("");
  Serial.println("Ready & WiFi connected");
  Serial.print("IP address: "); Serial.println(WiFi.localIP());
}


//==============================================================
//                     LOOP
//==============================================================
void loop() {
  ArduinoOTA.handle();

  if (WiFi.status() == WL_CONNECTED) {
    digitalWrite(BLINK, HIGH);
    delay(20);
    digitalWrite(BLINK, LOW);
    delay(20);
  }

  /****************antirimbalzo*******************/
  int StatoTastoQ;
  int StatoTastoQa = LOW;
  if (valoreTastoQ != StatoTastoQa)
  {
    Tempo1 = millis();
  }
  if ((millis() - Tempo1) > Tempo2)
  {
    StatoTastoQ = valoreTastoQ;
  }
  StatoTastoQa = valoreTastoQ;
  /*************fine*****************************/

  /**************esecuzione da openhab********************/
  MQTT_connect();
  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(500))) {
    if (subscription == &Robo500) {
      Serial.print(F("Got: ")); Serial.println((char *)Robo500.lastread);

      Serial.println("Close Relay for 100 ms & then Open");
      digitalWrite(relayPin, HIGH);
      delay(togDelay);
      digitalWrite(relayPin, LOW);
      delay(postDelay);
    }
  }

  /**************esecuzione da pulsante ***********************/

  int valoreTastoQ = digitalRead(FEED);
  if (valoreTastoQ == HIGH && flag == HIGH)
  {
    digitalWrite(relayPin, HIGH);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish("ON");
    flag = LOW;
  }
  if (valoreTastoQ == HIGH && flag == LOW) {
    digitalWrite(relayPin, LOW);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish ("OFF");
    flag = HIGH;
  }
  delay(1000); // attendo un secondo prima di ripetere il loop


  Serial.println (flag);
  delay (350);

  if (! mqtt.ping ()) {
    mqtt.disconnect ();
  }

}


/******************************funzione MQTT**********************/
void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Connecting to MQTT... ");

  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
    Serial.println(mqtt.connectErrorString(ret));
    Serial.println("Retrying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);  // wait 5 seconds
    retries--;
    if (retries == 0) {
      // basically die and wait for WDT to reset me
      while (1);
    }
  }
  Serial.println("MQTT Connected!");
}

Ma ti compila 'sta roba?
perchè a me non mi convince per nulla....
e non ho le librerie per provarla, non ci penso nemmeno a scaricarle apposta

Compila e funziona, ad eccezione della famosa flag, visto che da pulsante mi fa pubblicare sempre e solo OFF, non compilava il tuo secondo suggerimento per degli errori.

Poi scusa, se non compilava come facevo a verificare il funzionamento?

e' la stessa domanda che mi pongo io.....
viso che alla riga 39

/**********************MQTT*****************************************************/
Adafruit_MQTT_Client mqtt(&client, mqtt_server, mqtt_serverport, mqtt_username, mqtt_password);

l'oggetto client non è ancora dichiarato, quindi non compila
alla riga 117

  /****************antirimbalzo*******************/
  int StatoTastoQ;
  int StatoTastoQa = LOW;
  if (valoreTastoQ != StatoTastoQa)

la variabile valoreTastoQ non è ancora dichiarata, quindi nemmeno li compila
lo stesso alle righe 123 e 125
quindi ti esplico meglio la mia domanda:
Visto che il tuo programma non compila, come hai fatto a dire che il mio è sbagliato?
ma tralasciamo il mio, concentriamoci un poco sui consigli che ti ha dato Patrick, che sono vaidissimi
perchè non li hai messi in pratica?
giusto per essere chiari e netti: HO installato apposta le librerie necessarie, quando dico che NON compila parlo a ragion veduta

hai ragione nel copia&incolla per eliminare indirizzi ip e password ho fatto confusione.
Questo compila:

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <IRsend.h>
#include <ArduinoOTA.h>
#include <IRremoteESP8266.h>
#include <WiFiUdp.h>
#include <Adafruit_MQTT.h>
#include <Adafruit_MQTT_Client.h>

IPAddress staticIP(xx, xx, x, xxx); //ESP static ip
IPAddress gateway(xxx, xxx, x, x);   //IP Address of your WiFi Router (Gateway)
IPAddress subnet(255, 255, 255, 0);  //Subnet mask
IPAddress dns(8, 8, 8, 8);  //DNS

#define wifi_ssid  "xxx"
#define wifi_password  "xxx"

/************************* MQTT Broker Setup *********************************/
#define mqtt_server      "xxx.xxx.x.x"
#define mqtt_serverport  1883                   // use 8883 for SSL
#define mqtt_username    "xxx"
#define mqtt_password    "xxx"

/************************* Constants, Variables, Integers, etc *********************************/

const int BLINK   = D3; //D3
const int FEED = D6;
const int relayPin = D1;// D1
int value = 0;
int relayState = LOW;
const long togDelay = 100;  // pause for 100 milliseconds before toggling to Open
const long postDelay = 200;
boolean flag = HIGH;
int  ValueQ     =  0;
long Tempo1     =  0;
long Tempo2     = 50;
int  ValueCombQ =  5;
int valoreTastoQ = digitalRead(FEED);

IRsend irsend(4);
WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, mqtt_server, mqtt_serverport, mqtt_username, mqtt_password);
Adafruit_MQTT_Subscribe Robo500 = Adafruit_MQTT_Subscribe(&mqtt, "openhab/out/Robo500/command");
Adafruit_MQTT_Publish feed = Adafruit_MQTT_Publish(&mqtt,  "openhab/in/Robo500/state");
void MQTT_connect();

//==============================================================
//                  SETUP
//==============================================================
void setup() {

  Serial.begin(115200);
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);
  WiFi.begin(wifi_ssid, wifi_password);
  WiFi.config(staticIP, subnet, gateway, dns);
  WiFi.mode(WIFI_STA);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("WiFi connected at IP address: ");
  Serial.println(WiFi.localIP());

  irsend.begin();

  pinMode(BLINK,    OUTPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(FEED, INPUT);
  mqtt.subscribe(&Robo500);

  // Begin OTA
  ArduinoOTA.setPort(8266); // Port defaults to 8266
  ArduinoOTA.setHostname("xxx");   // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setPassword((const char *)"xxx");   // No authentication by default

  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if      (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("");
  Serial.println("Ready & WiFi connected");
  Serial.print("IP address: "); Serial.println(WiFi.localIP());
}

//==============================================================
//                     LOOP
//==============================================================
void loop() {
  ArduinoOTA.handle();

  if (WiFi.status() == WL_CONNECTED) {
    digitalWrite(BLINK, HIGH);
    delay(20);
    digitalWrite(BLINK, LOW);
    delay(20);
  }

  //-------- ANTIRIMBALZO------------------
  int StatoTastoQ;
  int StatoTastoQa = LOW;
  if (valoreTastoQ != StatoTastoQa)
  {
    Tempo1 = millis();
  }
  if ((millis() - Tempo1) > Tempo2)
  {
    StatoTastoQ = valoreTastoQ;
  }
  StatoTastoQa = valoreTastoQ;
  //-------- FINE ANTIRIMBALZO------------------


  MQTT_connect();
  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(500))) {
    if (subscription == &Robo500) {
      Serial.print(F("Got: ")); Serial.println((char *)Robo500.lastread);

      Serial.println("Close Relay for 100 ms & then Open");
      digitalWrite(relayPin, HIGH);
      delay(togDelay);
      digitalWrite(relayPin, LOW);
      delay(postDelay);
    }
  }

  //--------INIZIO ESECUZIONE ------------

  int valoreTastoQ = digitalRead(FEED);
  if (valoreTastoQ == HIGH && flag == HIGH)
  {
    digitalWrite(relayPin, HIGH);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish("ON");
    flag = LOW;
  }
  if (valoreTastoQ == HIGH && flag == LOW) {
    digitalWrite(relayPin, LOW);
    delay(togDelay);
    digitalWrite(relayPin, LOW);
    feed.publish ("OFF");
    flag = HIGH;
  }
  delay(1000); // attendo un secondo prima di ripetere il loop


  Serial.println (flag);
  delay (350);

  if (! mqtt.ping ()) {
    mqtt.disconnect ();
  }

}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Connecting to MQTT... ");

  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
    Serial.println(mqtt.connectErrorString(ret));
    Serial.println("Retrying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);  // wait 5 seconds
    retries--;
    if (retries == 0) {
      // basically die and wait for WDT to reset me
      while (1);
    }
  }
  Serial.println("MQTT Connected!");
}

bene, in questo caso non ho piu' nulla da dirti, buon lavoro

Cencio... io ritornerei al primo post, e alla prima risposta di Patrick che contiene il 99% della soluzione.

¿Porcue (in generale) non vi disegnate (quasi) mai la logica su carta prima di buttarla su codice?

Oggi sono in vena di disegnini... nel seguente disegno sinistra c'è il codice che hai scritto nel post #1, se segui le frecce col dito vedrai che si comporta male esattamente come hai visto (e la corretta indentazione aiuta a non commettere errori come questi).

A destra invece quello che vorresti facesse... Di differente da quanto ha scritto Patrick c'è solo l'aggiunta del controllo sulla variazione del pulsante tramite un'ulteriore variabile che ho chiamato 'precTastQ', in modo da considerare solo gli istanti di pressione e rilascio, e le due if rese mutuamente esclusive e non una sotto l'altra.

Tra l'altro, essendoci due variabili di stato binarie, abbiamo quattro possibili combinazioni, infatti il processo ha quattro possibili stati, non due, e si può descrivere in modo molto più semplice anche con un'unica variabile di stato (chiamata ad esempio 'stato') che svolge la funzione delle due precedenti ('flag' e 'precTastQ'):

grazie!
questo e' un ottimo consiglio (quello del disegno) mi ci metto subito , vediamo che scappa fuori

ok funziona , grazie.
Adesso devo gestire anche il "subscription" da OpenHab, quindi la notifica ON/OFF sara' gestita o dal pulsante fisico o dal pulsante virtuale di OpenHab, quindi inserisco un altra variabile binaria e mi rifaccio lo schemino, che dovrebbe avere sei combinazioni...giusto?