Sending mail with an ESP8266

Sending mail with an ESP8266 can be handy for a variety of things. I use it to occasionally have a remote ESP8266 send me a message it is still ok and functioning.
Though it is possible to have the ESP8266 directly access your mail server and send a message through that, that is usually not a good idea as many mailservers will refuse mail that is being sent from a different domain (your ip) than the mailserver’s.
it is therefore safer to use a service like smtp2go.com. As long as you stay below a certain limit of emails, one can get a free account.

After signing up  for smtp2go, you will need to choose a user id and password for your smtp log in. You thus have two sets of id and password: one for your user account and one for the mails you send.
The latter, you need to encode in base 64 to use  from your ESP8266. You can do that with an online encoder.
As there is no need to re-invent the wheel, I used this program as a basis and reworked that to my needs, but as your needs might be different from mine, I will just give a general example.
In order to send something more useful than ‘Hello World’, we are going to send the supply voltage and the chip ID. In real life I do not send the suply voltage as that is not so useful, but I send the battery voltage. But to keep it simple in this example we will stick to the supply voltage, which we get with ESP.getVcc().
The program is like this: (NOTE: the code might be badly formatted by wordpress, make sure you copy it completely)

#include <ESP8266WiFi.h>  // the ESP8266WiFi.h  lib
const char* SSID = "YourSSID";
const char* PASS = "YourPW";
char server[] = "mail.smtpcorp.com";
ADC_MODE(ADC_VCC);

WiFiClient client;
void setup()
{
  Serial.begin(115200);
  delay(10);
  Serial.println("");
  Serial.println("");
  Serial.print("Connecting To ");
  Serial.println(SSID);
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  byte ret = sendEmail();
}

void loop()
{
}

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  if (client.connect(server, 2525) == 1) {
    Serial.println(F("connected"));
  } else {
    Serial.println(F("connection failed"));
    return 0;
  }
  if (!eRcv()) return 0;

  Serial.println(F("Sending EHLO"));
  client.println("EHLO www.example.com");
  if (!eRcv()) return 0;
  Serial.println(F("Sending auth login"));
  client.println("auth login");
  if (!eRcv()) return 0;
  Serial.println(F("Sending User"));
  // Change to your base64, ASCII encoded user
  client.println("ZV83MTAwMEBnbWFljC5jb31="); // SMTP UserID
  if (!eRcv()) return 0;
  Serial.println(F("Sending Password"));
  // change to your base64, ASCII encoded password
  client.println("X5pqVU9vYlJjY7Bq");//  SMTP Passw
     if (!eRcv()) return 0;
    Serial.println(F("Sending From"));   // change to your email address (sender)
   client.println(F("MAIL From: yrmail@gmail.com"));// not important 
   if (!eRcv()) return 0;   // change to recipient address
    Serial.println(F("Sending To"));
    client.println(F("RCPT To: receiver@gmail.com"));
    if (!eRcv()) return 0;
    Serial.println(F("Sending DATA"));
    client.println(F("DATA"));
    if (!eRcv()) return 0;
    Serial.println(F("Sending email"));   // change to recipient address
   client.println(F("To: receiver@gmail.com"));   // change to your address
   client.println(F("From: sender@gmail.com"));
 client.println(F("Subject: Emails from ESp8266\r\n"));
    client.print(F("Power is: "));
    client.print(ESP.getVcc());
    client.println(F("mV"));
    client.print(F("Device Chip ID: "));
    client.println(ESP.getChipId());
    Serial.print(F("Voltage is: "));
    Serial.print(ESP.getVcc());
    client.println(F("."));
    if (!eRcv()) return 0;
    Serial.println(F("Sending QUIT"));
    client.println(F("QUIT"));
    if (!eRcv()) return 0;
    client.stop();
    Serial.println(F("disconnected"));
    return 1;
  }
  byte eRcv()
  {
    byte respCode;
    byte thisByte;
    int loopCount = 0;
    while (!client.available())
  {
      delay(1);
      loopCount++;     // if nothing received for 10 seconds, timeout
      if (loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return 0;
    }
  }

  respCode = client.peek();
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }

  if (respCode >= '4')
  {
    //  efail();
    return 0;
  }
  return 1;
}

In the example I use “gmail” but ofcourse this can be any other mailservice>
In the program you will also see a line with “yrmail@gmail.com"));// not important“. I may be wrong but it is not that important what that says. It is the identity under which your mails are grouped in the smpt2go dashboard. Maybe it is easiest to make that equal to the sender address, but it isnot important for the functioning of the program.

