Arduino IOTCloudTCP connection lost

Hi, I am using arduino IOT cloud for my project. I am currently using 2 arduino mkr 1010 devices and have defined a project for each one.

The idea is to use the 2nd one as a slave, having connected an env shield which measures variables such as temperature, humidity, etc. My 1st device is used as a master which displays these variables in an lcd display screen. The variables defined in the 1st project are linked with the ones in the 2nd one via iot cloud.

Once I run the project it works propperly for the first 5 seconds but after that an error is shown in my 2nd project serial port "ArduinoIoTCloudTCP::handle_Disconnect MQTT client connection lost" and the sensor values no longer upload to the 2nd project.

I have an idea of what might be causing the problem, arduino iot cloud refresh time might be too frequent, I tried to change the refreshing time of the values but this doens't solve the error. Does anyone have experience working with arduino iot cloud ?

1st project code:

#include <Arduino_MKRENV.h>
#include "thingProperties.h"
int muestras;

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
  
  if (!ENV.begin()) {
    Serial.println("Failed to initialize MKR ENV shield!");
    while (1);
  }
}
void loop() {
  ArduinoCloud.update();
  // Your code here 
  
  muestras = analogRead(A2);
  mV = map(muestras, 0, 1024, 0, 5000);
  co2 = map(mV, 0, 5000, 0, 10000);
  
  temperature = ENV.readTemperature();
  humidity    = ENV.readHumidity();
  
}

/*
  Since BoolSync is READ_WRITE variable, onBoolSyncChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onBoolSyncChange()  {
  // Add your code here to act upon BoolSync change
  
  Serial.print(mV);
  Serial.println(" mV");
  
  Serial.print(co2);
  Serial.println(" ppm");
  
  temperature = ENV.readTemperature();
  humidity    = ENV.readHumidity();
  
  Serial.print(temperature);
  Serial.println(" ºC");
  
  Serial.print(humidity);
  Serial.println(" %");
  
  
}
/*
  Since MV is READ_WRITE variable, onMVChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onMVChange()  {
  // Add your code here to act upon MV change
}

/*
  Since Co2 is READ_WRITE variable, onCo2Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onCo2Change()  {
  // Add your code here to act upon Co2 change
}

/*
  Since Temperature is READ_WRITE variable, onTemperatureChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onTemperatureChange()  {
  // Add your code here to act upon Temperature change
}

/*
  Since Humidity is READ_WRITE variable, onHumidityChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onHumidityChange()  {
  // Add your code here to act upon Humidity change
`

2nd project code:

#include "thingProperties.h"
#include <LiquidCrystal.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
}

void loop() {
  ArduinoCloud.update();
  // Your code here 
}

/*
  Since BoolSync2 is READ_WRITE variable, onBoolSync2Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onBoolSync2Change()  {
  // Add your code here to act upon BoolSync2 change
  /*
  if(bool_sync_2 = true)
  {
    lcd.begin(16, 2);
    lcd.print("Pulsa boton para");
    lcd.setCursor(0,1);
    lcd.print("mostrar parametros AQI");
  }
  else
  {
    lcd.begin(16, 2);
    lcd.print("CO2: ");
    lcd.print(co2_2);
    lcd.print("Temperatura: ");
    lcd.print(temperature_2);
    lcd.print(" ºC");
    
    lcd.setCursor(0,1);
    lcd.print("Humedad: ");
    lcd.print(humidity_2);
    lcd.print(" %");
  }
  */
  
}
/*
  Since Co22 is READ_WRITE variable, onCo22Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onCo22Change()  {
  // Add your code here to act upon Co22 change
  
  lcd.begin(16, 2);
  lcd.print("Parametros AQI: ");
  lcd.setCursor(0,1);
  lcd.print("CO2: ");
  lcd.print(co2_2);
  lcd.print(" ppm");
  
}

/*
  Since Temperature2 is READ_WRITE variable, onTemperature2Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onTemperature2Change()  {
  // Add your code here to act upon Temperature2 change
}

/*
  Since Humidity is READ_WRITE variable, onHumidityChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onHumidityChange()  {
  // Add your code here to act upon Humidity change
}
/*
  Since Humidity2 is READ_WRITE variable, onHumidity2Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onHumidity2Change()  {
  // Add your code here to act upon Humidity2 change
}

1st project: Slave device

2nd project: master device

Hi @arsma - Did you get anywhere with this problem? I am banging my head with this also! I have been using ArduinoIOTCloud for about 20months on ESP8266 but am having thi now on ESP32.

I would recommend setting the debug level to 4 - it might give you a better idea of what is failing.

I note your second device shows 'offline' - was it ever on-line? Hover over the 'offline' to see last activity

Hi @mick3000. I have no clue what the problem might be, but I presume the error is related to the Arduino cloud and its limitations, specifically the size of the data transfer and its refresh rate.

I found out a lot of people are using Arduino IOT cloud systems in simpler ways, such as home automation devices such as smart switches and controlled lights.

My conclusion is that the Arduino IOT cloud is still limited for these systems, which require more data traffic. But I wish someone with deeper knowledge than me could respond.

Hi @arsma. I think you are making a wrong assumption. AIoTC can handle significant amounts of data. At an update rate up to every second.
I found my problem was due to an issue with my wifi router not connected to the Internet.
I wonder if you have an error in the code for the second device?
Have you tried testing it with simpler sketch?

Hi @mick3000 I am using my phone as a router because I've used my home router before and I've experimented with connection issues. My home router usually has 5 devices connected besides my own PC, so I thought I could get a better connection with my phone. In fact, the variable values upload correctly until it stops for a period of time and then works again. I am getting the following message during this period of the device not working: the serial monitor shows the following error: "ArduinoIoTCloudTCP::handle_ConnectMqttBroker". I have seen different posts complaining about the same error but didn't find a reason or a solution

I tried simplifying the code of my second sketch, and this problem seems to keep happening; I have no code whatsoever. Also, in the picture I uploaded from my second device, you marked that it appeared to be offline. This is because at the moment I took the picture, I was still configuring the device; this doesn't happen now.

This is good! To come online the device is being recognised by the cloud security. In your logs for either device do you see a cloud message saying the Thing has connected? It must be there for the first device as it is connecting. Is it there for the second device.
I find my iPhone is very unreliable as a hotspot for devices. Most wifi routers handle more than 10 connections.

I am getting the following message during this period of the device not working: the serial monitor shows the following error: "ArduinoIoTCloudTCP::handle_ConnectMqttBroker".

Are you saying the second device connects sometimes? I thought that it was NEVER connecting? If it is connecting and then losing connection it could be that you have blocking code (delay() or while() etc. waiting for several seconds). Mqtt does not like being held up!

I have been working for a while and have had new ideas.

I've decided to program this project using Arduino Ide since I could not upload code to my board via IOT Cloud.

image

image

As you can see, I can successfully upload code using the IDE.

I have worked in my code and managed to pull out a device that reads data from an CO2 and CO sensor and shows it on the serial monitor and a 1602 LCD.

I tried to integrate my Arduino MKR ENV Shield and get temperature and humidity values, but when I do so, the LCD stops showing data. Note that when I plug in the MKR env shield, it keeps working well, but it stops working when the instruction "temperature = ENV.readTemperature();" is used.

image

I am using the next pin connection:

  • Arduino's D0-D3 pins to LCD's D4-D7 pins
  • Arduino's D10 (MISO) to LCD's RS pin
  • Arduino's D10 (MOSI) to LCD's EN pin

Does the shield communication interfere with the pins I am using for my LCD display? Is there any other way I can connect the LCD so it does not interfere with the pins the MKR is using?

That's the code I am using, it shows CO2 and CO values into the Seial Port and LCD display

#include <Arduino_MKRENV.h>
#include <LiquidCrystal.h>
                                                      
#define         MG_PIN                       (A0)     //define which analog input channel you are going to use
#define         DC_GAIN                      (8.7)   //define the DC gain of amplifier

/***********************Software Related Macros************************************/
#define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
#define         READ_SAMPLE_TIMES            (5)     //define the time interval(in milisecond) between each samples in
                                                     //normal operation

