[SOLVED]Stange ghost interrupt on ESP32 + rainmeter + Domoticz

I have ghost external interrupt on a rainmeter connected on an esp32. The esp32 send data to domoticz via wifi with http/json API.
The external interrupt FALLING fire 3 times/hours up to 1 time every 8 hours.

I thought the problem was long wire (15 meters) but I removed everything from the ESP12 and the problem persist with ESP32 only with nothing connect to (INPUT_PULLUP on the interrupt pin).

This can be usefull to understand my programs:

  • The rainmeter is not easy to de-bounce because the reed switch is only closed from 119ms to 141 ms. My strategy was to ignore any FALLING 500 ms after the first FALLING detected.
  • Interrupt are used because http connection can last more than 150ms
  • ESP32 is a 2 core micro-controller with multitask capabilities. Conflict are possible when you try to read/write the same variable in interrupt/main process. portENTER_CRITICAL_ISR(&mux); are used to avoid this.
  • I think volatile is not the right strategy for ESP32 (maybe I am wrong)
  • The program autoreconnect on wifi disconnect
  • SendDzAlarm log reconnect and http error (once reliable communication is back).

More détails on the hardware on the domoticz forum:
https://www.domoticz.com/forum/viewtopic.php?p=316387
The rainmeter is a reed switch connect to the interrupt pin and ground.

First, the simplified ESP32 program with all the wifi/http removed: there is no ghost interrupt on that one:


#define interruptPin 25                           //IO25/D2
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;  //pour eviter l'accès simultané aux variables

bool rainCountInitFlag = false;
double rainCount = 0.0;
long rainCountNew = 0;  //ISR - tipping bucket number
long rainCountOld = 0;
double rainRate = 0.0;  //ISR

uint64_t tRainCount = 0;   //ISR
uint64_t tRainCountO = 0;  //ISR
uint64_t tTimer = 0;

void IRAM_ATTR reedSwitch() {  //interrupt
  portENTER_CRITICAL_ISR(&mux);
  tRainCount = esp_timer_get_time();
  if (tRainCount - tRainCountO > 500000) {  //0.5s - RISING bounce will not be seen
    rainCountNew++;
    if (tRainCountO > 1) {
      rainRate = 3.6e9 * 0.2 / double(tRainCount - tRainCountO);
    }
    tRainCountO = tRainCount;
  }
  portEXIT_CRITICAL_ISR(&mux);
}
void SendDz() {
  digitalWrite(LED_BUILTIN, HIGH);
  portENTER_CRITICAL_ISR(&mux);
  long rainRate100 = rainRate * 100.0;
  double rainCountCopy = rainCount;
  portEXIT_CRITICAL_ISR(&mux);
  Serial.println((String)((float)esp_timer_get_time() / 1.0e6) + "s  Rain: " + (String)rainCountCopy + " Rain rate: " + (String)rainRate100);
  digitalWrite(LED_BUILTIN, LOW);
}

void setup() {
  setCpuFrequencyMhz(80);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(115200);
  Serial.println("\nConnecting");
  attachInterrupt(digitalPinToInterrupt(interruptPin), reedSwitch, FALLING);
}

void loop() {
  uint64_t t = esp_timer_get_time();
  portENTER_CRITICAL_ISR(&mux);
  long drain = rainCountNew - rainCountOld;
  rainCount = (float)rainCountNew * 0.2;
  portEXIT_CRITICAL_ISR(&mux);
  if (drain > 0) {  //interrupt with raincount occurs
    Serial.print("Count:");
    SendDz();

    tTimer = t;
    portENTER_CRITICAL_ISR(&mux);
    long rainCountOCopy = rainCountOld;
    rainCountOld = rainCountNew;
    portEXIT_CRITICAL_ISR(&mux);
  }
  if (t - tTimer > 300e6) {  //update tous les 300s=5min
    //recalcul rainrate
    portENTER_CRITICAL_ISR(&mux);
    if (rainCountNew > 1) {
      rainRate = 3.6e9 * 0.2 / double(t - tRainCountO);
      if (rainRate < 0.2) rainRate = 0.0;
    }
    portEXIT_CRITICAL_ISR(&mux);
    Serial.print("Timer:");
    SendDz();
    tTimer = t;
  }
}

With the full program and wifi/http, I have ghost interrupt:


#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>

#define interruptPin 25                           //IO25/D2
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 