The strings that are send are rather flexible. Instead of
client.println(F("Subject: Emails from ESp8266\r\n"));
On can also do:
client.print(F("Subject: "));
if (condition == met)
client.println(F(PREDEFINED_MESSAGE));

Monitoring LiPo battery voltage with Wemos D1 minibattery shield and Thingspeak

There are a million reasons why you would want to monitor the Battery voltage of  your Battery fed ESP8266. I will illustrate it with a Wemos D1 mini and the Battery shield

batteryshield
Wemos D1 Mini Battery shield

I am using a small 720 mAh LiPo cel. If I just leave the Wemos access the internet continuously it will last 6.5 hours, but for this example I will put the Wemos in Deepsleep for a minute, then read the battery voltage and upload that to Thingspeak.
You only need to make a few connections:
First, connect RST with GPIO16 (that is D0 on the Wemos D1 mini). This is needed to let the chip awake from sleep.
Then connect the Vbat  through a 100k resistor to A0.

So why a 100 k resistor?

Well the Wemos D1 mini already has an internal voltage divider  that connects the A0 pin to the ADC of the ESP8266 chip. This is a 220 k resistor over a 100 k resistor

Wemos D1 Internal Voltage divider
Wemos D1 Internal Voltage divider

By adding a 100k , it will in fact be a total resistance  of 100k+220k+100k=420k.
So if the Voltage of a fully loaded Cell would be 4.2 Volt, the ADC of the ESP8266 would get 4.2 * 100/420= 1 Volt

1 Volt is the max input to the ADC and will give a Raw reading of 1023.

The True voltage  then can be calculated by:
raw = AnalogRead(A0);voltage =raw/1023;
voltage =4.2*voltage;
Ofcourse you could also do that in one step, but I like to keep it easy to follow.

Wemos Battery monitoring
Wemos Battery monitoring

If you do use this possibility, do realise that the resistors drain the battery as well with a constant 10uA (4.2V/420 000ohm). The powerconsumption of an ESP8266 in deepsleep is about 77uA. With the battery monitor this would be 87uA, which is a sizeable increase. A solution could be to close off the Vbat to the A0 with a transistor, controlled from an ESP8266 pin

A program could look like this:

 

/*
 * Wemos battery shield, measure Vbat
 * add 100k between Vbat and ADC
 * Voltage divider of 100k+220k over 100k
 * gives 100/420k
 * ergo 4.2V -> 1Volt
 * Max input on A0=1Volt ->1023
 * 4.2*(Raw/1023)=Vbat
 */

// Connect RST en gpio16 (RST and D0 on Wemos)
#include <ESP8266WiFi.h>
unsigned int raw=0;
float volt=0.0;
// Time to sleep (in seconds):
const int sleepTimeS = 60;

void setup() {
  Serial.begin(115200);
  Serial.println("ESP8266 in normal mode");
  const char* ssid     = "YourSSID";
  const char* password = "YourPW";
  const char* host = "api.thingspeak.com";
  const char* writeAPIKey="YourAPIkey";
  // put your setup code here, to run once:
  pinMode(A0, INPUT);
  raw = analogRead(A0);
  volt=raw/1023.0;
  volt=volt*4.2;
//  Connect to WiFi network
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  }
  String v=String(volt);// change float into string
  // make TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    return;
  }
  String url = "/update?key=";
  url += writeAPIKey;
  url += "&field6=";// I had field 6 still free that's why
  url += String(volt);
  url += "\r\n";
 
// Send request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "Connection: close\r\n\r\n");

 //Sleep
   Serial.println("ESP8266 in sleep mode");
   ESP.deepSleep(sleepTimeS * 1000000);              
}

void loop() {
  //all code is in the Setup
}

So your touch sensor is not working?

sensorWe have all experienced it, you buy something at Aliexpress. It arrives and you confirm receipt before you have time to test everything and then when you finally get around to that… there is a problem.
That happened to me with a TTP223B capacitive touch sensor. Whatever I tried, the output remained low. Slightly frustrated I was looking at the rather simple board and thought that there really couldn’t be much wrong with it.
ttp223-icFound a datasheet of the TTP223B ic that is on this module and started measuring. Well to make a long story short, the input pin (pin 3) seemed to have no connection with the sensorplate. When I would just touch the input pin, it switched very well. According to an application note in the datasheet capacitor C1 should be between  the input and  the ground and as it should be connected it also should be connected to the  sensorplate, which in fact it was. Turns out pin 3 was not connected to anything. A small wire that I soldered between the top of C1 and  pin 3 remedied everything and after that the sensor worked wonder well.
On checking the feedback of people who ordered this sensor, I noticed many experienced the same problem. No doubt the manufacturer (not perse the seller) must have known about this.

