MQTT, Arduino MEGA client gets disconnected after some time

  • Platform information:
    • Hardware: Raspberry Pi 3 B+
    • OS: Raspbian last version
    • openHAB version: last version
  • Issue of the topic: please be detailed explaining your issue

Hi, my name is Josep Mencion and I’m doing a research school project on home automation.
I have a Raspberry Pi and an Arduino MEGA 2560 with an Ethernet Shield which connects to the Raspberry Pi 1883 MQTT broker.

I send temperature, humidity and luminosity data to the broker.

All seems to work, but the Arduino MEGA doesn’t send the data for more than 2 days. I explain: without any explanation, the Arduino disconnects from the broker and stops sending the data.

I attatch here my Arduino code, thanks a lot:

#include <Ethernet.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <Servo.h>


byte mac[] = { 0xDE, 0xED, 0xBF, 0xAF, 0xFF, 0xED };
IPAddress dnServer(1, 1, 1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress ip(192, 168, 1, 210);


IPAddress mqtt_server(192,168,1,220);


EthernetClient ethClient;
PubSubClient client(ethClient);



#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
const int LDRPin = A15;
const int DHTPin = 49;
const int PIRPin= 33;
const int ECHOPin = 43;
const int TRIGGERPin = 42;
const int BUZZPin = 39;
const int MQPin = 21;
const int LEDPin = 31;
const int WATERPin = 20;
const int RELAYPin = 35;
const int ACS712Pin = A11;
const int SERVOPin = 37;
DHT dht(DHTPin, DHTTYPE);
Servo servoPorta;

unsigned long prevMillis1 = 0;
unsigned long prevMillis2 = 0;
unsigned long time_now_1 = 0;
unsigned long time_now_2 = 0;
float lum = 0;
char lumStr[3];
char humStr[3];
char tempStr[3];
int pirState = 2;
int trigger = 0;
int hcsrState = 2;
volatile int mqState = 2;
int servoState = 2;
volatile int waterState =2;
int pos = 85;
int lightState;
int relayState;
int sensibility = 185; // use 185 for 5A Module
double voltage = 0;
double vRMS = 0;
double ampRMS = 0;
long duration;
long distanceCm;
char waterStr;



void reconnect(){
  
  while (!client.connected()) {
    Serial.println("Intentant connectar-se...");
    if (client.connect("Arduino_Client")) {
      Serial.println("Connectat");
    }else{
      Serial.print(F("Error de connexió, rc="));
      Serial.print(client.state());
      Serial.println(F(" Reintentar en 3 segons"));
      delay(3000);
    }
  }
  
}


unsigned long timerLlum = 0;         // timer per emagatzemar temps quan llum baixa de x per cent de lluminositat
unsigned long delayLlum = 7200000;   // temps que el llum estara ences un cop detecti que lluminositat baixa
    
void lightRead(){
      Serial.println ("lightRead");

      int inputLDR = analogRead(LDRPin);
      lum = map(inputLDR, 0, 1023, 0, 100);//Mapegem el resultat a un valor en 0 i 100
      dtostrf(lum, 2, 1, lumStr);
      client.publish("pidomohome/luminosity", lumStr);


}

void dhtRead(){
  Serial.println ("dhtRead");
  
  dht.begin();
  float t = dht.readTemperature();
  dtostrf(t, 2, 1, tempStr);
  client.publish("pidomohome/temperature", tempStr);
  float h = dht.readHumidity();
  dtostrf(h, 2, 1, humStr);
  if (isnan(h) || isnan(t)) {
      Serial.println("Error de lectura del sensor DHT-22");
      return;
  }
  client.publish("pidomohome/humidity", humStr);
  
}

//Llegir PIR
void pirRead(){
  
  if(millis() > time_now_2 + 1000){//Esperem 1 segon entre lectures
    time_now_2 = millis();
    int state = digitalRead(PIRPin);
    if (state == HIGH){
      client.publish("pidomohome/movement", "OPEN");
      Serial.print("Hi ha moviment!!! \n");
      pirState = 1;
      }
    if (pirState == 1){
      digitalWrite(LEDPin , HIGH);
    }
    if (state == LOW){
      pirState = 0;
      digitalWrite(LEDPin , LOW); 
      client.publish("pidomohome/movement", "CLOSED");
    }
}
}

unsigned long startHCSR = millis();
void hcsr04Read(){
  
  if (millis()-startHCSR > 2000) {//Esperem 2 segons entre lectures
      startHCSR = millis ();
      digitalWrite(TRIGGERPin, LOW);//LOW durant 4us per generar pols net
      delayMicroseconds(4);
      digitalWrite(TRIGGERPin, HIGH);//Generem trigger de 10us
      delayMicroseconds(10);
      digitalWrite(TRIGGERPin, LOW);
      duration = pulseIn(ECHOPin, HIGH);//Medim temps entre polsos en microsegons
      distanceCm = (duration * 10 / 292 / 2);// Transformem de distància a cm 
      Serial.print("La distància és de ");
      Serial.print(distanceCm);
      Serial.print("cm \n");
      if (distanceCm > 11 and hcsrState !=1){ 
        client.publish("pidomohome/door", "OPEN");
        hcsrState = 1;
      }
      if (hcsrState == 1){
        tone(BUZZPin, 500);
        digitalWrite(LEDPin , HIGH);
    }
      
      if (distanceCm <= 11 and hcsrState ==1){
        client.publish("pidomohome/door", "CLOSED");
        hcsrState = 0;
        noTone(BUZZPin);
        digitalWrite(LEDPin , LOW); 
      }
  }
 }


void mqRead(){
    bool gas = digitalRead(MQPin);

    if(gas and mqState != 1) {
      client.publish("pidomohome/fire", "OPEN");
      mqState = 1;   // info published
      tone(BUZZPin, 400);
      digitalWrite(LEDPin , HIGH);
      Serial.println ("Gas! Alarm");
    }

    if (!gas and mqState != 0) {
      client.publish("pidomohome/fire", "CLOSED");
      mqState = 0;   // info published
      noTone(BUZZPin);
      digitalWrite(LEDPin , LOW);
      Serial.println ("Gas OK");
    }
  }
  
void waterRead(){
    bool inputW = digitalRead(WATERPin);

    if(inputW and waterState != 1) {
      client.publish("pidomohome/flood", "OPEN");
      waterState = 1;   // info published
      tone(BUZZPin, 500);
      digitalWrite(LEDPin , HIGH);
      Serial.println ("Water! Alarm");
    }

    if (!inputW and waterState != 0) {
      client.publish("pidomohome/flood", "CLOSED");
      waterState = 0;   // info published
      noTone(BUZZPin);
      digitalWrite(LEDPin , LOW);
      Serial.println ("Water OK");
    }
}


float getVPP(){
  
  float result;  
  int readValue;             
  int maxValue = 0;         
  int minValue = 1024;  
  uint32_t startACS = millis();
  while((millis()-startACS) < 1000) {
       readValue = analogRead(ACS712Pin);
       if (readValue > maxValue) {
           maxValue = readValue;
       }
       if (readValue < minValue)  {
           minValue = readValue;}
   }
  

  result = ((maxValue - minValue) * 5.0)/1024.0;   
  return result;
  
 }


getVPP
void light(){

  Serial.println ("light");
  
  voltage =  getVPP();
  vRMS = (voltage / 2.0) * 0.707;
  ampRMS = (vRMS * 1000) / sensibility; 
  if (ampRMS>0.05 and lightState==0){
    lightState=1;
    client.publish("pidomohome/light", "ON");
  }  
 if (ampRMS<0.05 and lightState==1){
    lightState=0;
    client.publish("pidomohome/light", "OFF");
  }
 
}



void callback(char* topic, byte* payload, unsigned int length) {
 
  if (strcmp ("pidomohome/trigger", topic) == 0) {
  for (int i=0;i<length;i++) {
    char receivedChar = (char)payload[i];
    //Serial.println (receivedChar);
    if (receivedChar == 'N'){
      trigger = 1;
      Serial.println ("trigger activate");
    }
    if (receivedChar == 'F'){
      trigger = 0;
      Serial.println ("trigger de-activate");
    }
  }  
  }
  
  if (strcmp ("pidomohome/servo", topic) == 0) {
    for (int i=0;i<length;i++) {
      char receivedChar = (char)payload[i];     
      if (receivedChar == 'N' and servoState!= 1 and pos == 85){
        for (pos = 85; pos <= 165; pos += 1) {
          servoPorta.write(pos);
        }
        servoState = 1;
        pos = 165;
      }
      if (receivedChar == 'F' and servoState ==1 and pos == 165){
        for (pos = 165; pos >= 85; pos -= 1) {
          servoPorta.write(pos);
        }
        servoState = 0;
        pos = 85;
      } 
    }
  }
  
 if (strcmp ("pidomohome/light", topic) == 0){
    for (int i=0;i<length;i++) {
        char receivedChar = (char)payload[i];
        relayState = digitalRead(RELAYPin);

        if (receivedChar == 'F') {
          Serial.println ("light OFF");
          digitalWrite(RELAYPin, LOW);
        }

        if (receivedChar == 'N') {
          Serial.println ("light ON");
          digitalWrite(RELAYPin, HIGH);
        }
     }
  }
}
  



void setup() {
  
  Serial.begin(9600);
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  servoPorta.attach(SERVOPin);
  pinMode(LDRPin, INPUT);
  pinMode(DHTPin, INPUT);
  pinMode(PIRPin, INPUT);
  pinMode(ACS712Pin, INPUT);
  pinMode(TRIGGERPin, OUTPUT);
  pinMode(LEDPin, OUTPUT);
  pinMode(ECHOPin, INPUT);
  pinMode(BUZZPin, OUTPUT);
  pinMode(RELAYPin, OUTPUT);
  pinMode(MQPin, INPUT_PULLUP);
  pinMode(WATERPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(WATERPin), waterRead, CHANGE);
  attachInterrupt(digitalPinToInterrupt(MQPin), mqRead, CHANGE);

  // while (true) {
  //   testRele();
  // }
  
}

void testRele() {
  Serial.println ("Test rele");
  digitalWrite(RELAYPin, HIGH);
  delay (1000);
  digitalWrite(RELAYPin, LOW);
  delay (1000);
}


bool mqttConnectedFlag = false;

void loop() {
  
  if (!client.connected()) {

    if (mqttConnectedFlag) mqttConnectedFlag = false; // Reset flag MQTT connection

    Serial.print("Connecting ...\n");
    Ethernet.begin(mac, ip, gateway, subnet);
    reconnect();
    client.subscribe("pidomohome/#");
  }else{
    unsigned long time_now_1 = millis();
    if (time_now_1 - prevMillis1 >= 5000){
      Serial.print("Timer1\n");
      if (!mqttConnectedFlag) {   // Sends gas and water information when Arduino connects to the broker
        mqRead ();
        waterRead ();
        mqttConnectedFlag = true;
      }

      lightRead();
      dhtRead();
      pirRead();
      light(); // on/off
      prevMillis1 = millis();

    }
    
    if(trigger == 1){
       unsigned long time_now_2 = millis();
       if (time_now_2 - prevMillis2 >= 5000){
         Serial.print("Timer2\n");
         hcsr04Read();
         prevMillis2 = millis ();
       }
    }
    client.loop();
  }
  delay(100);
 
}

Thank you very much,

Best,

Josep

How does this relate to setup & use of OpenHAB??

@josep.mencion You may want to think about posting this in an arduino forum for max feedback. Some people here are suing arduino, many do not though and the focus of this forum is on OH2, so likely you will get only limited input. Some simple things to consider: thing about getting some logging done on your arduino (e.g., keep the IDE running) and, but this is a long shot, many a weird issues are caused by power failures, spikes, insufficient current of the power supply; not sure if this applies, but something to keep in mind. As a first step, use a different arduino board and power supply and see if you can repeat this.

Ok, will do. Is it possible to connect the power 12V entry and a,sk the USB to the computer? In that moment, I only power the Arduino with the 5V USB connected to the computer.

Thanks,
Best,
Josep

I’m sorry for the misunderstanding in the community using rules.

Josep

1 Like

Not sure exactly what you mean, but if your question was whether you can use two power supplies on the same board (via USB through your computer and through an external power supply), the answer is “it depends”. Some boards allow for that, others not. Please check before doing so, otherwise you can damage your board and in the worst case your computer.

OK, thanks.

Best,
Josep

Iepa!

I found the mistake in the code, and I paste it here to who it may serve. It was because when I defined the variable I only reserved 3 decimals.

So, in the Arduino code I have now defined these three variables with 13 significant figures reserved. It’s a really strange number, but it’s too big to have reserved decimal proms.

The problem was that when a variable extended from these 3 significant figures which were reserved before, the Arduino code crashed.

char lumStr[13];
char humStr[13];
char tempStr[13];

Thanks a lot and best,
Josep