// WiFi settings
#define ssid "ssidToChange"
#define password "passToChange"

HTTPClient http;
String url1 = "http://88.89.90.91:8080/json.htm?type=command&param=getdevices&rid=100";
String url2 = "http://88.89.90.91:8080/json.htm?type=command&param=udevice&idx=100&nvalue=0&svalue=";
int httpCode = -1;
int httpCodeO = -1;

bool rainCountInitFlag = true;
double rainCount = 0.0;  //ISR
long rainCountNew = 0;   //ISR - tipping bucket number
long rainCountOld = 0;   //ISR
double rainRate = 0.0;

uint64_t tRainCount = 0;   //ISR
uint64_t tRainCountO = 0;  //ISR
uint64_t tTimer = 0;


void IRAM_ATTR reedSwitch() {  //interrupt
  portENTER_CRITICAL_ISR(&mux);
  tRainCount = esp_timer_get_time();
  if (tRainCount - tRainCountO > 500000) {  //0.5s - RISING bounce will not be seen
    rainCountNew++;
    if (tRainCountO > 1) {
      rainRate = 3.6e9 * 0.2 / double(tRainCount - tRainCountO);
    }
    tRainCountO = tRainCount;
  }
  portEXIT_CRITICAL_ISR(&mux);
}

void ConnectedToAP_Handler(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info) {
  Serial.println("Connected To The WiFi Network");
}

void GotIP_Handler(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info) {
  Serial.print("Local ESP32 IP: ");
  Serial.println(WiFi.localIP());
  SendDzAlarm(3, "ESP32+Reconnection");
  if (rainCountInitFlag) {
    GetRaincount();
    if (!rainCountInitFlag) {
      SendDzAlarm(1, "Rain+Count+OK");
    }
  }
}

void WiFi_Disconnected_Handler(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info) {
  Serial.println("Disconnected From WiFi Network");
  // Attempt Re-Connection
  WiFi.begin(ssid, password);
}

void GetRaincount() {
  Serial.println("getraincount");
  HTTPClient http;
  http.begin(url1);       //Specify the URL
  httpCode = http.GET();  //Make the request

  if (httpCode > 0) {  //Check for the returning code

    String payload = http.getString();
    Serial.println("GetRaincount http code: " + (String)httpCode);
    //Serial.println(payload);

    //deserialize json
    JsonDocument doc;
    // Deserialize the JSON document
    DeserializationError error = deserializeJson(doc, payload);
    // Test if parsing succeeds.
    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.f_str());
    } else {
      String data = doc["result"][0]["Data"];
      Serial.println("JSON data: " + data);
      int index = data.indexOf(";");
      if (index == -1) {
        Serial.println("pas de ; dans la chaine");
      } else {
        String rainCountS = data.substring(index + 1);
        portENTER_CRITICAL_ISR(&mux);
        rainCountNew = 5.0 * rainCountS.toFloat() + 0.05;  //0.05 to avoid 1->0.99->4.95->4
        portEXIT_CRITICAL_ISR(&mux);

        Serial.println("rainCount: " + (String)rainCountS.toFloat());
        rainCountInitFlag = false;
        digitalWrite(LED_BUILTIN, LOW);
      }
    }
  } else {
    Serial.println("Error on HTTP request");
  }
  http.end();  //Free the resources
}

void SendDz() {             //send rainCount to DZ
  if (rainCountInitFlag) {  //send only if get rainCount in DZ
    Serial.println("Erreur: rainCount non récupérer sur DZ");
  } else {
    digitalWrite(LED_BUILTIN, HIGH);

    portENTER_CRITICAL_ISR(&mux);
    long rainRate100 = rainRate * 100.0;
    double rainCountCopy = rainCount;
    portEXIT_CRITICAL_ISR(&mux);
    Serial.print((String)((float)esp_timer_get_time() / 1.0e6) + "s  Rain: " + (String)rainCountCopy + " Rain rate: " + (String)rainRate100);

    HTTPClient http;
    //Serial.println(url2 +(String)rainRate100+";"+ (String)rainCountCopy);
    http.begin(url2 + (String)rainRate100 + ";" + (String)rainCountCopy);
    httpCode = http.GET();  //Make the request

    if (httpCode > 0) {  //Check for the returning code

      //String payload = http.getString();
      Serial.println(" SendDZ http code: " + (String)httpCode);
      //Serial.println(payload);
      digitalWrite(LED_BUILTIN, LOW);
    } else {
      Serial.println(" Error on HTTP request");
    }
    http.end();  //Free the resources
  }
}

