08/08/2019

ESP8266 Light Sleep with MQTT

By snorlaxprime

This is the continuation of the ESP8266 Light Sleep mode. In this post, I will show the practical example of using the Light Sleep mode combined with MQTT. For this to work you will need the following components:

  • ESP8266
  • MQTT broker account (I am using shiftr.io)
  • Temperature Sensor LM35

We are reusing the same temperature sensor in the previous post on ESP8266 Deep Sleep mode. The connection diagram can be seen below:

The idea is to have the ESP8266 in deep sleep most of the time to save the battery power and then only wakes up when the button is pressed. When it wakes up it will connect to the WiFi, take the measurement of the temperature via the temperature sensor and then post it to the MQTT broker. So let’s get started:

Step 1. Defining the MQTT broker connection

The following code defines the MQTT broker, because I am using the shiftr.io service for this example, I am using their test account. For your security you should create your own account and make sure to use your own username and password to post to the “topic”.

// MQTT info
 const char* thehostname = "broker.shiftr.io";
 int port = 10031;
 const char* user = "try";
 const char* user_password = "try";
 const char* id = "ESP8266";

Step 2. Setting up section

Similar to the previous post, we are initialising the serial connection for debugging purposes and initialisation of the GPIO pins. Additionally we need to define the connection to the MQTT broker. This is shown in the following code:

void setup() {
   Serial.begin(115200);
   Serial.println();
   gpio_init(); // Initilise GPIO pins
     // Connect to MQTT
   client.begin(thehostname, net);
   client.onMessage(messageReceived);  
 }

Step 3. Loop() section of code

Different from the Deep Sleep mode, the loop section is where the light sleep mode will wake up and perform the temperature reading and posting the results to the MQTT broker. This is shown in the below code:

void loop() {
   initWifi();
   data();
   delay(200);
   Serial.println("Going to sleep now");
   light_sleep();
   doDelays();
   Serial.println("Wake up");
 }

It is necessary to call initWifi() function first, as this will make sure that when ESP8266 wakes up, the first thing it will do is to connect to the WiFi. Then the data() is where we get the temperature reading (this is explained in step 5), and posting it to MQTT broker at the same time. It is necessary to set a delay after this processing, as the light_sleep() function takes a while to take affect and this is to ensure that the code will not loop back when the ESP8266 is still trying to sleep.

Step 4. InitWifi() function

InitiWifi() function is very similar to the InitWifi() function used in the previous post. The sole purpose of this is to attemp connection to the WiFi and also connecting to the MQTT broker. The code can be seen below:

void initWifi() {
   WiFi.mode(WIFI_STA);
   WiFi.begin(ssid, password);  
 Serial.print("Attempting to connect: ");
   //try to connect for 10 seconds
   int i = 10;
   while(WiFi.status() != WL_CONNECTED && i >=0) {
     delay(1000);
     Serial.print(i);
     Serial.print(", ");
     i--;
   }
   Serial.println("");
   if(WiFi.status() == WL_CONNECTED){
     Serial.print("WiFi connected, IP address: "); Serial.println(WiFi.localIP());
     Serial.print("\nconnecting to MQTT…");
       while (!client.connect(id, user, user_password)) {
         Serial.print(".");
         delay(1000);
       }
       //client.subscribe("/homeautomation/temperature");
   }
     else {
       Serial.println("Connection failed - check your credentials or connection");
   }  
 }

Step 5. Data() function

This section performs the heavy listing by starting to read the LM35 via analog pin A0, then converting this to the temperature value and then posting the value to the MQTT broker in the “/homeautomation/temperature” topic, if the MQTT broker is connected. This is shown in the following code:

void data() {
   int value = analogRead(A0);
   float volts=(value * 3.03) / 1024;      //conversion to volts
   tempC = volts*100.0;             //conversion to temp Celsius
   Serial.print("Temperature C: ");
   Serial.println(tempC);
 if (client.connected()) {
     Serial.println("MQTT client connected");
     client.publish("/homeautomation/temperature", String(tempC));
     delay(1000);
   } else {
     Serial.println("MQTT client not connected");
   }
 }

Step 6. Light_sleep() function

The light_sleep() function similar to the previous post is to force the ESP8266 to go into light sleep for indefinite period of time until the pin GPIO2 (D4) is connected to the GND. The code is shown below:

void light_sleep(){
   wifi_station_disconnect();
   wifi_set_opmode_current(NULL_MODE);
   wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); // set sleep type, the above posters wifi_set_sleep_type() didnt seem to work for me although it did let me compile and upload with no errors 
   wifi_fpm_open(); // Enables force sleep
   gpio_pin_wakeup_enable(GPIO_ID_PIN(2), GPIO_PIN_INTR_LOLEVEL); // GPIO_ID_PIN(2) corresponds to GPIO2 on ESP8266-01 , GPIO_PIN_INTR_LOLEVEL for a logic low, can also do other interrupts, see gpio.h above
   wifi_fpm_do_sleep(0xFFFFFFF); // Sleep for longest possible time
 }

You can access the full source code here.

Once you have uploaded the code to the ESP8266 and wired the connection as per diagram above, you should be able to test the posting. The following image shows my log files when the button is pressed.

I hope you can put this into a good use. Please drop me a line if you like this post and don’t hesitate to let me know if you have any further questions related to this topic. If you like you can subscribe to the blog to receive regular update on IoT related topic.