Tuesday, 8 September 2015

Arduino and ESP8266 - part 2 - The web thermometer

In the previous video, I've shown various options to connect an ESP8266 module to an Arduino board. Now it is time to turn that into something (sortof) userful.

Watch this video to see how I build a web connected thermometer.



The program is a bit particular in that it wants AT-firmware 0.9.2.2 to run stable. I have tried the latest AT firmware but had no luck and didn't invenstigate any further. It's default baud rate of 9k6 is slow enough for a SoftwareSerial connection.

There are no surprises in the schematic diagram:



Here ist the code:


 /* ====== ESP8266 Web Thermometer Demo ======  
  * Print out temperature from TMP36 sensor  
  * on analog-in 3  
  * (Modified Aug 28, 2015 ARe)  
  * ==========================  
  *  
  * Change SSID and PASS to match your WiFi settings.  
  * The IP address is displayed to serial upon successful connection.  
  *  
  * modified by Andy Reischle (www.AReResearch.net)  
  * based on:  
  * Ray Wang @ Rayshobby LLC  
  * http://rayshobby.net/?p=9734  
  */  
 #define SSID "MYWIFI"   // change this to match your WiFi SSID  
 #define PASS "sorrywonttell" // change this to match your WiFi password  
 #define PORT "80"      // using port 80 by default  
 char buffer[BUFFER_SIZE];  
 // using Software Serial for connection to ESP  
 // Use the definitions below  
 #include <SoftwareSerial.h>  
 SoftwareSerial esp(10,11); // used pins 10, 11 for software serial   
 #define dbg Serial  
 // By default we are looking for OK\r\n  
 char OKrn[] = "OK\r\n";  
 byte wait_for_esp_response(int timeout, char* term=OKrn) {  
  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(esp.available()) {  
    buffer[i++]=esp.read();  
    if(i>=len) {  
     if(strncmp(buffer+i-len, term, len)==0) {  
      found=true;  
      break;  
     }  
    }  
   }  
  }  
  buffer[i]=0;  
  dbg.print(buffer);  
  return found;  
 }  
 void setup() {  
  // assume esp8266 operates at 9600 baud rate  
  // change if necessary to match your modules' baud rate  
  esp.begin(9600);  
  dbg.begin(9600);  
  dbg.println("begin.");  
  setupWiFi();  
  // print device IP address  
  dbg.print("device ip addr:");  
  esp.println("AT+CIFSR");  
  wait_for_esp_response(1000);  
 }  
 bool read_till_eol() {  
  static int i=0;  
  if(esp.available()) {  
   buffer[i++]=esp.read();  
   if(i==BUFFER_SIZE) i=0;  
   if(i>1 && buffer[i-2]==13 && buffer[i-1]==10) {  
    buffer[i]=0;  
    i=0;  
    dbg.print(buffer);  
    return true;  
   }  
  }  
  return false;  
 }  
 void loop() {  
  int ch_id, packet_len;  
  char *pb;   
  if(read_till_eol()) {  
   if(strncmp(buffer, "+IPD,", 5)==0) {  
    // request: +IPD,ch,len:data  
    sscanf(buffer+5, "%d,%d", &ch_id, &packet_len);  
    if (packet_len > 0) {  
     // read serial until packet_len character received  
     // start from :  
     pb = buffer+5;  
     while(*pb!=':') pb++;  
     pb++;  
     if (strncmp(pb, "GET /", 5) == 0) {  
      wait_for_esp_response(1000);  
      dbg.println("-> serve homepage");  
      serve_homepage(ch_id);  
     }  
    }  
   }  
  }  
 }  
 void serve_homepage(int ch_id) {  
  String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\nRefresh: 5\r\n";  
  String content="";  
 // read in TMP36 at Analog 3 port  
  int reading = analogRead(3);  
  float voltage = reading * 5.0;  
  voltage /= 1024.0;   
  float temperatureC = (voltage - 0.5) * 100 ;  
  Serial.print(temperatureC); Serial.println(" degrees C");  
  content += "Temperature is ";  
  content += temperatureC;  
  content += "C <br />\n";  
  header += "Content-Length:";  
  header += (int)(content.length());  
  header += "\r\n\r\n";  
  esp.print("AT+CIPSEND=");  
  esp.print(ch_id);  
  esp.print(",");  
  esp.println(header.length()+content.length());  
  if(wait_for_esp_response(2000, "> ")) {  
   esp.print(header);  
   esp.print(content);  
  } else {  
   esp.print("AT+CIPCLOSE=");  
   esp.println(ch_id);  
  }  
 }  
 void setupWiFi() {  
  // try empty AT command  
  esp.println("AT");  
  wait_for_esp_response(2000);  
  // set mode 1 (client)  
  esp.println("AT+CWMODE=1");  
  wait_for_esp_response(2000);   
  // reset WiFi module  
 /*  
  esp.print("AT+RST\r\n");  
  wait_for_esp_response(3000);  
  delay(5000);  
  */  
  // join AP  
  esp.print("AT+CWJAP=\"");  
  esp.print(SSID);  
  esp.print("\",\"");  
  esp.print(PASS);  
  esp.println("\"");  
  // this may take a while, so wait for 5 seconds  
  wait_for_esp_response(5000);  
  esp.println("AT+CIPSTO=30");   
  wait_for_esp_response(1000);  
  // start server  
  esp.println("AT+CIPMUX=1");  
  wait_for_esp_response(1000);  
  esp.print("AT+CIPSERVER=1,"); // turn on TCP service  
  esp.println(PORT);  
  wait_for_esp_response(1000);  
 }  

