Introduction: Email Weather Reminder Using XChips and ESP8266

This project measures the temperature and sends you an email to dress warm or cool. Completed in 20min using Xinabox xChips.

Step 1: Things Used in This Project

Hardware components

  • XinaBox SW01 x 1
    xChip Temperature, humidity and atmospheric pressure sensor based on the BME280 from Bosch.
  • XinaBox CW01 x 1
    xChip Wi-Fi Core based on ESP8266 Wi-Fi Module
  • XinaBox XC10 x 4
    xChip BUS Connectors
  • XinaBox IP01 x 1
    xChip USB Programmer based on FT232R From FTDI Limited
  • XinaBox PB04 x 1
    xChip Dual AA Intelligent Battery Power Supply

Software apps and online services

Step 2: Story

Introduction

I built this simple project using XinaBox xChips. The SW01 was used to measure the ambient temperature. If the temperature was between 12°C and 18°C, an email would be sent to indicate the cold weather. If the temperature is between 18°C and 25°C, moderate temperature conditions would be emailed and if the temperature is above 25°C, the email would read hot conditions.

Email Notification reminding you to dress cool.

Step 3: Software Setup

Download the following libraries and add them to the Arduino IDE Libraries. Also download the board and follow the instructions that accompany it.

After installing the board, select the "Generic ESP8266 Module" as shown below and replicate other parameters under Tools. Be sure to select the correct COM port.

ESP8266 Board Selection and Settings

Step 4: Gmail and BASE64 Setup

This project can only be accomplished using Gmail. Set up your gmail account by following this link ESP8266 GMail Sender. Since you are allowing less secure apps, it is advisable to create another Gmail account and not use your personal account. Now, using BASE64, copy and paste your email address into the textbox and press encode. Save the encoded character string somewhere on your computer. Do the same for your password. See the example below.

Example of Encoded email address

Step 5: Build for Programming

Connect your IP01 and CW01 using the XC10 bus connectors as shown below.

Assemble to Program

Insert the combination into an available USB port. Download the code or preferably copy and paste each code in different tabs into one Arduino IDE Window and follow the instructions below.

Step 6: Inputting Your Details

In the 'Temp_Email' tab, scroll to the 'email_details' function and replace "your email" with the email you chose to use. See image below.

Insert your Email address

In the 'Gsender.h' tab, copy and paste your username and password that you encrypted on BASE64 in their respective locations as well as the email address you are sending from. See the image below.

BASE64 Encrypted Login and Password

In the 'Temp_Email' tab, insert your WiFi details. Refer to below image.

Your WiFi Credentials

Now compile and upload the code to your CW01 board. Once uploaded the RGB LED on the CW01 should be green before you remove it.

Step 7: Operation

Remove IP01 from your computer and separate the two xChips. IP01 is no longer needed. Now click SW01 and CW01 together using the XC10 bus connectors as shown below.

ESP8266 and Temperature Sensor

Now connect the power supply (PB04) as shown below.

Final Assembly. SW01 will read the temperature and send you an email based off it.

Flip the switch of the PB04 to the on position and an email will be sent to you based on the temperature. If you're looking for something more permanent, consider the PU01 connected to a fixed USB power supply and keep your project somewhere safe on your porch. This way you'll never forget your jacket at home.

Once powered up, you should receive an email

Step 8: Code

Temp_Email.ino Arduino
Main Program. Insert your WiFi details and recipient address in this code. Open each file in a different tab in your Arduino IDE.

#include <ESP8266WiFi.h>            // include ESP8266 library
#include "Gsender.h"                // include the email library
#include <xCore.h>                  // include core library
#include <xSW01.h>                  // include temperature sensor library<br><br>xSW01 SW01;

// flags to send email once only
bool flag0;
bool flag1;
bool flag2;

// variable containing the temp in celsius
float tempC;

// enter your wifi credentials
const char* WIFI_SSID = "yourwifidetails";        // enter your wifi network name
const char* WIFI_PASS = "yourwifipassword";       // enter you wifi network password


