The IRF520 FET switching module

Various webstores sell a FET module that is aimed at switching high current loads with an Arduino or even a Raspberry pi.

The module seems quite handy, especially if you do not like soldering. It has everything you need, including handy screw connectors for that heavy load you plan to switch. A quick glance on the specs tells you it can deliver 9.7 amps at a 100 Volts and it has a resistance (Rdson) of 0.2 ohm and it is “for the Arduino” so you should be fine right?

Well….not really. The FET used, the IRF520 is not really suitable for the logic levels the Arduino is working with, let alone the 3.3Volt levels of the Raspi. The IRF520 is more at ease with 10 Volt gate voltage. I wrote a post on this subject a while ago.

Using Mosfets with TTL levels.
Power LED Drivers.

So suppose you just bought a couple of those modules. Can’t you use them at all?

Well… maybe but let’s have a look at the datasheet first. In the ‘electric characteristics’ it says that the treshold Vgs, that is the voltage between gate and source (usually ground) should be 2-4 volts for the FET to start conducting. That sounds great -as the Arduino delivers 5 Volt- but it isn’t. At the threshold Vgs the current flowing is only minimal, in this case 250uAmp. That is not a current you bought a powerfet for.

But, i hear you say, the arduino delivers 5 volt, surely 5 Volt should be OK. Well if we again look in the datasheet (Fig 3), yes 5 Volt looks a bit better

Transfer characteristics

At 5 Volt the module should be able to deliver some 4 Amps and that ofcourse is not bad. But there is a caveat. Section 28.2 of the atmega328 datasheet says that the HIGH output voltage of the I/O pins is 0.7 Volt lower than the Vcc. So let’s take the scenario in which you are using a phone charger to power your arduino and it only provides 4.8 volt. The Arduino output then will be 4.1 volt. That brings the drain current in the 250uA range again. That’s not good.

So what to do? Well if you were smart you’d say ‘lesson learned’ throw them in a box and buy a decent logic level FET e.g. the IRL520. That one can deli er some 9 amps on a 4 volt gate to source voltage. Sadly however those do not come on such a handy little board as this IRF520 module. ( the IPP096N03L however is probably an even better choice than the IRL 520)

If you really want to use the IRF520 module, coz you hate to let it go to waste, there are some options, but these are only practical if you have say a 12 volt source availeble, for instance if you wanted to use the module to drive a 12 Volt load:

Use a transistor to drive the FET: usually this is done by pulling up the gate to 12 volt with a 10k resistor and switching the gate to LOW with a transistor (e.g. a BC547). (This will invert the signal though). Like so:

FET driver

In this case however that will not work because the module contains a 1k pulldown resistor. So when the transistor receives a LOW on its base to switch the FET on the 10k will form a voltage divider with the 1k, rendering only 1 volt on the gate. So we would need to remove the pull down resistor. It is the resistor directly next to the SIG label. Most likely you would also need to remove the LED (next to Vcc label) or its 1k seriesresistor (next to GND label).

IRF520 switch module

A more elegant method is using an optocoupler such as the ubiquitous PC817 to drive the FET. A look at the datasheet tells us it has a max collector current of 50mA and a Vce of 0.2Volt in saturation.

Connection with optocoupler

Thus when the optocoupler opens a current of 12/500=24mA will flow (500 because the module has 2x1k resistor on the input). The voltage on the gate will be 12-0.2Volt.

Should you still looking to buy a ready to use MOSFET module, consider the D4184 module

D4184 module

Dynamic icons & colours in Asynchronous webserver

What I will describe might be cut and dry for many people but beginners may struggle with it, hence this short instruction.

Asynchronous webservers have some distinct advantages, he main one being the possibility to automatically update necessary elements of the served website without having to refresh the entire website. A typical example is a website with server readings. Only updating the readings without updating the entire website makes for a quiter few that is much easier on the eye. Asynchronous websites are typically combined with Websockets, Single Server events and/or AJAX/JavaScript.

Websites with sensor readings are often glammed up with icons and colours and it would be nice to be able to change those as well, depending on the server readings. An example is a thermometer icon showing a high scale in red when it is warm and a low scale in blue when it is cold.
sse-page

In order not to reinvent the wheel, I will take an example from the randomnerdtutorials website and alter that. Randomnerds Sara and Rui Santos regularly publish great content and you should check out thit site if you are not already doing that.

