tcparduinoesp8266esp8266wifi

ESP8266 NodeMCU can't send TCP commands - same code works on Arduino Uno?


I'm a noob at this, so hopefully a stupidly obvious one.

I'm trying to create a simple temperature/humidity sensor that takes readings from a DHT22 and uses an ESP8266 to ping them to Thingspeak's API to then graph out/store etc.

I've pasted code below - it worked on Arduino Uno and I'm trying to shrinkify it onto a ESP8266 so I can produce lots of little temperature sensors for around the house.

Symptoms

I can't tell if it's something odd about moving from Arduino Uno to ESP8266 that's causing the problem (ie different libraries required, TCP commands being different etc)

Any help from a more seasoned veteran would be much appreciated!

Here's a snippet of the serial monitor output and the code (just passwords/apis etc)

22:16:50.266 -> **************
22:16:57.579 -> Wifi Connection Successful
22:16:57.579 -> The IP Address of the Sensor is:192.168.1.211
22:16:57.579 -> Humidity: 41.50
22:16:57.579 -> Temperature: 21.70
22:16:57.579 -> AT+CIPSTART="TCP","api.thingspeak.com",80
22:17:00.574 -> AT+CIPSEND=63
22:17:01.561 -> AT+CIPCLOSE
22:17:02.577 -> Data Fail!
22:17:02.577 -> GET /update?apikey=<REMOVED>&field1=21.70&field2=41.50


#include<stdlib.h>
#include "DHT.h"
#include <ESP8266WiFi.h>

#define SSID "<REMOVED>" //your network name
#define PASS "<REMOVED>" //your network password
#define API "<REMOVED>" //api string
#define IP "api.thingspeak.com" // thingspeak.com
#define DHTPIN 4     // what pin the DHT sensor is connected to
#define DHTTYPE DHT22   // Change to DHT22 if that's what you have
#define Baud_Rate 115200 //Another common value is 9600
#define DELAY_TIME 300000 //time in ms between posting data to ThingSpeak

//Can use a post also
String GET = String("GET /update?apikey=") + API + "&field1=";
String FIELD2 = "&field2=";

//if you want to add more fields this is how
//String FIELD3 = "&field3=";

bool updated;

DHT dht(DHTPIN, DHTTYPE);

//this runs once
void setup()
{
  delay(5000);
  Serial.begin(Baud_Rate);
  // Connect to WIFI
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print("*");
  }

  Serial.println("");
  Serial.println("Wifi Connection Successful");
  Serial.print("The IP Address of the Sensor is:");
  Serial.println(WiFi.localIP()); //Print the IP Address


  //initalize DHT sensor
  dht.begin();
}

//this runs over and over
void loop() {
  float h = dht.readHumidity();
  Serial.print("Humidity: ");
  Serial.println(h);
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float c = dht.readTemperature();
  Serial.print("Temperature: ");
  Serial.println(c);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(c)) {
    Serial.println("Reading DHT22 Failed, exiting");
    return;
  }

  //update ThingSpeak channel with new values
  updated = updateTemp(String(c), String(h));

   //wait for delay time before attempting to post again
  delay(DELAY_TIME);
}

bool updateTemp(String tempC, String humid) {
  //initialize your AT command string
  String cmd = "AT+CIPSTART=\"TCP\",\"";

  //add IP address and port
  cmd += IP;
  cmd += "\",80";

  //connect
  Serial.println(cmd);
  delay(2000);
  if (Serial.find("Error")) {
    return false;
  }

  //build GET command, ThingSpeak takes Post or Get commands for updates, I use a Get
  cmd = GET;
  cmd += tempC;
  cmd += FIELD2;
  cmd += humid;
  cmd += "\r\n";  

  //continue to add data here if you have more fields such as a light sensor
  //cmd += FIELD3;
  //cmd += <field 3 value>

  //Serial.println(cmd);
  //Use AT commands to send data
  Serial.print("AT+CIPSEND=");
  Serial.println(cmd.length());
  if (Serial.find(">")) {
    //send through command to update values
    Serial.print(cmd);
  } else {
    Serial.println("AT+CIPCLOSE");
  }

  if (Serial.find("OK")) {
    //success! Your most recent values should be online.
    Serial.println("Data Sent!");
    return true;
  } else {
    Serial.println("Data Fail!");
    Serial.println(cmd);
    return false;
  }
}

boolean connectWiFi() {
  //set ESP8266 mode with AT commands
  Serial.println("AT+CWMODE=1");
  delay(2000);

  //build connection command
  String cmd = "AT+CWJAP=\"";
  cmd += SSID;
  cmd += "\",\"";
  cmd += PASS;
  cmd += "\"";

  //connect to WiFi network and wait 5 seconds
  Serial.println(cmd);
  delay(5000);

  //if connected return true, else false
  if (Serial.find("OK")) {
    Serial.println("WIFI connected");
    return true;
  } else {
    Serial.println("WIFI not connected");
    return false;
  }
}



