Chat freely about anything...

User avatar
By juan3211
#61796 Hi, I have just begin with ESP8266, really with wemos mini d1 boards.

Before, I have read lots of web pages and forum's post.

I usually want to check things that I will use in my sketches and now I was trying to see the improvement of MQTT over HTTP when you have to sleep, get some data, send it, and sleep again. That is a usual application for ESP8266 modules.

I have read always that MQTT is better than HTTP because of you have to send less bytes and, about answer from server, it is faster than HTTP.

So I have written and sketch and upload it in two of my Wemos D1 mini boards, one of them is sending data with HTTP (get) and the other one with MQTT. (you can find my sketch attached here)

See the sketch in github: https://github.com/ortegafernando/TESTmqttVShttp/blob/master/test.ino or at final of this post. ( I know that sketch is not perfect, but it is only for test)

Both of them same data and same server: thingspeak.

The trick of the sketch is that i use RTCmemory to save how long take ESP8266 to send data to the server. millis() give me miliseconds from boot, and each wake from deepsleep is a new boot. They send data every two minutes. The MQTT board was startedfew hours after the HTTP board (but for my test, that is the same)

As you can see here: https://thingspeak.com/channels/220480 I have 4 fields:

1. HTTP (get) board: Vcc and Time (Vcc is aprox, is only to see me when to disconect them as they are working from a LiFePO4 battery, and to calculate how many days they work).

2. MQTT board: Vcc and Time (Vcc idem)

What is strange is that MQTT time is higher than HTTP time.

What do you think about it ? Is my sketch wrong ? May be thinkspeal new mqtt server is not as good as its HTTP answer ?

Probably I am doing something wrong. Please, help me to find it !!!! Thanks.

Hope you understand me and comment about this.

Thanks.

Code: Select all//ESP.getResetInfoPtr
extern "C" {
#include <user_interface.h>
}

//Tipo 0
#include <ESP8266WiFi.h> // ESP8266WiFi.h library
// make TCP connections
WiFiClient client;

const char* ssid     = "xxxx";
const char* password = "xxxx";
const char* host = "api.thingspeak.com";
const char* writeAPIKey = "xxxx";

//Tipo 1
#include <PubSubClient.h>
// Initialize the PuBSubClient library
PubSubClient mqttClient(client);
// Define the ThingSpeak MQTT broker
const char* mqttserver = "mqtt.thingspeak.com";
const char* channelID = "220480";

byte tipo = 1;
//If define DEEPSLEEP both methods will deepsleep instead of delay. Also, will send to Thingspeak miliseconds for sending de message
#define DEEPSLEEP
#define SLEEPTIME 120  //segundos
/*
 * Tipo:
 * 0: sin sleep, con HTTP, en la oficina (habitacion de estudiar), envio cada 120 segundos
 * 1: idem al 0, pero mediante MQTT
 */

#ifdef DEEPSLEEP
    //Con deepSleep y dado que Thingspeak solo me deja mandar un dato cada 15 segundos, lo que hago es guardar el tiempo en el RTCmem y luego envio el tiempo "con el siguiente".
    #define RTCMEMORYSTART 64
    #define COLLECT 27
    typedef struct {
      int magicNumber;
      unsigned long tiempo;
    } rtcManagementStruc;
    rtcManagementStruc rtcManagement;
    byte buckets = 0;
#endif


float vcc = 0;
unsigned long tiempo = 0;