/**********************Application Related Macros**********************************/
//These two values differ from sensor to sensor. user should derermine this value.
#define         ZERO_POINT_VOLTAGE           (0.220) //define the output of the sensor in volts when the concentration of CO2 is 400PPM
#define         REACTION_VOLTGAE             (0.035) //define the voltage drop of the sensor when move the sensor from air into 1000ppm CO2

/*****************************Globals***********************************************/
float           CO2Curve[3]  =  {2.602,ZERO_POINT_VOLTAGE,(REACTION_VOLTGAE/(2.602-3))};
                                                     //two points are taken from the curve.
                                                     //with these two points, a line is formed which is
                                                     //"approximately equivalent" to the original curve.
                                                     //data format:{ x, y, slope}; point1: (lg400, 0.324), point2: (lg4000, 0.280)
                                                     //slope = ( reaction voltage ) / (log400 –log1000)

const int       AOUTpin   =  1  ;                    //the AOUT pin of the CO sensor goes into analog pin A1 of the arduino
//const int       DOUTpin   =  5  ;                    //the DOUT pin of the CO sensor goes into digital pin D5 of the arduino
//const int       ledPin    =  6  ;                    //the anode of the LED connects to digital pin D6 of the arduino

const int rs = 10, en = 8, d4 = 3, d5 = 2, d6 = 1, d7 = 0;    // initialize the library by associating any needed LCD interface pin
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);            // with the arduino pin number it is connected to

bool            boton = false;
int             limit ;                              //limit is the digital threshold coming form digital pin of MQ-7 sensor
int             value ;                              //value will read Analog output of MQ-7 sensor 
String          string_value;
String          string_percentage;