Solution

  • First before we discuss of the problem you are facing, you need to understand the two different ways of using ESP8266:

    When using it as a WiFi modem, you communicate with it using AT-command, and by default that is what most of ESP8266 module does, it shipped with At-command firmware.

    When you using an ESP8266 as an MCU, you flash the ESP8266 with Arduino sketch, which overrides the AT-Command firmware and upload it with Arduino bootloader, and allow the ESP8266 to be used as a stand-alone MCU like an Arduino.

    You mentioned that you be able to communicate with ESP8266 without any problem when using Arduino Uno, which suggests that you were communicating with the ESP8266 using AT-command (and part of your code suggested that this was the case).

    When you upload an Arduino sketch to the ESP8266 to use it as a stand-alone MCU, you need to communicate with ESP8266 using Arduino library such as ESP8266WiFi which will take care of the lower level communication with the ESP8266 chip. This is why you be able to establish a WiFi by using the capability provided by ESP8266WiFi class.

    However, your code in your updateTemp() is still using AT-command that no longer work. You will need either use ESP8266WebClient or ESP8266HTTPClient(this one is simpler and easier) library for establishing a http connection. Here is the code that I modified for using the ESP8266HTTClient library to handle the HTTP requests. BTW, the code compiled okay, but I have not test it with thinkspeak server as I don't use thinkspeak and don't have an api-key for it.

    #include <DHT.h>
    #include <ESP8266WiFi.h>
    #include <ESP8266HTTPClient.h>
    
    #define SSID "<REMOVED>" //your network name
    #define PASS "<REMOVED>" //your network password
    #define API "<REMOVED>" //api string
    #define IP "api.thingspeak.com" // thingspeak.com
    #define PORT 80
    #define DHTPIN 4     // what pin the DHT sensor is connected to
    #define DHTTYPE DHT22   // Change to DHT22 if that's what you have
    #define BAUD_RATE 115200 //Another common value is 9600
    #define DELAY_TIME 300000 //time in ms between posting data to ThingSpeak
    
    DHT dht(DHTPIN, DHTTYPE);
    
    //this runs once
    void setup()
    {
      Serial.begin(BAUD_RATE);
    
      // Connect to WIFI
      WiFi.begin(SSID, PASS);
      while (WiFi.status() != WL_CONNECTED)
      {
        delay(500);
        Serial.print("*");
      }
      Serial.println("");
      Serial.println("Wifi Connection Successful");
      Serial.print("The IP Address of the Sensor is:");
      Serial.println(WiFi.localIP());
    
      //initalize DHT sensor
      dht.begin();
    }
    
    //this runs over and over
    void loop() {
      float h = dht.readHumidity();
      Serial.print("Humidity: ");
      Serial.println(h);
      // Read temperature as Fahrenheit (isFahrenheit = true)
      float c = dht.readTemperature();
      Serial.print("Temperature: ");
      Serial.println(c);
    
      // Check if any reads failed and exit early (to try again).
      if (isnan(h) || isnan(c)) {
        Serial.println("Reading DHT22 Failed, exiting");
        return;
      }
    
      //update ThingSpeak channel with new values
      updateTemp(c, h);
    
      //wait for delay time before attempting to post again
      delay(DELAY_TIME);
    }
    
    
    bool updateTemp(float tempC, float humid) {
    
      WiFiClient client;    // Create a WiFiClient to for TCP connection
    
      if (!client.connect(IP, PORT)) {
       Serial.println("HTTP connection failed");
       return false;
      }
    
      Serial.println("Sending data to server");
      if (client.connected()) {
        client.print("GET /update?api_key="); client.print(API);
        client.print("&field1="); client.print(String(tempC));
        client.print("&field2="); client.print(String(humid));
        client.println(" HTTP/1.1");
        client.print("Host: "); client.println(IP);
        client.println("Connection: close");
        client.println();    //extra "\r\n" as per HTTP protocol
      }
    
      // wait for data to be available
      unsigned long timeout = millis();
      while (client.available() == 0) {
        if (millis() - timeout > 5000) {
         Serial.println("HTTP Client Timeout !");
         client.stop();
         return false;
        }
      }
    
      Serial.println("Receiving HTTP response");
      while (client.available()) {
       char ch = static_cast<char>(client.read());
       Serial.print(ch);
      }
      Serial.println();
    
      Serial.println("Closing TCP connection");
      client.stop();
      return true;
    }