Using an ESP8266 as a time source (Part 1)

So i’ve obtained some ESP8266 WiFi modules lately and have been having a play with them. If you’ve not heard of the ESP8266 they are tiny serial controlled WiFi modules that are about £5 each and enable an easy and cheap method of connecting an electronics project to your home network or the internet. They also have an onboard chip (SoC) that can be accessed and programmed although i’ve not gone that far and have simply used the serial interface so far.

ESP8266

The reason I got one was to try and obtain an accurate time signal from the internet using NTP or some other method. I had built a digital clock circuit with a 4 digit 7-segment display and was trying to find ways of ensuring the time was always accurate. I tried out several DCF and MSF time receiver units and found that on their own they were able to successfully receive a time signal, once added to the rest of the circuit they were hyper-sensitive to the tiniest bit of electronic noise and failed to sync.

Clock ProjectNext I tried a GPS module. GPS modules return a very accurate time and date in the NMEA string and so they are a great way of obtaining accurate time. However, they need a view of the sky to receive the satellite signals and so indoors usually only work when near a window. This is not much good for my clock project as I don’t want the clock near a window all the time.

So the next idea was to connect to the internet and using NTP or some other method obtain time that way. I have several ethernet shields for my Arduino’s and also have some Arduino Yun’s but this was complete overkill for a clock. I then heard about the ESP8266 WiFi modules and decided to purchase one. AT £4.95 inc. delivery from eBay it was worth the risk.

IMG_20150225_115737Since then i’ve been playing around with the module and learning how to use it. I first had to update the firmware on them which was a pain in the ass and at one point I thought i’d bricked the unit. In the end I was able to update both the firmware and the AT command set and I am now running at version 0020000903_NTP.

The module hooks up to the Arduino via one of the serial ports. I used a Mega 1280 as it has 4 serial ports and enables me to use one for comms with the ESP8266 and the other to send debug messages to the serial monitor window of the Arduino IDE. You need to make sure that your baud rate matches that of your unit (Mine was set to 115,200 baud) and you are then able to send AT commands to the device to control it.

The pins for the device are as in the diagram below.

Thanks to Boxtec.com
Thanks to Boxtec.com

The GND pin goes to ground, VCC goes to 3.3v (NOT 5v!) and the RX and TX pins go to the opposite RX and TX pins on the appropriate serial port of your Arduino. The CH_PD pin need sto be held high so connect it to VCC also. The other pins are only used for special functions such as upgrading the firmware which I will not go into here.

Note that the ESP8266 draws a considerable mount of current and it is recommended that it is powered by a separate power supply. This makes it an interesting choice for battery powered projects, though it does have a sleep mode to conserve power. It has been known to draw up to 700mA. Your FTDI cable or Arduino may not be able to provide this much and if the device keeps resetting this is probably the cause. Where possible power it with a dedicated PSU.

To send a command to the device you simply use Serial.println  and send your command, e.g.

Serial1.println("AT+RST");

To reset the device you send

AT+RST

and the device will reset and send back a reset message. With the latest firmware the reset message is, in my opinion, needlessly large and is

 ets Jan  8 2013,rst cause:4, boot mode:(3,7)

wdt reset
load 0x40100000, len 25816, room 16 
tail 8
chksum 0x0d
load 0x3ffe8000, len 3476, room 0 
tail 4
chksum 0x8b
load 0x3ffe8da0, len 7376, room 4 
tail 12
chksum 0x33
csum 0x33
rl
ready

Essentially what you are looking for is the ‘ready’ message which shows the device has been reset and is now ready for other commands.

You can set the device in one of 3 modes using the AT+CWMODE command, as a client as an access point or as both. This means you can actually connect other devices directly to it when in AP mode, such as your phone. For my use I am using mode 1 so the device is a client.

Serial1.println("AT+CWMODE=1");

Then you need to connect the device to your WiFi router withthe CWJAP command by feeding it your SSID and Password thus

#define SSID "YourSSIDHere" 
#define PASS "YourPasswordHere"

#define ESP8266 Serial1   // Use Serial1 to talk to ESP8266 (Mega)

String cmd;   // AT command string