Recently they published a BME280based webserver, for the ESP8266 using SSE as well as one for the ESP32 and this should work on both, though I only tested it on an ESP8266.

There are more ways to skin a cat, but I will show the easiest/quickest way to change the randomnerds code to make the thermometer icon change depending on the measured temperature.

Quickly summarizing the working of the code:

  • The results of the BME280 readings are sent as ‘events’ to the webserver.
  • The webserver has some JavaScript eventhandlers that insert the readings at their proper place in the website.

So what we have to do to change the icons is:

  • Add an event
  • Add an event handler
  • Add appropriate html/css code for the webserver

As said, there are other ways of doing it, but this is the easiest to implement in the randomnerd code that I am using.

Add an event
After we get the readings of the BME280, the temperature reading is sent as an event to the webserver, inthis line events.send(String(temperature).c_str(), "temperature", millis());

We can find that line here:
right under that we will add another server event:
if (temperature <10) {
events.send("<i class='fas fa-thermometer-quarter' style='color:#0000ff;'></i>","warm", millis());
}else{
events.send("<i class='fas fa-thermometer-half' style='color:#059e8a;'></i>","warm", millis());
}

As wordpress sometimes garbles code a bit, it should look like this

This code checks if the temperature is below 10 degrees and if yes sends a piece of html that defines a new icon (fa-thermometer-quarter) and the color red. It sends that in an event with the name ‘warm’
If it is 10 degrees or higher, it restores the ‘old’ icon and color. If you want that to be a blue color the colour code should be ff0000 rather than ‘059e8a’.

Where can we find that extra icon we need:

Have a look at the HTML and CSS code. The icons that are used are found in a “style sheet” on the “awesomefonts.com” website. As it is on an external website, we call it an “external style sheet” and the code links to it with the following statement found in the heading of the HTML code:
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css"

Checking the awesome font website, we can find a low temperature thermometer icon. I picked “fa-thermometer-half”

Event handler
Now we need to add an Eventhandler that knows what to do with the event.
We find the event handlers in the <script></section> section of the webserver. The one handling the temperature looks like this:
Right under that we will be adding another event handler that handles our ‘warm’ event. That one should look like so:
What this code does is it listens for the event called ‘warm’ and then prints it to the ‘console’ that is the console in your browser(F12) and it is useful for error checking, you can delete the line, it is not essential.
The document.getElementByID instruction then inserts the data that was sent with the event into an HTML ‘element’ that has an id that is also called ‘warm’ (you may give that another name if you wish).

Adapting the HTML code
The icon is called in the body of the webpage with the following code:
<i class="fas fa-thermometer-half" style=color:#059e8a;"></i>"

(picture shows it as well)
The ‘i’ element that is used here is the html code for ‘italics’, but it is often used as an element in which to define icons as well.

As we are using the  document.getElementByID instruction all we need to do is to use an identifier (called “warm”) for the piece of text we want to replace.
We do that by putting ‘<span id="warm"> <span> around the section we want to replace, like this:
But remember to keep the surrounding code on that line intact, like this
Here you will find a complete code that also has a card added for the voltage and has dynamic icons for temperature, Atmospheric Pressure and Voltage. It has a static IP.

Soil moisture sensors: problems & solutions

Soil moisture sensors are popular among hobbyists who e.g. want to monitor or automatically irrigate their plants.

There are a number of cheap sensors available in the various ‘Chinese webshops’ but those come with a caveat. I will discuss a few and come with ‘solutions’ to some of the biggest problems.

The above sensor is very popular, but in short: it is shit. It is a resistive soil moisture sensor and those come with a big problem: electrolysis. The fact that there is a constant current flowing through the sensor when it is in contact with wet soil will lead to electrolytic breakdown of the very thin layer on the sensor’s PCB, or in other words: after a relatively short period the metal will no longer be on your sensor, but in your soil.

Another issue with this module is that people use the entire module even when that is not necessary. Let me explain with help of a picture:

Soil moisture sensor module

The image shows the circuit used in the module. It is basically a comparator that when the soil moisture (and thus the resistance) reaches a value that is set with the variable resistor, the output of the comparator (DO) toggles. So far so good. The analog output (AO) on the other hand is directly connected to the sensor. That means that if you only use the Analog Output, you do not need the module at all, just connecting the sensor to an analog input and use an internal or external pullup will suffice.
I suggest you do not use this sensor at all.