I have made two modifications to the code:

  • To keep the Arduino's original debugging facility, I kept the hardware UART for that purpose and defined a "software serial" port on pins 10 and 11. The suggested firmware version defaults to 9600 baud, so speed is not an issue.
  • The other change is that I nicked a few lines of code from Adafruit to replace the original output

22 comments:

  1. I follow your blog and it is very inspiring! I would like to ask you how I can I publish this data to mqtt? I have several arduino that works perfectly stable with sensors and now log the readings flawlessly to SD cards, but I want to add esp8266 to send the sensor data every 30 seconds with mqtt to a mosquitto server running on raspberry pi.
    Any help would be much appreciated.

    ReplyDelete
    Replies
    1. I'd first check if the Arduinos are still necessary. The NodeMCU firmware has a fairly robust MQTT implementation. ( http://www.nodemcu.com/docs/mqtt-module/ ). So you might interface the sensors directly to the ESP module.
      If that is not an option (because you'd lose the SD-card as a local storage), you'll have to resort to the AT-Firmware and have a look at this thread: http://forum.arduino.cc/index.php?topic=290665.0

      Delete
    2. I've tried with using only esp and sensor, but several different tests have proven that the esp was so unstable and would not provide consistent results and more than often freeze.
      I also tried the espduino. No problem flashing it to the esp but then when uploading the ino file to the arduino only gives weird characters and could not make it connect.

      Delete
  2. I am using the same code but still not getting o/p
    please if you can answer my following questions
    1.) which board should we use arduino uno or generic esp8266
    2.) why I am getting nothing on serial monitor although program is showing zero errors

    ReplyDelete
    Replies
    1. 1) You're only programming the Arduino from the Arduino IDE, so you have to choose "Arduino Uno" as the board.
      2) Do you have the 0.9.2.2 AT-firmware on the ESP8266 module?

      Delete
  3. Thanks for an awesome blog.

    I have tried to compile this code on a arduino ide 1.6.7 on a pro-mini 3.3 and get the following error

    error: 'buffer' was not declared in this scope

    if(strncmp(buffer, "+IPD,", 5)==0) {

    ^

    exit status 1
    'BUFFER_SIZE' was not declared in this scope

    any help would be appreciated.

    ReplyDelete
    Replies
    1. Oh, I see. Try a "#define BUFFER_SIZE 100" at the top of the sketch. Haven't tried that yet, though.

      Delete
  4. hello sir sorry
    I want to share my project with you, i want to connect 3,4 sensors with arduino and esp8266 so that I can get the data of them all on my mobile.
    Till now I am successful in sending just a particular text that I type on the serial moNitor to my mobile phone(when i did this task sir I connected the transmitter and receiver of esp directly to transmitter and receiver of arduino) and i just used few AT commands AT CIPSEND=0,30 which was the used including some other like AT CIFSR etc

    Sir please i really need your help in this project.please reply me some valuable tips.
    thanks in advance
    raman
    electronics student

    ReplyDelete
    Replies
    1. Depending on the sensors, it might make sense to cut out the arduino completely. You can still do your development in the arduino IDE, but program the ESP8266 directly. (Or use NodeMCU, which is my preferred firmware)
      If your sensors are I2C devices, this should work great for you.

      Delete
    2. Sir I think you have made this project on CWMODE=1 but I want to make it on CWMODE=2 ie TCP/IP client mode. Moreover I want to do this on arduino itself.
      Have you made any project related to this in which we don't use any external Wi-Fi like I think you are using in this web thermometer.
      Can you guide a little bit for "How to transmit sensor data using arduino and esp8266 on tcp/ip mode.
      thanks in advance.

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
  6. Thanks Sir ... for this Job
    when i open serial monitor, I only got this two line:
    begin.
    device ip addr:

    where is the problem ??

    ReplyDelete
  7. Sir Thank You for the awesome tutorial.I appreciate your hardwork nad dedication.

    Sir how can we figure out if AT-Firmware is there or not on ESP-8266?

    ReplyDelete
    Replies
    1. You can see that from the response on the serial interface. The easiest way is to use "esplorer". It has pre-defined commands for both NodeMCU and AT-Firmware.

      Delete
  8. Compile Errors:

    'BUFFER_SIZE' was not declared in this scope

    From your comment above I added:

    #define BUFFER_SIZE 100

    Now I get this:

    'esp' was not declared in this scope

    Please advise?

    ReplyDelete
    Replies
    1. Something must have happened to the line:
      SoftwareSerial esp(10,11);
      Please check if that is near the beginning of your code.

      Delete
  9. I had commented out software serial because I don't plan to use it. But re-added your code from scratch and the only changes made this time was the #define BUFFER_SIZE 100
    And adding my SSID and Password. Now I get this:

    Arduino: 1.6.10 (Windows 7), Board: "Arduino Nano, ATmega328"

    C:\Users\david\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.14\cores\arduino\main.cpp: In function 'main':

    C:\Users\david\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.14\cores\arduino\main.cpp:51:1: error: unable to find a register to spill in class 'NO_REGS'

    }

    ^

    C:\Users\david\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.14\cores\arduino\main.cpp:51:1: error: this is the insn:

    (insn 389 386 392 34 (set (mem:QI (post_dec:HI (reg/f:HI 32 __SP_L__)) [0 S1 A8])

    (subreg:QI (reg/f:HI 383) 1)) C:\Users\david\AppData\Local\Temp\arduino_modified_sketch_314486\BareMinimum.ino:81 1 {pushqi1}

    (expr_list:REG_ARGS_SIZE (const_int 7 [0x7])

    (nil)))

    C:\Users\david\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.14\cores\arduino\main.cpp:51: confused by earlier errors, bailing out

    lto-wrapper: C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-gcc returned 1 exit status

    c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.9.2/../../../../avr/bin/ld.exe: lto-wrapper failed

    collect2.exe: error: ld returned 1 exit status

    exit status 1
    Error compiling for board Arduino Nano.

    ReplyDelete
    Replies
    1. The sketch should be ok on a Nano. But if you don't want to use SoftwareSerial, this breaks all lines with "esp."
      It is then easier to modify the original version:
      http://rayshobby.net/?p=9734

      Delete
    2. I'm already way ahead of you ;) As soon as I encountered problems, I went to the original.
      Unfortunately I have issues there too but my post at rayshobby.net remains unanswered.
      I give up. Thanks for the help though.

      Delete
    3. No need to give up. The downside of Ray's original sketch is that you can't use the standard port for debugging on an arduino. Do you need all the GPIO pins and can't spare the two pins for the software-uart?

      Delete
  10. I am using an ESP8266 on an adapter board with a Nano because I don't want to have to deal with level shifting. The adapter does all this for me so I have only 4 pins coming from my ESP. GND VCC RX and TX.
    The module works just fine, can connect to my wifi and be pinged on the network. - No issues there.

    This is the exact model I purchased:(http://www.banggood.com/ESP8266-ESP-01-WIFI-Transceiver-Wireless-Module-Serial-Wi-Fi-Wireless-Adapter-Module-For-Arduino-p-1049585.html)

    GPIO pins are not really the issue, the issue is that I don't have a serial programmer (yet, on order) so cannot use the software serial. Of course I realize it doesn't need to be removed from the code.

    What I am trying to ultimately do is get the nano to dump it's temp readings into an influxdb database using this lib:

    https://hwwong168.wordpress.com/2015/11/23/esp8266-writing-data-into-influxdb/

    I will then graph this data with "grafana" visualization software (both of which I already have running, but without being able to get the nano to drop it's data into the database, I'm stuck)

    So I think it's pretty clear I'm out of my depth with this project as a complete beginner with arduino and ESP. I just don't have the skills or knowledge to make this work.

    ReplyDelete
  11. Arduino: 1.6.11 (Mac OS X), Board: "Arduino/Genuino Uno"

    Temp_to_IP:18: error: 'BUFFER_SIZE' was not declared in this scope
    char buffer[BUFFER_SIZE];
    ^
    /Users/pratibhabenjamin/Documents/Arduino/Temp_to_IP/Temp_to_IP.ino: In function 'byte wait_for_esp_response(int, char*)':
    Temp_to_IP:35: error: 'buffer' was not declared in this scope
    buffer[i++]=esp.read();
    ^
    Temp_to_IP:44: error: 'buffer' was not declared in this scope
    buffer[i]=0;
    ^
    /Users/pratibhabenjamin/Documents/Arduino/Temp_to_IP/Temp_to_IP.ino: In function 'bool read_till_eol()':
    Temp_to_IP:63: error: 'buffer' was not declared in this scope
    buffer[i++]=esp.read();
    ^
    Temp_to_IP:64: error: 'BUFFER_SIZE' was not declared in this scope
    if(i==BUFFER_SIZE) i=0;
    ^
    /Users/pratibhabenjamin/Documents/Arduino/Temp_to_IP/Temp_to_IP.ino: In function 'void loop()':
    Temp_to_IP:78: error: 'buffer' was not declared in this scope
    if(strncmp(buffer, "+IPD,", 5)==0) {
    ^
    exit status 1
    'BUFFER_SIZE' was not declared in this scope

    This report would have more information with
    "Show verbose output during compilation"
    option enabled in File -> Preferences.
    I'm getting this error

    ReplyDelete