ttp233

Update two channels (different API’s) in Thingspeak

Uploading to two different channels in Thingspeak is fairly easy and can be done with the code below.
The code does close connection in between the uploads, perhaps that isnt necessary but I had some trouble getting it to work without closing the connection,not saying it cant be done

void  sendDataToThingspeak(void)
{

// make TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(thingspeakServer, httpPort)) {
    return;
  }

  String url = "/update?key=";
  url += writeAPIKey;
  url += "&field1=";
  url += String(humidity);//
  url += "&field2=";
  url += String(humiditySetPoint );//
  url += "&field3=";
  url += String(humidifier);
  url += "&field4=";
  url += String(autoMode); //
  url += "&field5=";
  url += String(t);
  url += "\r\n";

  // Send request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
               
  // Second channel            

//-------- Make new connection
 if (!client.connect(thingspeakServer, httpPort)) {
    return;
  }
  url = "/update?key=";
  url += writeAPIKey2;
  url += "&field1=";
  url += String(value1);// 
  url += "&field2=";
  url += String(value2 );// 
  url += "\r\n";
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
 Serial.println("Thingspeak");
}

Connect ESP8266 with Thingspeak through LUA: Analog pin and Internal ReferenceVoltage

esp8266-thingspeakluaConnecting your ESP to Thingspeak with a program written in your Arduino IDE is quite easy and those programs come a dime a dozen.
However, when I went to look for a program that did the same in LUA I came a cross a number of programs that simply didn’t work.
So I had to give it a go myself.
The below program is more or less a skeleton for thingspeak connection. It reads two values and posts those on Thingspeak. As it was just for testing I didnt want to add a lot of sensors, so th eonly two values read are the Internal reference voltage and the analog value from ADC0.
To make the program easily adaptable, I readthe sensors in a seperate function.
If you want to add a variable resistor to test the ADC, mind you that it can only take 1 Volt input so you need a voltage divider that limits it to 1 volt instead of 3.3 Volt.
When using the program dont forget your network credentials and  Thingspeak API Key

WRITEKEY="T3I6T9YF67JE527" -- set your thingspeak.com key
wifi.setmode(wifi.STATION)
wifi.sta.config("YourSSID","YourPW")
wifi.sta.connect()
tmr.delay(1000000)
volt=0 --Internal reference voltage
ana=0 -- analog port A0 Mind you, this one has a 1 Volt max

--read sensor
function ReadSensor()
volt = node.readvdd33()
ana=adc.read(0) -- 1V=1023
print("Internal Ref.Voltage: " ..(volt/1000).."."..(volt%1000).." Volt")
print("Analoog: "..ana)
end 

-- send to https://api.thingspeak.com 
function sendTS() 
conn = nil
conn = net.createConnection(net.TCP, 0)
conn:on("receive", function(conn, payload)success = true print(payload)end)
conn:on("connection",
   function(conn, payload)
   print("Connected")
   conn:send('GET /update?key='..WRITEKEY..'&field1='..(volt/1000)..'.'..(volt%1000)..'&field2='..ana..'HTTP/1.1\r\n\
   Host: api.thingspeak.com\r\nAccept: */*\r\nUser-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n\r\n')end)
conn:on("disconnection", function(conn, payload) print('Disconnected') end)
conn:connect(80,'184.106.153.149')
end

ReadSensor()
sendTS()
tmr.alarm(1,6000,1,function()ReadSensor()sendTS()end)

Now I haven’t been completely honest here, as it isnt really good practice to read the internal Voltage and the A0 port as it reads either the one or the other.
When using the  A0 to read internal voltage  in the Arduino IDE rather than in LUA ADC_MODE(ADC_VCC); in combination with ESP.getVcc() is now the correct way to do it. Using readvdd33 causes problems

A quick introduction to LUA on the ESP8266: create an Accespoint and LAN client to switch a lamp

If you have been using an ESP8266 with the Arduino IDE, you will nevertheless have heard about LUA and you may be curious to try it.

The object of this article is not to teach LUA, but rather to quickly show  how to get started.

Though some ESP8266 modules and boards come with the LUA interpreter installed, once you have flashed programs to your ESP8266 with your Arduino IDE, that interpreter is gone. So, first we may need to reflash LUA interpreter back in the ESP8266 again:

Putting LUA (back) on your ESP8266.