Soil moisture sensor

The above sensor is more of the same. It is also a resistive sensor and thus has the same problems as the one above. It does not have a digital output, just an analog. Also, because of the exposed electronics on it, it is not really suitable for outside use. I suggest you do not buy this one.

Soil sensor (supposedly protected)

The above sensor supposedly is made from a non-electrolytic sensitive material. It is suggested it is made of carbon. My experience with it is not long enough to say if that is true, but it seems to be fake in that aspect. However, it is definitely useable in combination with some solutions i will suggest later.

Capacitive soilsensor

The above sensor is a capacitive sensor. That means it does not measure the resistance of the soil but the capacitance of the soil. That means that there is no need to have any bare metal sticking in the soil and therefore electrolysis is not a problem. It has some other issues though: The coating that is used to cover the plates of the ‘capacitor’ sadly does not cover the sides of the PCB. Therefore moisture will eventually leak in and basically turn the capacitor into a resistor that will rot away. Also because of the exposed electronics at the top it is not really suitable to use outside. If you want to use this sensor it would be a good idea to dip or spray it completely into/with PlastiDipR.

Sadly there are some issues with this sensor:

  1. Some sensors do not use a TLC555 but an NE555. The latter is not working properly with 3v3 which means you have to remove the voltage regulator.
  2. The 1Mohm resistor (called R4 on the pcb) is not connected to ground on some boards, leading to very slow readings. As this seems to be a problem in the boards design it is easiest solved by soldering a 1Mohm resistor over the Aout and Ground pins.

Realise that capacitive sensors measure other values than resistive soil sensors. A capacitive sensor measures true water content of the soil whereas a resistive sensor in fact measures ion/salt content in the soil, so adding say fertilizer to your soil will change the reading of your resistive sensor but not your capacitive sensor. As such capacitive sensors are better than resistive sensors, but it can be a pain to make sure they are completely watertight. In my experience the often used nailpolish will dissolve over time as does laquer. The before mentioned PlastiDipis a good solution, but adds to the cost of the sensor. The resistive sensor is just much easier.

So what can we do to protect the resistive sensor against electrolysis?
You will read various ‘solutions’ for this:
“You have to feed it with AC”
Yeah, right.Let alone that most of the circuits to do that do not provide AC but just a DC Sinewave or some other form of pulsed DC which does not help at all
“You have to reverse the voltage”
Okay….. apart from the fact that this requires an extra pin, it also takes a lot of time sensitive programming.

There are better solutions:
Use decent galvanized bolts/nails of say 6mm thick and don’t give a fuck. After the growing season take them out, give them a scrub and use again. They will last pretty long.

Only apply a voltage and thus a current to your sensor when you need it.
You really do not need to know the moisture content of your soil every second of the day. Suppose you measure only 4-6 times a day and every measurement takes say 1 mSec. Then you only need to apply a voltage for 4-6mSec a day. That is a lot less electrolysis.
You can do this by feeding the voltage divider that makes up your sensor and pull up resistor simply from an extra pin of your microcontroller and set up a timer to drive that pin HIGH, read the value and drive the pin LOW once every 4-6 hrs. If you do not cherish the idea to use an I/O pin to feed a sensor, the circuits below will do the same. Obviously one should not set an internal pull up resistor when using this option.

soilmoisture sensor,High side switching with PNP transistor
Soilmoisture sensor,Low side switching with FET

There are purists that say you would still need to reverse the voltage for those 4-6 msecs as well, but come on.

The easiest though is to do away with metal alltogether and to use graphite rods. These are current conducting and not subjected to electrolysis or regular corrosis.
It is of course not possible to solder wires to graphite but wires can easily be attached with some heat shrink. The rods as shown here have a combined resistance of approx 10k.

A simple sensor with graphite rods

I2C address conflicts

I2C is a handy protocol to control plenty of chips/sensors/actuators with only 2 pins. With 128 adresses available you would think you are not going to run into an address conflict, meaning you want to use 2 modules that have the same I2C address, but you’d be surprised. Many I2C modules can in fact be set for another address, usually through some address jumpers, but that is not always possible. Even when the chip itself has a possibility to select more than one I2C address, the module does not always implement that (Various PCF8591 modules for instance)
The Adafruit I2C address list shows the I2C addresses of many modules.