cmd = "AT+CWJAP=\""; // Join the Access Point
cmd += SSID;
cmd += "\",\"";
cmd += PASS;
cmd += "\"";
ESP8266.println(cmd); //send command to device

You can find out the IP and MAC address of the device using

ESP8266.println("AT+CIFSR");

There will be two sets, one for STA (Station mode) and one for AP (Access point) in Mode 3 and only one in Modes 1 and 2.

AT+CIFSR 
+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"1a:ef:34:f8:46:6c"
+CIFSR:STAIP,"192.168.0.8"
+CIFSR:STAMAC,"18:da:13:9f:12:7b"

If you want to know your firmware version you can use the GMR command

ESP8266.println("AT+GMR");

Which will return something like

AT+GMR 
0020000903_NTP

Now to obtain the time there are two methods. The first is by using the NTP command built into the latest AT command firmware.

AT+CIPNTP=0

The format is AT+CIPNTP=<offset from GMT>. Then to query the time from the NTP server simply use

AT+CIPNTP?

This works sometimes and will return the current date, time and GMT offset like this

AT+CIPNTP?
Time: 22:22:42 12/02/2014 GMT+02

However, that is only if it works. Most of the time NTP severs are notoriously overloaded and busy and you will be unable to get the time. On those occasions you will receive this message

Sntp initializing TZ: GMT00...
Sntp initializing...
pool.ntp.orgsntp_request: Waiting for server address to be resolved.
sntp_dns_found: Server address resolved, sending request
sntp_send_request: Sending request to server
sntp_process: 1424870150, ussntp_recv: Scheduled next time request: 3600000 ms

So, I had to find another way of getting the time. Thanks to some posts on Pete Scargill’s blog I was able to use a method similar to one he had used with a HTTP GET command. You simply upload a text file to your server and then request the file using GET commands. In return (when it works) you get back the date and time in the HTTP header.

This time we need to make a TCP connection to the relevant IP address of the server and send a GET request with the location of the file.

#define DST_IP "173.254.30.60" //my web site, replace with yours
cmd = "AT+CIPSTART=\"TCP\",\"";
cmd += DST_IP;
cmd += "\",80";
ESP8266.println(cmd); //send command to device
cmd = "GET /Test.txt HTTP/1.1\r\n\r\n"; //construct http GET request
cmd += "Host: thearduinoguy.org\r\n\r\n"; //test file on my web
ESP8266.print("AT+CIPSEND=");
ESP8266.println(cmd.length()); //esp8266 needs to know message length of incoming message
ESP8266.println(cmd);
ESP8266.println("AT+CIPCLOSE"); // Close the TCP connection

The relevant commands are the CIPSTART, CIPSEND and CIPCLOSE commands.

If you are lucky you will get back a response such as this

Date: Wed, 25 Feb 2015 13:34:09 GMT

A lot of the time, for reasons I have yet to fathom, you get a busy s… message by return and other error messages. As far as I can make out this is a bug in the firmware so will hopefully be ironed out eventually.

AT+CIPSTART="TCP","173.254.30.60",80 
CONNECT

OK

AT+CIPSEND=53 
>

GET /Test.txt HTTP/1.0 Host: thearduinoguy.org busy s...
AT+CIPCLOSE busy s...

SEND OK

However, the date and time string is returned often enough successfully that it can be parsed and used to sync the time on an RTC chip for your clock project. Obviously, don’t use my web page, use your own, though your welcome to use it for testing purposes only.

The whole test code for this is below. Note that this is not complete and is mainly code for sending AT commands and seeing the response. The relevant timeout is allowed for a response after each command (some take longer than others).

Once the code is complete I can add it to the code for the clock project. I need to parse the returned date/time header and then inject that latest time into the RTC chip on the clock circuit.

Message me if you need any help with any of the above.

Mike

#define BUFFER 1024 // size of the buffer in bytes 

#define SSID   "YourSSIDHere" 
#define PASS   "YourPasswordHere"
#define DST_IP "173.254.30.60" //my web site, replace with yours

char buffer[BUFFER];  // buffer for returned messages
String cmd;   // AT command string

#define DEBUG Serial      // Send debug messages to serial monitor
#define ESP8266 Serial1   // Use Serial1 to talk to ESP8266 (Mega)

// By default we expect OK\r\n back
char OK[] = "OK\r\n";