// define RGB LED pin numbers
#define RED 12
#define GREEN 13
#define BLUE 5

void setup() {
  // put your setup code here, to run once:
  // start serial communication
  Serial.begin(115200);

  // set RGB LED pins
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);  pinMode(BLUE, OUTPUT);

  // initialize variables
  flag0 = true;
  flag1 = true;
  flag2 = true;

  // temperature in celcius
  tempC = 0;

  // start the I2C communication
  Wire.begin(2, 14);

  // start the temperature sensor
  SW01.begin();

  // start wifi connection
  WIFI_connect();

    // delay for normalization
    delay(5000);
}

void loop() {
  // put your main code here, to run repeatedly:

  // constantly read temperature
  SW01.poll();

  // retrieve temperature from sensor
  tempC = SW01.getTempC();

  // display the actual temperature on the serial monitor
  Serial.print("Temperature: ");
  Serial.println(tempC);

  // call main program
  temperature();
  }

// establish wifi connection
void WIFI_connect() {
  if (WiFi.status() != WL_CONNECTED) {
    digitalWrite(GREEN, LOW);
    // Connect to WiFi access point.
    Serial.println(); Serial.println();
    Serial.print("Connecting to :");
    Serial.print("[");
    Serial.print(WIFI_SSID);
    Serial.print("]");

    // Start ESP8266 STA mode
    WiFi.begin(WIFI_SSID, WIFI_PASS);

    // check connection status
    while (WiFi.status() != WL_CONNECTED) {
      digitalWrite(RED, HIGH);
      delay(100);
      digitalWrite(RED, LOW);
      delay(100);
      Serial.print(".");
    }
    if (WiFi.status() == WL_CONNECTED) {
      digitalWrite(GREEN, HIGH);
      Serial.println("[CONNECTED]");
    }
  }
}

// categorizes temperature measurement
// add subject and message between double the quotes
void temperature() {

  // cold
  if((tempC >= 12) && (tempC < 18) && (flag0 == true)){
    // send email
    email_details("Cold weather Conditions","It is cold outside. Don't forget a jacket.");
    flag0 = false;
    flag1 = true;
    flag2 = true;
  }

  // moderate
  else if((tempC >= 18) && (tempC < 25) && (flag1 == true)){
    // send email
    email_details("Moderate Weather Conditions","The weather outside is nice. Go for a picnic");
    flag1 = false;    // prevents email from looping
    flag0 = true;
    flag2 = true;
  }

  // hot
  else if((tempC >= 25) && (flag2 == true)){
    // send email
    email_details("Hot Weather Conditions","The weather outside is hot. Dress cool");
    flag2 = false;    // prevents email from looping
    flag0 = true;
    flag1 = true;
  }
  else{
    // do nothing
  }
}

// send email
void email_details(String subject, String message){

    Gsender *gsender = Gsender::Instance();    // Getting pointer to class instance

    // enter the recipient's email address
    if(gsender->Subject(subject)->Send("youremail", message)) {
        Serial.println("Message send.");
    } else {
        Serial.print("Error sending message: ");
        Serial.println(gsender->getError());
    }
}

Gsender.h Arduino
Enter your encoded details here.

#ifndef G_SENDER
#define G_SENDER
#define GS_SERIAL_LOG_1         // Print to Serial only server responce
#include <WiFiClientSecure.h>

class Gsender
{
    protected:
        Gsender();
    private:
        const int SMTP_PORT = 465;
        const char* SMTP_SERVER = "smtp.gmail.com";

        // enter your encrypted details
        const char* EMAILBASE64_LOGIN = "encoded email address";
        const char* EMAILBASE64_PASSWORD = "encoded password";

        const char* FROM = "your email address";
        const char* _error = nullptr;
        char* _subject = nullptr;
        String _serverResponce;
        static Gsender* _instance;
        bool AwaitSMTPResponse(WiFiClientSecure &client, const String &resp = "", uint16_t timeOut = 10000);