The Arduino does have one hardware I2C port, except for the Arduino Due, that has 2.

So what can we do to use 2 or more I2C modules that share 0ne address?
The only solution is to create multiple I2C busses.
This can be done in 2 ways:

Software
The Wire Library that comes with the Arduino IDE only allows you to use the pins on the Arduino that are meant for I2C:

Board I2C / TWI pins
Uno, Ethernet A4 (SDA), A5 (SCL)
Mega2560 20 (SDA), 21 (SCL)
Leonardo 2 (SDA), 3 (SCL)
Due 20 (SDA), 21 (SCL), SDA1, SCL1

The Wire library doesn’t cater for multiple I2C busses, you can only call one instance of it.

So you will need a library that does allow multiple I2C objects. The following libraries do that.

SoftI2CMaster is a lean I2C implementation.

SoftWire allows any pins of the Arduino to be used. It needs another library called AsyncDelay.

Software_I2C on GitHub might be akin to this one from Seeedstudio, but I did not make a full comparison.
Some more multiple bus Software I2C libraries can be found here.

Using those software libraries is a quick and easy way to set up multiple I2C busses, but there is one major drawback. That is the fact that many existing libraries for I2C peripherals make direct calls to the “Wire” library. These would need some modification to make them work with another I2C library.

Hardware.
Instead of a software solution, it is also possible to use an I2C port expander. The TCA9548A is such an expander. It connects to the existing I2C port and then can be made to send commands to 1 of 8 different I2C ports.

The TCA9548A has its own I2C address of 0x70, which can be changed using three pins. This allows you to have up to eight of these modules in your design, adding a total of 64 extra I2C buses that of course each can address some 128 device

The TCA9548A operates on a range of 3 to 5.5 volts, making it suitable for say ‘old’ Arduino 5 Volt logic as well as the new 3V3 logic.

Its use is quite simple: One only needs to write the required bus nr (0-7) to the Chips address (0x70 by default).
It is easiest do to this in a routine:

void TCA9548A(uint8_t bus)
{
  Wire.beginTransmission(0x70);  // default TCA9548A address
  Wire.write(1 << bus);          // select bus
  Wire.endTransmission();
}

a program thus could look as follows:

void setup()
{
TCA9548A(0);
setup your device connected to bus 0
TCA9548A(1);
setup your device connected to bus 1
}
void loop()
{
TCA9548A(0);
write to (or read from) device connected to bus 0
TCA9548A(1);
write to (or read from) device connected to bus 1
}
void TCA9548A(uint8_t bus)
{
 Wire.beginTransmission(0x70);
 Wire.write(1 << bus);
 Wire.endTransmission();
}

As said, the default address of the TCA9548A is 0x70, but can be changed over the range 0x70-0x77. Make sure that you have no other chip on the chosen address as commands to that chip could be seen as commands to the I2C expander.
Chips in that range are:

  • HT16K33 LED Matrix Driver (0x70 – 0x77)
  • PCT2075 Temperature Sensor (0x28-0x2E, 0x48-0x4F, 0x70-0x77)

So make sure you choose another address for them than the addresss you put the Expander (0x70-0x77) on.

 

 

Modifying the Cam32 Webserver HTML file

The standard webserver for the CAM32 module comes with a hoist of options.
If you want to modify that webserver e.g. add a button for the flash or whatever, you need to alter the webserver’s  HTML page.
That however is not as straightforward as it may seem.
Where is that HTML page??

Well, if you look in the ArduinoIDE after loading the example file, there is one file, called ‘camera_index’  and when you open it up,you will see an array called “index_html_gz”. That is the index file…but it is encoded.
So before one can work on it, it needs to be decoded back to html code.
That is not impossible, as there is a site that can do that for us. It is Cyberchef.

If you follow the above link, Cyberchef will open with the proper decode ‘Recipe’ set. You only need to paste in your code (from the array).
In the output window you will see the decoded html file that can be saved.
For efficacy I already did that for you and you can find the decoded html file here.

After you made the desired changes, you need to encode the html page again and that can be done by cyberchef as well. When you click this link, it should give you the proper settings. Only need to use your HTML as input. Then copy the output without the first comma, and use that to replace the content of the “index_html_gz”  array in your camera_index file.