int             percentage;
byte            flecha[8] ={
  B00010,
  B00100,
  B01000,
  B10000,
  B01000,
  B00100,
  B00010
};

void setup()
{
    Serial.begin(9600);                              //UART setup, baudrate = 9600bps
    lcd.begin(16, 2);                                // set up the LCD's number of columns and rows:
    lcd.clear();
    lcd.createChar(1,flecha);
    //pinMode(DOUTpin, INPUT);                         //sets the pin as an input to the arduino
    //pinMode(ledPin, OUTPUT);                         //sets the pin as an output of the arduino

}

void loop()
{                                  
    float volts;
    if (!ENV.begin()) {
        Serial.println("Failed to initialize MKR ENV shield!");
        while (1);
   }
    
    Serial.println("Environmental data demonstrarion: ");
    
    volts = MGRead(MG_PIN);
    Serial.print( "SEN0159:" );
    Serial.print(volts);
    Serial.print( "V           " );

    percentage = MGGetPercentage(volts,CO2Curve);     //stores the CO2 ppm value using MGPercentage function

    lcd.setCursor(0,0);
    lcd.print("CO2: ");
    
    Serial.print("CO2:");
    if (percentage == -1) {
        Serial.print( "<400");
        lcd.write(1);
        lcd.print("400");
    } else {
        Serial.print(percentage);
        lcd.print(percentage);
    }
    lcd.print(" ppm");

    
    Serial.print( "ppm" );
    Serial.print("\n");
    
    value = analogRead(AOUTpin);                    //reads the analaog value from the CO sensor's AOUT pin

    lcd.setCursor(0,1);
    lcd.print("CO: ");
    lcd.print(value);
    lcd.print(" ppm");
    
    Serial.print("CO value: ");
    Serial.print(value);//prints the CO value
    Serial.println(" ppm");//prints the limit reached as either LOW or HIGH (above or underneath)

    if (limit == HIGH){
       digitalWrite(ledPin, HIGH); //if limit has been reached, LED turns on as status indicator
       Serial.println("Alarma CO");
    }
    else{
       digitalWrite(ledPin, LOW);//if threshold not reached, LED remains off
    }
    Serial.print('\n');

}

/*****************************  MGRead *********************************************
Input:   mg_pin - analog channel
Output:  output of SEN-000007
Remarks: This function reads the output of SEN-000007
************************************************************************************/
float MGRead(int mg_pin)
{
    int i;
    float v=0;

    for (i=0;i<READ_SAMPLE_TIMES;i++) {
        v += analogRead(mg_pin);
        delay(READ_SAMPLE_INTERVAL);
    }
    v = (v/READ_SAMPLE_TIMES) *5/1024 ;
    return v;
}

/*****************************  MQGetPercentage **********************************
Input:   volts   - SEN-000007 output measured in volts
         pcurve  - pointer to the curve of the target gas
Output:  ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
         of the line could be derived if y(MG-811 output) is provided. As it is a
         logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
         value.
************************************************************************************/
int  MGGetPercentage(float volts, float *pcurve)
{
   if ((volts/DC_GAIN )>=ZERO_POINT_VOLTAGE) {
      return -1;
   } else {
      return pow(10, ((volts/DC_GAIN)-pcurve[1])/pcurve[2]+pcurve[0]);
   }
}

I have a DHT22 sensor that I could use in substitution of the ENV Shield, but I prefer to use the ENV Shield if there is a way to solve the issue.

After solving this problem, I have to upload the parameters to the Arduino IOT Cloud so I can build a dashboard in some way. I saw a tutorial where MKR 1000 was used as a server and was sending data to a web IP:

Is there a way to do this by using gauges and indicators to show the values in a prettier way?

Hi @arsma. These are the pins used by the MKR ENV Shield:

Pin Use
4 SD (SPI)
6 HTS221 DRDY
7 LPS22HB DRDY
8 SD (SPI)
9 SD (SPI)
10 SD (SPI)
11 LPS22HB, HTS221, TEMT6000 (I2C)
12 LPS22HB, HTS221, TEMT6000 (I2C)
A2 Light sensor

But you aren't using an SD card so there shouldn't be any conflict between the pins.

HI @ptillisch Thanks for your useful information. The code runs well while the mkr is connected; it is when I upload the "temperature = ENV.readTemperature();" expression.

I thought the temperature sensor had some kind of incompatibility or overlap with the Arduino pins I am using. But now I have no clue what the problem might be.

My advice is to create a demonstration program that contains only the absolute minimum of code required to produce the fault. Doing this will make the situation easier to understand by removing all irrelevant complexity from the system.

I find that often by the time I have completed this work the cause of the fault has become clear to me. Even if it doesn't, you can then share this minimal, reproducible, verifiable example (MCVE) here on the forum. It will be of value to the helpers here.