void SendDzAlarm(byte level, String text) {  //send rainCount to DZ
  digitalWrite(LED_BUILTIN, HIGH);
  HTTPClient http;
  float tConnect = (float)esp_timer_get_time() / 1e6;
  http.begin("http://88.89.90.91:8080/json.htm?type=command&param=udevice&idx=101&nvalue=" + (String)level + "&svalue=" + text + "+a+" + (String)tConnect + "+s");
  httpCode = http.GET();  //Make the request
  if (httpCode > 0) {     //Check for the returning code
    //String payload = http.getString();
    //Serial.println("SendDZAlarm http code: " + (String)httpCode);
    //Serial.println(payload);
    digitalWrite(LED_BUILTIN, LOW);
  } else {
    Serial.println(" Error on HTTP request");
  }
  http.end();  //Free the resources
}

void setup() {
  setCpuFrequencyMhz(80);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.onEvent(ConnectedToAP_Handler, SYSTEM_EVENT_STA_CONNECTED);         //ARDUINO_EVENT_WIFI_STA_CONNECTED     SYSTEM_EVENT_STA_CONNECTED
  WiFi.onEvent(GotIP_Handler, SYSTEM_EVENT_STA_GOT_IP);                    // ARDUINO_EVENT_WIFI_STA_GOT_IP    SYSTEM_EVENT_STA_GOT_IP
  WiFi.onEvent(WiFi_Disconnected_Handler, SYSTEM_EVENT_STA_DISCONNECTED);  // ARDUINO_EVENT_WIFI_STA_DISCONNECTED    SYSTEM_EVENT_STA_DISCONNECTED

  WiFi.begin(ssid, password);
  Serial.println("\nConnecting");


  attachInterrupt(digitalPinToInterrupt(interruptPin), reedSwitch, FALLING);
}

void loop() {
  uint64_t t = esp_timer_get_time();
  portENTER_CRITICAL_ISR(&mux);  //a mettre si risque ecriture simultannee
  long drain = rainCountNew - rainCountOld;
  rainCount = (float)rainCountNew * 0.2;
  portEXIT_CRITICAL_ISR(&mux);

  if (drain > 0) {  //interrupt with raincount occurs
    Serial.print("Count:");
    SendDz();

    tTimer = t;
    if (httpCode != httpCodeO) {
      SendDzAlarm(2, "RetouR+d+un+hhtp+Code+" + (String)httpCodeO + "+vers+" + (String)httpCode);
      httpCodeO = httpCode;
    }
    //to be removed
    portENTER_CRITICAL_ISR(&mux);
    long rainCountOCopy = rainCountOld;
    portEXIT_CRITICAL_ISR(&mux);

    if (rainCountOld == 0)
      SendDzAlarm(0, "Rafaichissement+au+demarrage");
    else
      SendDzAlarm(1, "Basculement+d+auget+detecte");
    //to be removed end

    portENTER_CRITICAL_ISR(&mux);
    rainCountOld = rainCountNew;
    portEXIT_CRITICAL_ISR(&mux);
  }

  if (t - tTimer > 300e6) {  //update tous les 300s=5min
    if (rainCountInitFlag) {
      GetRaincount();
      if (!rainCountInitFlag) {
        SendDzAlarm(2, "Rain+Count+non+initialise+au+demmarrage");
      }
    }
    //recalcul rainrate
    portENTER_CRITICAL_ISR(&mux);
    if (rainCountNew > 1) {
      //rainrate calculation only if 2 tipping bucket after reset
      rainRate = 3.6e9 * 0.2 / double(t - tRainCountO);
      if (rainRate < 0.2) rainRate = 0.0;
    }
    portEXIT_CRITICAL_ISR(&mux);

    Serial.print("Timer:");
    SendDz();
    tTimer = t;
    if (httpCode != httpCodeO) {
      SendDzAlarm(2, "Retour+d+un+hhTp+Code+" + (String)httpCodeO + "+vers+" + (String)httpCode);
      httpCodeO = httpCode;
    }
  }
}

Sorry for that long code but I can't reproduce the error with a shorter code!

I think I found the solution here:

I add :


WiFi.setSleep(false);