Now I was going to add a flashbutton, but apparently that has been done already. You will also find a pretty decent one right here.
You may also find a randomnerds article about various ESP32cam settings useful.

The Pinout of the ESP32Cam is as follows:
esp32camPins

These pins are internally connected to the Micro SD card reader:

  • GPIO 14: CLK
  • GPIO 15: CMD
  • GPIO 2: Data 0
  • GPIO 4: Data 1 (also connected to the on-board LED)
  • GPIO 12: Data 2
  • GPIO 13: Data 3

Very Deep Sleep and energy saving on ESP8266 – Part 5: ESP-NOW and WiFi

In the previous 4 articles on deepsleep and energy saving, I mainly focussed on establishing a WiFi connection to send data.

Part 1 General – DeepSleep
Part 2 Http requests – DeepSleep
Part 3 MQTT publish – DeepSleep
Part 4 MQTT subscribe – DeepSleep

There are other ways to send data though that cost less time and therefore less energy than establishing a WiFi connection. One of those ways is to use ESP-NOW. ESP-NOW is a kind of connectionless Wi-Fi communication protocol that is defined by Espressif. In ESP-NOW, application data is encapsulated in a vendor-specific action frame and then transmitted from one Wi-Fi device to another without connection.
The big gain in using ESP-NOW is that the ESP8266 (or ESP32 for that matter) does not need to make connection with a router, but it sends data immediately to another designated ESP, which makes the process much faster. That is also one of the drawbacks: you need an extra ESP8266 (or ESP32). That extra ESP can receive data from 20 other ESP’s.
Another drawback is that the receiving ESP is ‘isolated’. Sure you can add an LCD to read the data, but it would be handier if the received data would be available on a network, for Home Assistant or openHAB being able to do something with it, or to store it in a database.
ESP-NOW works fairly straightforward on the ESP32 and a very good “How To” can be found on randomnerdtutorials.

It is perfectly well possible though to also use it on an ESP8266 and that is what I will be doing here. I am certainly no pioneer in this. Anthony Elder in fact already published code using ESP-NOW to transfer BME280 data and go to sleep in between, and also “The guy with the Swiss accent’ did, as did some others, but usually based on Anthony’s code.
Anthony’s sketches though do not have the receiving ESP connect to a network as well, but it can be done, albeit in a bit unorthodox way. Wim3D on instructables however follows an interesting concept as well as he has the sending ESP8266 connect to MQTT if the ESP-NOW transfer goes faulty. Sample code can be found here too (pdf),

So what I will do here is:
1 use one ESP8266 to read a sensor like the BME280 and send the data via ESP-NOW, keeping the ESP in deepsleep in between.
2 use another ESP8266 to receive the incoming data and eventually send that via an http request or MQTT to the network

1 The Sender
There is plenty of information on the Web so there is no real need to reinvent the wheel. I used a sketch from Anthony Elder, that I adapted for my needs. It can be found here. Although this sketch does not have all the energy savings that can be made as shown in my parts 1-4, it is a good begin to test the ESP-NOW datatransfer.

We can see that the transfer only takes a tadd less than 300ms and part of that is not even the active connection. By removing the print statements it is possible to shave off another 40-50msec. So can we win some more energy savings here. Let’s see. It turns out that that the biggest time saver we can implement is to add WiFi.persistent( false ); right at the beginning of the Setup(). Once we do that we go from 300msec to 87msec.

That addition is now already in the sendfile I linked to earlier. When you decide to take out the Serial.print statements, do not remove the Serial.println(bme280.begin(), HEX); statement as that one initializs the BME280. You could ofcourse replace that by a simple bme280.begin(); call

2 The receiver-basic
As there is much info already available on the web, there is no need to re-invent the wheel. I adapted a sketch from Anthony Elder to serve my needs and it can be found here. It simply receives the ESPNOW messages and printes them to the serial monitor. Obviously that is still not what we want as we want it to function as either an HTTP or MQTT gateway, but for now it will do to test if we can make the ESPNOW data transfer.