void setup() {

  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.print("Booted "); 

    rst_info *rsti;
    rsti = ESP.getResetInfoPtr();

    Serial.print("rsti->reason: ");
    Serial.println(rsti->reason);

  #ifdef DEEPSLEEP

//enum rst_reason {
//        REASON_DEFAULT_RST              = 0,    /* normal startup by power on */
//        REASON_WDT_RST                  = 1,    /* hardware watch dog reset */
//        REASON_EXCEPTION_RST    = 2,    /* exception reset, GPIO status won’t change */
//        REASON_SOFT_WDT_RST     = 3,    /* software watch dog reset, GPIO status won’t change */
//        REASON_SOFT_RESTART     = 4,    /* software restart ,system_restart , GPIO status won’t change */
//        REASON_DEEP_SLEEP_AWAKE = 5,    /* wake up from deep-sleep */
//        REASON_EXT_SYS_RST      = 6             /* external system reset */
//};

  //if (rsti->reason==0){Serial.println("CH_PD button from deep sleep = SW1");};
  //// PowerOn from normal run, not from deep sleep is 0, the same as CH_PD from deep sleep !!!
  //if (rsti->reason==5){Serial.println("Power ON from deep sleep!");};
  //if (rsti->reason==6){Serial.println("RST button from deep sleep = SW2");}
 
    //Paquetes de 4 bytes, que es como se organiza la memoria del RTC
    buckets = (sizeof(rtcManagement) / 4);
    if (buckets == 0) buckets = 1;
   
    switch (rsti->reason) {
      case 5:
        //Serial.println(" from RTC-RESET (ResetInfo.reason = 5)");
        //Leer en paquetes de 4
        system_rtc_mem_read(RTCMEMORYSTART, &rtcManagement, buckets * 4);   
        if (rtcManagement.magicNumber == COLLECT) {
          //Parece que esta bien el numero de verificación => la RTCmem no se ha borrado => cojo el tiempo
          tiempo = rtcManagement.tiempo;
        } else {
          //Reinicio el sistema para la siguiente
          rtcManagement.magicNumber = COLLECT;
          rtcManagement.tiempo = 0;
          system_rtc_mem_write(RTCMEMORYSTART, &rtcManagement, buckets * 4);         
        }
        break;
      case 6:
        //Serial.println(" from POWER-UP (ResetInfo.reason = 6)");
        //Reinicio el sistema para la siguiente
        rtcManagement.magicNumber = COLLECT;
        rtcManagement.tiempo = 0;
        system_rtc_mem_write(RTCMEMORYSTART, &rtcManagement, buckets * 4);     
        break;
    }
  #endif
 
  //Connect to WiFi network
  WiFi.persistent(false);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  if (tipo == 1) {
    // Set the MQTT broker details
    mqttClient.setServer(mqttserver, 1883);
  }
}

void loop() {

  switch (tipo) {
    case 0:
      if (!client.connect(host, 80)) {
        return;
      }
      {
        String url = "/update?api_key=";     
        url+=writeAPIKey;
        url+="&field1=";
        url+=String( analogRead(0) * 4.2 / 1023 );
        #ifdef DEEPSLEEP
          if (tiempo != 0) {
            url+="&field2=";
            url+=String(tiempo);
          }
        #endif
        url+="\r\n";
        // Request to the server
        client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" +
                   "Connection: close\r\n\r\n");
      }
      client.stop();
      break;
    case 1:
      // Check if MQTT client has connected else reconnect
      if (!mqttClient.connected())
      {
        reconnect();
      }
      // Call the loop continuously to establish connection to the server
      mqttClient.loop();
      mqttpublish();
      break;
  }
  #ifdef DEEPSLEEP
      //Grabo el tiempo hasta aqui
      tiempo = millis(); 
      rtcManagement.tiempo = tiempo;
      //Y lo guardo en la memoria RTC para el siguente reinicio tras el reset
      system_rtc_mem_write(RTCMEMORYSTART, &rtcManagement, buckets * 4);
      ESP.deepSleep(120*1000000);  //microseconds
  #else
      delay(120*1000);
  #endif 
}

//TIPO 1
void reconnect()
{
  // Loop until we're reconnected
  while (!mqttClient.connected())
  {
    if (!mqttClient.connect("ESP8266"))
    {
      // Wait 5 seconds before retrying to connect again
      delay(5000);
    }
  }
}
void mqttpublish() {
  // Create data string to send to ThingSpeak
  String data="field3=";
  if (tipo == 0) {
    data="field1=";
  }
  data+=String( analogRead(0) * 4.2 / 1023 );
  #ifdef DEEPSLEEP
    if (tiempo != 0) {
      if (tipo == 1) {
        data+="&field4=";
      } else {
        data+="&field2=";
      }
      data+=String(tiempo);
    }
  #endif
  // Get the data string length
  int length = data.length();
  char msgBuffer[length];
  // Convert data string to character buffer
  data.toCharArray(msgBuffer,length+1);
  //Serial.println(msgBuffer);
  String url="channels/";
  url+=channelID;
  url+="/publish/";
  url+=writeAPIKey;
  length = url.length();
  char urlBuffer[length];
  url.toCharArray(urlBuffer,length+1); 
  // Publish data to ThingSpeak. Replace <YOUR-CHANNEL-ID> with your channel ID and <YOUR-CHANNEL-WRITEAPIKEY> with your write API key
  mqttClient.publish(urlBuffer,msgBuffer);
  // note the last connection time
  //lastConnectionTime = millis();
}
User avatar
By al1fch
#61805 Hi !

