Very DeepSleep and energy saving on ESP8266 – Part 2: Sending data with HTTP

In an earlier post,  I showed how to  try and do some major energy saving in case you are using a battery. I gave a working framework sketch, that did all but actually read data or send data as it just focussed on the energy saving.

Though it isn’t hard to add that to the program, as I indicated where you could add a ‘read sensor’ and ‘senddata’ procedure, I realize that that may still cause some obstacles for a beginner, so I will show how to add some code to send the data somewhere.

Though MQTT is a popular way to send data, in this example I have chosen to send data to a MySQL database (in fact I am using MariaDB, but that works the same).

As there is no reason to reinvent the wheel, for setting up the database and the needed  php files, I refer to the randomnerdstutorial website that has 2 excellent tutorials about this. We will use their server-side code (database and php files) to send the data to.

We will use the BME280 to gather the data.

Since the BME280 is used as I2C device, we need to inlude the Wire library. As we will use the Adafruit library to read the data, we will actually need two  more libraries, that we add in the global section of the program. We will also declare the object:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h> //defaults to 0x77, change that if yr BME is 0x76
Adafruit_BME280 bme;

In the Setup() section, we have to initialize the library.  The library defaults to the BME having an I2C address of 0x76, but if you happen to have a 0x77 module, here is where you can change the default.
We then do am optional check to see if the BME280 is detected and in principle you are good to go. However, in my previous article I mentioned you could put the BME280 to sleep in between readings and that is what we will do. Therefore for now I only added a jump to a procedure that i call ‘BMEsetup’. We will fill it in later

Wire.begin();
//bme.begin() will return True if the sensor was found, and False if not. If you get a False value back, check your wiring!
status = bme.begin(); //bme.begin(address) 0x76 or 0x77
if (!status) {
Serial.println("no BME detected");
delay(1);
}
BMEsetup(); // set weathermonitormode

So now we have to do 2 things: we have to read the sensor  and send those in an HTTP request.

As we are using Forced Mode we have to wake the sensor and tell it it has to take a new measurement:

bme.takeForcedMeasurement();

We can read the sensor and  build  our HTTP request string in one go like so:

// Prepare your HTTP POST request data

httpRequestData = "api_key=" + apiKeyValue + "&sensor=" + sensorName
+ "&location=" + sensorLocation + "&value1=" + String(bme.readTemperature())
+ "&value2=" + String(bme.readPressure() / 100.0F) + "&value3=" + String(bme.readHumidity())+ "";

Sadly, the Adafruit library is extremely inefficient in reading the data. The datasheet advises a ‘burst read’ of the data, both for speed and to prevent mix-up of data. The adafruit library has chosen to do separate register readings, but to make matters worse, it precedes the pressure and humidity readings each with a temperature reading first, which is then discarded. So 3 measurements become 5 which adds at least 4 ms to the total. As we are reading the temperature first in our httprequest string, we could opt to remove the extra reads from the Adafruit library. The Sparkfun library does not have these extra reads.

The total conversion time of the 3 measurements comes to 13msec and it is better to do that while the radio is still off, especially when the library adds anothe 4 msecs

As I plan to send the http request in a seperate procedure (to keep it all clear and transparent), we have to define the String variable httpRequestData as a global variable (by adding it in the global section of the program), like so:

String httpRequestData;

Then it is time to Switch the WiFi on like described before and make our http request.

void sql() {
//Check WiFi connection status
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;

// Your Domain name with URL path or IP address with path
http.begin(serverName);// deprecated.

// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");

// Send the request and collect the response
int httpResponseCode = http.POST(httpRequestData);

if (httpResponseCode > 0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
}
else {
Serial.println("WiFi Disconnected");
}
}

The http.begin(serverName); command, is or will be deprecated in near future. I understand the proper command then will be: http.begin(client,serverName);. Current code is working.

Now we only have to define the BMEsetup routine that we called earlier. Thats an easy one:

// weather monitoring
void BMEsetup() {
Serial.println("-- Weather Station Scenario --");
Serial.println("forced mode, 1x temperature / 1x humidity / 1x pressure oversampling,");
Serial.println("filter off");
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X1, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF );
}

Download the entire file here.  After you got it working feel free to delete the print statements.

A word on voltage monitoring
In my previous article I mentioned that voltage monitoring -a popular thing to do when using a battery- needs a voltage divider that can be a considerable, constant drain on on the battery.
If you are using a LiPobattery that can be as high as 4.2Volts, a 320k over 1ook voltage divider is a decent choice, but still adds to a discharge of the batteries. From that aspect, measuring the internal Vcc is an interesting alternative.
Sure, if you use a stabiliser to get the battery voltage down to 3.3 Volt, initially you have no info on the battery voltage, but you will know when it gets critical.
Presume you have an HT7833 that has a voltage drop og 360 mV. Suppose the output is a rock solid 3.3Volt, then the only thing you know is that your battery is still OK, i.e >3.63 Volt. The moment your Vcc drops below 3.3Volt you know yr battery is dropping below its nominal 3.7 Volt, while there still is plenty of juice to feed your ESP.
If you want to monitor the internal Vcc, then just add.

ADC_MODE(ADC_VCC);

to the declaration section and read the voltage with

ESP.getVcc()/1023.0F

Adding fields
Should you want to add a field, e.g. for the battery voltage, then there are several things to do:

    1. add  String(ESP.getVcc()/1023.0F) to the httpRequest string
    2. add a field to the database. you can do that with
      ALTER TABLE yourtable ADD newfieldname VARCHAR() after fieldname

      but it is better to use your own specific database management system. (I use webmin)

    3. Adapt the post-esp-data.php file to collect and store data, to cater for an extra field. Go ahead, try, it is simple
    4. Do the same for the esp_data.php file

Board
The best board to use would be an ESP12F:

In a follow up article I will show how to implement MQTT with this deep sleep example

Part 1 -DeepSleep General
Part 2 -DeepSleep HTTP publishing
Part 3 -DeepSleep MQTT Publishing
Part 4 -DeepSleep MQTT Subscribing
Part 5 -Deepsleep ESP-NOW