This disable the WiFi sleep mode.
I have no ghost interrupt since I addthat.

Here is the code update. It is usefull for those coming from the domoticz forum.
If you want to use the code, you must change:

  • wifi SSID
  • wifi password
  • IP address and port
  • idx of rainmeter in domoticz
  • idx of alarm in domoticz

The code would be better with those value easy to change at the beginning of the code.

#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>

#define interruptPin 25                           //IO25/D2
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;

// WiFi settings
#define ssid "ssidToChange"
#define password "passToChange"
const char* host = "88.89.90.91";  //DZ nas
const int port = 8080;

HTTPClient http;
String url1 = "http://88.89.90.91:8080/json.htm?type=command&param=getdevices&rid=100";
String url2 = "http://88.89.90.91:8080/json.htm?type=command&param=udevice&idx=100&nvalue=0&svalue=";
int httpCode = -2;
int httpCodeO = -2;

boolean rainCountInitFlag = true;
double rainCount = 0.0;  //ISR
long rainCountNew = 0;  //ISR - tipping bucket number
long rainCountOld = 0;  //ISR
double rainRate = 0.0;

uint64_t tRainCount = 0;   //ISR
uint64_t tRainCountO = 0;  //ISR
uint64_t tTimer = 0;


void IRAM_ATTR reedSwitch() {    //interrupt
  portENTER_CRITICAL_ISR(&mux);
  tRainCount = esp_timer_get_time();
  if (tRainCount - tRainCountO > 500000) {  //0.5s - RISING bounce will not be seen
    rainCountNew++;
    if (tRainCountO > 1) {
      rainRate = 3.6e9 * 0.2 / double(tRainCount - tRainCountO); 
    }
    tRainCountO = tRainCount;
  }
  portEXIT_CRITICAL_ISR(&mux);
}

void ConnectedToAP_Handler(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info) {
  Serial.println("Connected To The WiFi Network");
}

void GotIP_Handler(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info) {
  Serial.print("Local ESP32 IP: ");
  Serial.println(WiFi.localIP());
  SendDzAlarm(3, "ESP32+Reconnection");
  if (rainCountInitFlag) {  //si rainCount pas encore récupéré
    GetRaincount();
    if (!rainCountInitFlag) {
      SendDzAlarm(1, "Rain+Count+OK");
    }
  }
}

void WiFi_Disconnected_Handler(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info) {
  Serial.println("Disconnected From WiFi Network");
  // Attempt Re-Connection
  WiFi.begin(ssid, password);
}

void GetRaincount() {
  Serial.println("getraincount");
  HTTPClient http;
  http.begin(url1);       //Specify the URL
  httpCode = http.GET();  //Make the request

  if (httpCode > 0) {  //Check for the returning code

    String payload = http.getString();
    Serial.println("GetRaincount http code: " + (String)httpCode);
    //Serial.println(payload);

    //deserialize json
    JsonDocument doc;
    // Deserialize the JSON document
    DeserializationError error = deserializeJson(doc, payload);
    // Test if parsing succeeds.
    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.f_str());
    } else {
      String data = doc["result"][0]["Data"];
      Serial.println("JSON data: " + data);
      int index = data.indexOf(";");
      if (index == -1) {
        Serial.println("pas de ; dans la chaine");
      } else {
        String rainCountS = data.substring(index + 1);
        portENTER_CRITICAL_ISR(&mux);
        rainCountNew = 5.0*rainCountS.toFloat()+0.05;//0.05 to avoid 1->0.99->4.95->4
        portEXIT_CRITICAL_ISR(&mux);

        Serial.println("rainCount: " + (String)rainCountS.toFloat());
        rainCountInitFlag = false;
        digitalWrite(LED_BUILTIN, LOW);
      }
    }
  } else {
    Serial.println("Error on HTTP request");
  }
  http.end();  //Free the resources
}

void SendDz() {             //send rainCount to DZ
  if (rainCountInitFlag) {  //send only if get rainCount in DZ
    Serial.println("Erreur: rainCount non récupérer sur DZ");
  } else {
    digitalWrite(LED_BUILTIN, HIGH);

    portENTER_CRITICAL_ISR(&mux);
    int rainRate100 = rainRate * 100.0;
    double rainCountCopy = rainCount;
    portEXIT_CRITICAL_ISR(&mux);

    HTTPClient http;
    http.begin(url2 + (String)rainRate100 + ";" + (String)rainCountCopy);
    httpCode = http.GET();  //Make the request

    if (httpCode > 0) {  //Check for the returning code
      Serial.println("SendDZ http code: " + (String)httpCode);
      digitalWrite(LED_BUILTIN, LOW);
    } else {
      Serial.println("Error on HTTP request");
    }
    http.end();  //Free the resources
  }
}