flasherGo to github.com/ nodemcu and choose the nodemcu-flasher. Download and unpack it. Connect your ESP8266 to your 3v3 USB TTL converter. Go to the Win32/Release folder and start the ESP8266Flasher.exe. Set your ESP8266 in flash mode in the way that is suitable for the board you are using.

Select the proper com port and click ‘Flash’. When the program is done it will return 2 MAC addresses: one for an Accespoint and the other one or a ‘station’.

Close the flasher and reset the ESP8266.

The ESP8266 is now ready for LUA programming.

Uploading LUA Programs

In order to upload a program to your LUA interpreter/ESP8266, there are several programs. I am using ESPlorer. Download and unpack that program and start it with ‘Esplorer.bat’ .

Presuming your ESP8266 is still connected to your computer, choose the proper Com port and baudrate in the right side pane of the program and click connect. The esp8266 will now likely reprt itself and come back with the message: “no init.lua”.

The ‘init.lua’ file is the file that is executed on boot. If we want our program to start on boot, that is the name we will give it.

As it is not my intention to teach LUA here, we will use an existing program: Go back to the Nodemcu github and choose “nodemcu-firmware”. Then clicl ‘lua-examples’, choose ‘webap_toggle_pin.lua, then  click RAW. Copy the code and go back to the ESPlorer program. Choose the ‘Nodemcu/Micropython’ tab and the Scripts tab and paste the copied program in the leftpane of the ESPlorer program.

Save the program as ‘init.lua’  and then upload it to the ESP (under the File tab).

Once the program is uploaded, reset the ESP8266.

As the program configures an Accespoint, go to the wireless connections on your computer. You should see an accesspoint there called ‘test’ log on to that one. When it asks for a password provide ‘ 12345678’. Once you are logged on, go to ip 192.168.4.1. You should be presented with a webpage that allows you to toggle a pin.

Now that may be handy, as te esp8266 is not connected to the internet it can only be accessed from a limited distance. But what if you want to switch a lamp from the other sidof the world? Well i will show you how to change the accespoint created in an accesspoint and LAN client so you can log into it either directly, or via your router.

You need to configure the first 2 lines as follows:

esplorer8266The firstline is changed into ‘wifi.STATIONAP’ this configures the ESP8266 both as an AP and a LAN client. The next line that configures the AP is left untouched, but the LAN still needs to be configured wih ssid and password as shown in the picture. Upload the altered program to the ESP and reset it. The ESP is now both a direct Accesspoint as well as connected to the internet via your router.

gpioOne more remark: the gpio pins of the ESP8266 are not directly translated to the numbers of the ‘pins’  in the program. If you are not using a Wemos D1 or NodeMCU, but rather an ESP8266-01 and you ant to switch GPIO2, in the program you need to state ‘pin4’

 

Solarpower for ESP8266

wemospsuNeeded a solar powersupply for an ESP8266-01. As the ESP8266-01 needs 3.3 Volt, a LiPo cell seemed a good choice for a battery. However, fully loaded these give 4.2 Volt, which is too much for the ESP8266. In order to get to 3.3Volt a Lowdrop (LDO) regulator is necessary.

As the ESP8266 does require a hefty current when it is transmitting, the regulator needs to be able to give some 500mA.

Possibilities are the SPX3819 (500mA, dropvoltage 340mV, maxinput 20V) (found on the Lolin NodeMCU-ESP12E) and the AP2112 (600mA, dropvoltage 250mV, maxinput 6V, quiescent current 55uA) ( found on the Adafruit Huzzah). As the maxinput will be 4.2Volt, I have chosen the AP2112 (but I in fact recommend the RT9013). The HT7333, that is recommended for e.g. the backside of the ESP8266-12 adapter plate has a drop voltage of 100mV. However, that is measured at 40mA and the datasheet gives no info on the dropvoltage at higher currents. The quiescent current is 3.5mA, so I did not pick that one for battery power.
Other possible options are the RT9013 (That is for instance found on the Wemos D1 mini) and the XC6203. The RT9013 has a 250mV @ 0.5A drop. Quiescent current is 25uA, but only 7uA if the chip is disabled (which is not really an option in this application). The XC6203 has a 150mV @ 100mA and a 300mV@ 200mA drop.

The LiPo battery is being charged by a small TP4056 module. These have a maxinput of 8 Volt, hence a 6 Volt solarpanel will do nicely.

Capacity of the LiPo and the Solarpanel depend on the current needed. If you put the esp8266 to sleep in between transmission it can last long on a battery, especially if it is charged throughout the day.