//=====================================================================
void setup() {
  delay(1000);
  ESP8266.begin(115200); // Start ESP8266 comms 
  DEBUG.begin(115200); // Start seriam monitor comms for debug messages
  DEBUG.println("Initialising...");
  
  initESP8266(); // Initialise the ESP8266 module
}

//=====================================================================
byte waitForResponse(int timeout, char* term=OK) {
  unsigned long t=millis();
  bool found=false;
  int i=0;
  int len=strlen(term);
  // wait for at most timeout milliseconds
  // or if OK\r\n is found
  while(millis()<(t+timeout)) {
    if(ESP8266.available()) {
      buffer[i++]=ESP8266.read();
      if(i>=len) {
        if(strncmp(buffer+i-len, term, len)==0) {
          found=true;
          break;
        }
      }
    }
  }
  buffer[i]=0;
  DEBUG.println(buffer);
  delay(100);
  return found;
}

//=====================================================================
void initESP8266() { 
  ESP8266.println("AT+RST"); // Reset the ESP8266
  waitForResponse(10000);
   
  ESP8266.println("AT+CWMODE=1"); // Set Mode 1 (STA = Client)
  waitForResponse(5000);  
  
  cmd = "AT+CWJAP=\""; // Join the Access Point
  cmd += SSID;
  cmd += "\",\"";
  cmd += PASS;
  cmd += "\"";
  ESP8266.println(cmd);  //send command to device
  waitForResponse(10000);
  
  ESP8266.println("AT+CIPMUX=0"); // Single connection
  waitForResponse(5000); 
  
  ESP8266.println("AT+CIPMODE=0"); // Normal mode
  waitForResponse(5000);  
  
  ESP8266.println("AT+CIFSR"); // Print the IP address of module
  waitForResponse(5000);
  
  ESP8266.println("AT+GMR"); // Print the Firmware version
  waitForResponse(5000);
  
  DEBUG.println("============================");
}

//=====================================================================
void getTheTime() {
  cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += DST_IP;
  cmd += "\",80";
  ESP8266.println(cmd);  //send command to device
  waitForResponse(10000);
  
  cmd =  "GET /Test.txt HTTP/1.0\r\n\r\n";  //construct http GET request
  cmd += "Host: thearduinoguy.org\r\n\r\n";        //test file on my web
  ESP8266.print("AT+CIPSEND=");
  ESP8266.println(cmd.length());  //esp8266 needs to know message length of incoming messa
  waitForResponse(10000);
  
  ESP8266.println(cmd);
  waitForResponse(60000);
  
  ESP8266.println("AT+CIPCLOSE"); // Close the TCP connection
  waitForResponse(5000);
  
  DEBUG.println("------------------------------");
}

//=====================================================================
void loop() { 
  getTheTime();
  delay(30000); // Check for time once a minute 
}

 

17 thoughts on “Using an ESP8266 as a time source (Part 1)

  1. MIke
    Worth adding that the ESP8266 will draw significant current at 3V3, (mine takes >700mA).
    This can cause your ‘duino, or your USB port to bork if you don’t power it seperately.

    Chic

  2. Hello…..if i test your script that is http://thearduinoguy.org/Test.txt in web bowser then i gets response like :This is a test

    so if i send same request using ESP8266 using GET method then should i get same kind of response in terminal or no response becuase when i tested it with ESP8266 i could not get any response…

    where is my mistake?

  3. 173.254.30.60 is a personal web server you run?

    I have a hosted website, but I don’t have an IP address for it.
    I only have the URL.
    Can I still use the HTTP GET method to get the NTP time?

    1. Hi, yes it is a personal web server with the time file included. You could just as easily get the time from the header of any small website. HTTP time and NTP time are two seperate things.

        1. Yes it works pretty well. You only have to update the time about once a week or even once a month anyway so it’s no big deal.

        1. It doesn’t. When a HTML page is requested over HTTP the header of the page includes the date and time it was requested. With a tiny text file this will be done very quicky and hence is quick enough to do a time sync.

  4. I guess I am dense, but I don’t see anywhere in your code how you are parsing the HTTP header for the time and date.

Leave a Reply

Your email address will not be published. Required fields are marked *