I've made same king of tests : ThingSpeak-MQTT vs ThingSpeak-HTTP with deepsleep.
Same average time for me, ThingSpeak-MQTT is not shorter than HTTP Get. (about 1,2s from awake to sleep)
Same results for some of us :
http://www.esp8266.com/viewtopic.php?f=29&t=13235

Why ? Maybe MQTT is shorter with permanent connection to broker, here with deepsleep we have to reconnect to broker when ESP8266 awakes.
User avatar
By juan3211
#61838 Hi, after speakin with Andreas Spiess I have now my own answer. I want to post here to help other people with my same question.

Please visits his youtube channel, he has good videos for ESP8266 stuf:

https://www.youtube.com/channel/UCu7_D0o48KbfhpEohoP7YSQ

Here is some pieces of Andreas and I have been speaking:

..................
To compare two different technologies is always interesting and important. Battery live should be very similar because the ESP uses most of the energy to connect to Wi-Fi, and not to transfer these few data, which is done in a very short time. And in addition, the difference in bytes between a simple GET and a MQTT message is not big ( only a few bytes).

Lets assume you would have 100 nodes which need your info. With GET, you have to connect 100 times (to each node), with MQTT only once (to the broker). Then, you would see the big difference in battery live.

The purpose of GET and MQTT are quite different: MQTT is a Machine-to-Machine protocol. Thingspeak is a cloud storage and visualization. MQTT has concepts like QOS, Last Will, Subscription (one-to-many) etc.

As far as I know, Thingspeak even does not distribute your messages to other nodes. So, Thingspeak is not a good example for MQTT. It is better for GET. This is, why they only added MQTT very recently, and mostly because of marketing purposes

...............
I think that what I have read about MQTT is "a bit of marketing". I am read a lot of web pages saying that it is better to send data through MQTT, not HTTP.

It is incredible how many pages about ESP, SIM900 and SIM800 saying that is better to send data with MQTT !!!!
..........................
If you want to signal messages from device to device, MQTT has clear advantages over HTTP:
1. It is standardized.
2. HTTP is very flexible, but not as much standardized on the field of transmission of data from small devices.
3. Error handling for HTTP scenarios (e.g. retransmission in case of problems) have to be programed by you. MQTT has a QOS concept buit in and you can use it if you want.

I use HTTP for small setups, also because it can be called from a browser. As soon as you have three or more devices, MQTT is usually easier in handling. But this is not because of the protocol, it is because of the concept.

And there is the most important difference: HTTP is a direct way from sender to receiver. MQTT always needs a broker.
....................................
I understand that if you want to communicate two esp8266 or one esp8266 and an arduino with sim900 gsm chip, or a raspberry pi .... It will be better to do it with MQTT system. But if you want (it is my case at this moment) save data to a MySQL database ( for example), may be http will be better (not QOS or you have to program or control your http gets and responses)
................................

I hope it helps to somebody else.

I wanted to know if the effort to understand MQTT over HTTP/PHP will worth. Depens on your case.

Regards.
User avatar
By torntrousers
#61882 A couple of comments on that sketch -

On the HTTP side it doesn't wait to receive the http response, it does the "client.print(String("GET ")..." and then client.stop(). I'm a bit surprised thats even working and the sent data is actually getting stored in ThingSpeak. If the connection is closed before ThingSpeak gets to sending the HTTP 200 OK response then the ThingSpeak sever may well just discard the request if it hasn't processed it yet.

Another thing, not related to this HTTP/MQTT comparison, its always doing WiFi.begin(ssid, password), I've heard (though not tested) that that is slower than just letting the ESP auto connect to the previously used SSID, which is why you often see code doing:

if (strcmp (WiFi.SSID().c_str(), ssid) != 0) {
WiFi.begin(ssid, password);
}

HTH.

EDIT: Hope thats not sounding negative, I think its interesting what you're doing, just pointing out its not timing the complete http request-response.