2 The receiver-MQTT
Of course just printing data to the serial monitor is not going to be of much use, so I was looking for a way to make an ESP-NOW to MQTT Gateway. As it happens, ‘Swiss guy’ Andreas Spiess had already done work on that and provided a sketch that I only had to adapt slightly.
As the present ESP-NOW sdk does not support simultaneous use of ESP-NOW and a wifi connection, the WiFi connection to the broker is now started a new when an ESP-NOW message is received. After a WiFi channel is used, the ESP-NOW protocol can only start when the same WiFi channel is used. As this comes with some limitations I for now have solved it by testarting the sketch every time an MQTT message is published.  Possibly there is another way that I have not tried yet and that is to define the receiver both as AP and STA and use different channels for each and use the AP for the ESP-NOW  and the STA for internet connection. Rui Santos from randomnerdtutorials gives an example of this for the ESP32 although that is just to have the receiving ESP32 to serve a webpage as well. Whether it will work for the ESP8266 to be an MQTT or HTTP client I cannot confirm it yet.

That of course is far from ideal and makes the gateway a bit slow, but it should not be a problem with ESP-NOW messages coming in that have a sensible sleeping period in between. Whether this reset is still necessary with the new sdk I need to check (when I have time)

3 The receiver HTTP
If you prefer an HTTP connection to upload the data to an SQL server (or Thinkspeak), that of course is possible as well. This sketch sends MQTT as well as HTTP.