    public:
        static Gsender* Instance();
        Gsender* Subject(const char* subject);
        Gsender* Subject(const String &subject);
        bool Send(const String &to, const String &message);
        String getLastResponce();
        const char* getError();
};
#endif // G_SENDER

Gsender.cpp Arduino
Leave as is.

 #include "Gsender.h"
Gsender* Gsender::_instance = 0;
Gsender::Gsender(){}
Gsender* Gsender::Instance()
{
    if (_instance == 0)
        _instance = new Gsender;
    return _instance;
}

Gsender* Gsender::Subject(const char* subject)
{
  delete [] _subject;
  _subject = new char[strlen(subject)+1];
  strcpy(_subject, subject);
  return _instance;
}
Gsender* Gsender::Subject(const String &subject)
{
  return Subject(subject.c_str());
}

bool Gsender::AwaitSMTPResponse(WiFiClientSecure &client, const String &resp, uint16_t timeOut)
{
  uint32_t ts = millis();
  while (!client.available())
  {
    if(millis() > (ts + timeOut)) {
      _error = "SMTP Response TIMEOUT!";
      return false;
    }
  }
  _serverResponce = client.readStringUntil('\n');
#if defined(GS_SERIAL_LOG_1) || defined(GS_SERIAL_LOG_2)
  Serial.println(_serverResponce);
#endif
  if (resp && _serverResponce.indexOf(resp) == -1) return false;
  return true;
}

String Gsender::getLastResponce()
{
  return _serverResponce;
}

const char* Gsender::getError()
{
  return _error;
}

bool Gsender::Send(const String &to, const String &message)
{
  WiFiClientSecure client;
#if defined(GS_SERIAL_LOG_2)
  Serial.print("Connecting to :");
  Serial.println(SMTP_SERVER);
#endif
  if(!client.connect(SMTP_SERVER, SMTP_PORT)) {
    _error = "Could not connect to mail server";
    return false;
  }
  if(!AwaitSMTPResponse(client, "220")) {
    _error = "Connection Error";
    return false;
  }

#if defined(GS_SERIAL_LOG_2)
  Serial.println("HELO friend:");
#endif
  client.println("HELO friend");
  if(!AwaitSMTPResponse(client, "250")){
    _error = "identification error";
    return false;
  }

#if defined(GS_SERIAL_LOG_2)
  Serial.println("AUTH LOGIN:");
#endif
  client.println("AUTH LOGIN");
  AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2)
  Serial.println("EMAILBASE64_LOGIN:");
#endif
  client.println(EMAILBASE64_LOGIN);
  AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2)
  Serial.println("EMAILBASE64_PASSWORD:");
#endif
  client.println(EMAILBASE64_PASSWORD);
  if (!AwaitSMTPResponse(client, "235")) {
    _error = "SMTP AUTH error";
    return false;
  }

  String mailFrom = "MAIL FROM: <" + String(FROM) + '>';
#if defined(GS_SERIAL_LOG_2)
  Serial.println(mailFrom);
#endif
  client.println(mailFrom);
  AwaitSMTPResponse(client);

  String rcpt = "RCPT TO: <" + to + '>';
#if defined(GS_SERIAL_LOG_2)
  Serial.println(rcpt);
#endif
  client.println(rcpt);
  AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2)
  Serial.println("DATA:");
#endif
  client.println("DATA");
  if(!AwaitSMTPResponse(client, "354")) {
    _error = "SMTP DATA error";
    return false;
  }

  client.println("From: <" + String(FROM) + '>');
  client.println("To: <" + to + '>');

  client.print("Subject: ");
  client.println(_subject);

  client.println("Mime-Version: 1.0");
  client.println("Content-Type: text/html; charset=\"UTF-8\"");
  client.println("Content-Transfer-Encoding: 7bit");
  client.println();
  String body = "" + message + "";
  client.println(body);
  client.println(".");
  if (!AwaitSMTPResponse(client, "250")) {
    _error = "Sending message error";
    return false;
  }
  client.println("QUIT");
  if (!AwaitSMTPResponse(client, "221")) {
    _error = "SMTP QUIT error";
    return false;
  }
  return true;
}