void SendDzAlarm(byte level, String text) {  //send rainCount to DZ
  digitalWrite(LED_BUILTIN, HIGH);
  HTTPClient http;
  float tConnect = (float)esp_timer_get_time() / 1e6;
  http.begin("http://88.89.90.91:8080/json.htm?type=command&param=udevice&idx=101&nvalue=" + (String)level + "&svalue=" + text + "+a+" + (String)tConnect + "+s");
  httpCode = http.GET();  //Make the request
  if (httpCode > 0) {     //Check for the returning code
    Serial.println("SendDZAlarm http code: " + (String)httpCode);
    digitalWrite(LED_BUILTIN, LOW);
  } else {
    Serial.println("Error on HTTP request");
  }
  http.end();  //Free the resources
}

void setup() {
  setCpuFrequencyMhz(80);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.setSleep(WIFI_PS_NONE); //!!!!!!!!!!!!!!!!!!!! against ghost interrupt
  WiFi.onEvent(ConnectedToAP_Handler, SYSTEM_EVENT_STA_CONNECTED);         //ARDUINO_EVENT_WIFI_STA_CONNECTED     SYSTEM_EVENT_STA_CONNECTED
  WiFi.onEvent(GotIP_Handler, SYSTEM_EVENT_STA_GOT_IP);                    // ARDUINO_EVENT_WIFI_STA_GOT_IP    SYSTEM_EVENT_STA_GOT_IP
  WiFi.onEvent(WiFi_Disconnected_Handler, SYSTEM_EVENT_STA_DISCONNECTED);  // ARDUINO_EVENT_WIFI_STA_DISCONNECTED    SYSTEM_EVENT_STA_DISCONNECTED

  WiFi.begin(ssid, password);
  Serial.println("\nConnecting");

  
  attachInterrupt(digitalPinToInterrupt(interruptPin), reedSwitch, FALLING);
}

void loop() {
  uint64_t t = esp_timer_get_time();
  portENTER_CRITICAL_ISR(&mux);  //a mettre si risque ecriture simultannee
  long drain = rainCountNew - rainCountOld;
  rainCount=(float)rainCountNew*0.2;
  portEXIT_CRITICAL_ISR(&mux);

  if (drain > 0) {  //interrupt with raincount occurs
    SendDz();
    tTimer = t;
    if (httpCode != httpCodeO) {
      SendDzAlarm(2, "RetouR+d+un+hhtp+Code+" + (String)httpCodeO + "+vers+" + (String)httpCode);
      httpCodeO = httpCode;
    }
    portENTER_CRITICAL_ISR(&mux);
    long rainCountOCopy = rainCountOld;
    portEXIT_CRITICAL_ISR(&mux);
    
    if (rainCountOld==0)
    SendDzAlarm(0, "Rafaichissement+au+demarrage");
    else
    SendDzAlarm(1, "Basculement+d+auget+detecte");

    portENTER_CRITICAL_ISR(&mux);
    rainCountOld = rainCountNew;
    portEXIT_CRITICAL_ISR(&mux);
  }

  if (t - tTimer > 300e6) {   //update tous les 300s=5min
    if (rainCountInitFlag) {  
      GetRaincount();         
      if (!rainCountInitFlag) {
        SendDzAlarm(2, "Rain+Count+non+initialise+au+demmarrage");
      }
    }
    //rainrate calculation if long time without rain
    portENTER_CRITICAL_ISR(&mux);
    if (rainCountNew > 1) {
      //rainrate calculation only if 2 tipping bucket after reset
      rainRate = 3.6e9 * 0.2 / double(t - tRainCountO);
      if (rainRate < 0.2) rainRate = 0.0;
    }
    portEXIT_CRITICAL_ISR(&mux);

    SendDz();
    tTimer = t;
    if (httpCode != httpCodeO) {
      SendDzAlarm(2, "Retour+d+un+hhTp+Code+" + (String)httpCodeO + "+vers+" + (String)httpCode);
      httpCodeO = httpCode;
    }
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.