4 Miscellaneous
There are a couple of functions important/needed to set up the ESP-NOW sender.
Of course we begin with calling the necessary library espnow.h.
Then we set up a data structure that we will send.
We initialize the protocol with esp_now_init().
We define the role with esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
We define the peer (slave) that we will be sending to with esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
and then we register the callback with esp_now_register_send_cb([](uint8_t* mac, uint8_t sendStatus). The callback function returns whether the delivery was successful or not.
We finally send the data with esp_now_send(NULL, bs, sizeof(sensorData)); NULL means send to all peers (thats to say the ones we added)

The code for the ESP8266 starts with a bit of an awkward instruction:

extern "C" {
#include <espnow.h>
}

that is basically to instruct the compiler to expect C code rather than C++ code
Sendercode.
ReceiveESPNOW and send through MQTT/HTTP code.

stk500_getsync() attempt 1 of 10: not in sync: resp=0x7c

There may be many reasons why you may get an stk500_getsync() error when uploading code to an arduino, but the 0x7c error is a bit rare.
There might be various reasons for it, but when I recently got it on a “new” arduino nano, fresh from China, I could see that the Blink program that it came with worked, so I knew  that the processor was working.
Ofcourse I tried another cable, eventhough a faulty cable usually gives another return code. Yes, it came with a CH340 chip, but that never caused a problem before.
So i tried:
Tools-Processor-Atmega328 (Old Bootloader)
That worked immediately

Very deep sleep – part 4, subscribing to MQTT messages

In a previous article, I presented a deepsleep program for the ESP8266 that would publish mqtt messages when it woke up from deepsleep.

In that article I wrote that receiving MQTT messages in a deepsleep-wake cycle is possible, but that it came with some issues of its own.  In the present article lets what we need to do to receive MQTT messsages while on a deepsleep wake cycle.

First however ask yourselves if it is really a good idea to incorporate receiving MQTT messages in a deepsleep project: It will cost time and whatever you plan to regulate via MQTT will be practically null and void when the ESP goes into deepsleep.
The only reason I can come up with is  using MQTT to instruct the ESP to not go to deepsleep yet, but do a firmware update first.

Anyway, here we go. There are two hurdles to overcome:

  1. When did broker send the MQTT message?
    If your program sleeps for 3 hrs and the broker sent a message 2 hrs earlier, we need to make sure it is still there when the ESP8266 wakes up. Therefore we need to retain or persist the messages coming from the broker. Remember that when you retain a message, the broker will keep offering it on every wake up.
  2. How long do we need to wait for the messages to come in and how many messages are expected?
    Normally it is the ‘client.loop‘ instruction in void loop(){} that will gather the incoming messages, but with deepsleep we never get to the void loop(). But if we put the client.loop instruction in the setup, then it will run only once, which will likely not be enough to receive and process any incoming MQTT messages. So we need to build our own ‘loop’ in the setup.
    That loop should last long enough to process incoming messages, but still as short as possible to save battery-life.The most efficient way is to set a flag holding up the deepsleep and clear that flag when a message is received. But that means if no message received, the ESP does not go to sleep, so that’s not really an option (it can work with retained messages). That means we have to do it differently. Will get to that later.

We will make a simple MQTT command to light the LED on a Wemos board. In the verydeepsleepMQTT.ino from the previous article, go to void reconnect, find:

client.publish("home/sleep/stat/connection", "OK");

and add right under that, the following line:

client.subscribe("home/sleep/cmd/led");

Then, at the end of the program, add the following routine

void callback(char* topic, byte* payload, unsigned int length) {

Serial.print("Message arrived in topic: ");
Serial.println(topic);

Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
digitalWrite(ledPin,LOW);
}

In the program find the line:

//client.setCallback(callback);

and uncomment that

In the declaration section of the program, add the instruction:

ledPin=3

find the section ‘//Go do stuff’ and add:

pinMode(ledPin, OUTPUT); // initialize digital ledPin as an output.

then go to the setup() and find the line:

sendMQTTmessage();

and add right under that:

if (!client.connected()) {
reconnect();
}
for(int i=0;i<10; i++)
{
client.loop(); //Ensure we've sent & received everything
delay(100);
}

This adds 1 sec to our wake time. You could try with less, depending on speed of yr connection and the amount of messages you expect.

Now add an LED with 560 ohm-1k seriesresistor between 3.3V and the ‘ledPin’ and send the MQTT message “home/sleep/cmd/led” with payload “ON”. The next time the ESP8266 wakes up, the LED will light up for a short time and the serial monitor -if connected- will show the message that was received.

To be fair……. this program will react to any payload, whether it is ON or OFF or anything else, as  I do not check for that, but you can easily do that yourself. My goal was just to show how to receive MQTT messages.
Also, in the loop I created, I use short (100ms) delays. I do that because it is easy to follow. In real life though it is better to avoid delays.

Full code download here. Beware. The sensor and ledPin are slightly different in that program.

Part 1 General – DeepSleep
Part 2 Http requests – DeepSleep
Part 3 MQTT publish – DeepSleep
Part 4 MQTT subscribe – DeepSleep
Part 5 ESP-NOW -DeepSleep

Very Deep Sleep and energy saving on ESP8266 – Part 3: MQTT

In part 1 and 2 of this series, I sketched how to be very energy efficient when using a battery (part 1) and how to periodically gather sensor data and send that to a server through http (part 2).

In this part 3 I will show how to use an energy thrifty ESP8266 sketch to send sensor data via MQTT.

Again I am using the sketch from part 1, that has a section for ‘read data’ or ‘do stuff’  and a section for ‘send data’ and  I just insert the necessary code.

All in all it is quite straight forward. This time I will not be using a BME280 sensor, but that good old DHT11.
As usual, you have to insert your own wifi credentials, and in this case also the ip number and port of your MQTT broker.

I laced the sketch with print statement that should help you in case of problems, but once you have the sketch up and running you can remove those.

There is a possibility for a bit more enerdy saving:
I use the following 2 statements to read and send the sensor data:

client.publish("home/sleep/stat/temp",String(dht.readTemperature()).c_str(),false);
client.publish("sleep/sleep/stat/humid",String(dht.readHumidity()).c_str(),false);

However, the DHT11 isn’t a really fast sensor and the read is while we are connected to WiFi. You could probably shave off a bit of connection time (and thus current) by reading the sensors in the ‘do stuff’ section, store them each into a global variable and use those variables in your MQTT publish.
Do that as follows:

//global
float t;
float h;

//do stuff
t=dht.readTemperature();
h=dht.readHumidity();

//when connected
client.publish("home/sleep/stat/temp",String(t).c_str(),false); client.publish("sleep/sleep/stat/humid",String(h).c_str(),false);

This would also allow you to check for false readings with

if(isnan(h)||isnan(t));

and take corrective action. But that is not really the subject of this HowTo. Don’t forget a 5.1k pull-up resistor. As the DHT11 draws about 0.5mA, you could decide to feed it from one of the gpio pins and just switch it on when needed. (0.5mA comes to 12mAh over a day). However, also take into account that the DHT11 may need a bit of time to get ready.

Also, this sketch only publishes MQTT messages, it does not subscribe to any messages. DeepSleep and receiving subscribed MQTT messages comes with its own set of problems, but it is not impossible. Perhaps that I will write about that in the future.

You will find the link to this program here.

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

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