ESP8266 #2 with DHT11 to Thingspeak

Today I got my new DHT11 Sensors from china, which may have been record time as far as I can tell.  Although I don’t *NEED* them, I thought I’d crack one open and put it to use.  I’m getting more comfortable with arduino C and increasing the complexity of the programs so I decided to functionalize the the Thingspeak Upload since I was having a hard time making heads or tails of inserting snippets from other programs.

I also wanted to see if the following elements could coexist.  I’m used to running virtualenv in python to limit the interactions of different libraries, but have not done this in C and don’t even know if it’s possible.  This program combines the following.

  • WiFi Manager (totally awesome utility for connecting)
    • This is so awesome because I no longer have to hardcode and subsequently erase WiFi creds when I upload to a repo.
  • NTP client for timestamping data (not yet implemented)
  • DHT11 Sensor and a calculated dewpoint
  • Thingspeak Web POST to API

Although to seasoned programmers, I’m guessing this is not too much going on, but for me, it’s the most activity in one device at once and it took some wrapping my head around.   I’m posting the code which is poorly documented and Dr. Purdum would probably shit a brick sideways at my lack thereof.  When I started with arduino, I relied heavily on his book to learn the basics of C and find myself regularly referring to it. 

I would like to add a non-blocking millis() timer to the mix next refactor.

The code is below, and after I clean it up a bit, it’ll go to github.

#include           //https://github.com/esp8266/Arduino

//needed for library
#include 
#include 
#include           //https://github.com/tzapu/WiFiManager

#include               //UDP Socket for NTP timekeeping

#include 
#define DHTTYPE DHT11
#define DHTPIN  12
DHT dht(DHTPIN, DHTTYPE, 11); // 11 works fine for ESP8266
float humidity, temp_f;  // Values read from sensor

//THINGSPEAK
String apiKey = "xxxxxxxxxxxxxxxx";
const char* server = "api.thingspeak.com";

//for LED status
#include 
Ticker ticker;

//UDP funcionality
unsigned int localPort = 2390;      // local port to listen for UDP packets

/* Don't hardwire the IP address or we won't get the benefits of the pool.
    Lookup the IP address for the host name instead */
//IPAddress timeServer(98, 175, 203, 200 ); // time.nist.gov NTP server
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";

const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;

void tick()
{
  //toggle state
  int state = digitalRead(BUILTIN_LED);  // get the current state of GPIO1 pin
  digitalWrite(BUILTIN_LED, !state);     // set pin to the opposite state
}

//gets called when WiFiManager enters configuration mode
void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
  //entered config mode, make led toggle faster
  ticker.attach(0.2, tick);
}
//instantiate wifi client
WiFiClient client;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  dht.begin();           //DHT11 I2C Start

  //Set pin 13 as a indicator of NTP time activity
  pinMode(13, OUTPUT);

  //set led pin as output
  pinMode(BUILTIN_LED, OUTPUT);
  // start ticker with 0.5 because we start in AP mode and try to connect
  ticker.attach(0.6, tick);

  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;
  //reset settings - for testing
  //  wifiManager.resetSettings();

  //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
  wifiManager.setAPCallback(configModeCallback);

  //fetches ssid and pass and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "AutoConnectAP"
  //and goes into a blocking loop awaiting configuration
  if (!wifiManager.autoConnect()) {
    Serial.println("failed to connect and hit timeout");
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(1000);
  }

  //if you get here you have connected to the WiFi
  Serial.println("connected...yeey :)");
  ticker.detach();
  //keep LED on
  digitalWrite(BUILTIN_LED, LOW);

  /*UDP LOOP SETUP

  */
  Serial.println("WiFi connected for NTP Service");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Starting UDP");
  udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(udp.localPort());


}

void loop() {
  digitalWrite(13, HIGH);
  //get a random server from the pool
  WiFi.hostByName(ntpServerName, timeServerIP);

  float h = dht.readHumidity();    // reading Humidity
  float tempC = dht.readTemperature(); // read Temperature as Celsius (the default)
  float temp = (32 + (9 * tempC) / 5); //approximately 2 degrees error correction for conversion and sensor inaccuracy

  float dP = (dewPointFast(tempC, h));
  float cDP = ((dP * 9) / 5) + 32;

  Serial.println("Temp\tRelHum\tcDewPt");
  Serial.print(temp);
  Serial.print("\t");
  Serial.print(h);
  Serial.print("\t");
  Serial.println(cDP);

  sendNTPpacket(timeServerIP); // send an NTP packet to a time server
  // wait to see if a reply is available
  delay(1000);

  int cb = udp.parsePacket();
  if (!cb) {
    Serial.println("no packet yet");
  }
  else {
    //    Serial.print("packet received, length=");
    //    Serial.println(cb);
    // We've received a packet, read the data from it
    udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    //    Serial.print("Seconds since Jan 1 1900 = " );
    //    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    //    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
    // print Unix time:
    //    Serial.println(epoch);


    // print the hour, minute and second:
    Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
    Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day)
    Serial.print(':');
    if ( ((epoch % 3600) / 60) < 10 ) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':');
    if ( (epoch % 60) < 10 ) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(epoch % 60); // print the second


    //Now lets print the local time for EST
    Serial.print("The EST time is ");
    byte hourGMT = ((epoch  % 86400L) / 3600);  // print the hour (86400 equals secs per day)
    int hourEST = (hourGMT - 4);                //  adjust UTC to EST with DST
    if (hourEST < 0) {                          // if EST hour is negative then...
      hourEST = (24 + hourEST);                 // add it to 24 to get legit EST hour
    }

    Serial.print(hourEST);
    Serial.print(':');
    if ( ((epoch % 3600) / 60) < 10 ) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':');
    if ( (epoch % 60) < 10 ) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(epoch % 60); // print the second

  }
  digitalWrite(13, LOW);
  // wait ten seconds before asking for the time again
  delay(60000);

  thingspeakPublish(temp, h, cDP);

  // END OF VOID LOOP END OF VOID LOOP

}

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address)
{
  Serial.println("sending NTP packet...");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  udp.beginPacket(address, 123); //NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();

}
// DEW POINT CALCULATION********************
// delta max = 0.6544 wrt dewPoint()
// 6.9 x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
  double a = 17.271;
  double b = 237.7;
  double temp = (a * celsius) / (b + celsius) + log(humidity * 0.01);
  double Td = (b * temp) / (a - temp);
  return Td;
}

void thingspeakPublish(float temp, float h, float cDP) {
  if (client.connect(server, 80)) { // "184.106.153.149" or api.thingspeak.com
    String postStr = apiKey;
    postStr += "&field1=";
    postStr += String(temp);
    postStr += "&field2=";
    postStr += String(h);
    postStr += "&field3=";
    postStr += String(cDP);
    postStr += "\r\n\r\n";

    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(postStr.length());
    client.print("\n\n");
    client.print(postStr);

    Serial.print("Temperature: ");
    Serial.print(temp);
    Serial.println(" F");
    Serial.println("% send to Thingspeak");
  }
  client.stop();


};

 

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s