Arduino, Thingspeak & an ESP8266 (Part VI)

Fourth Revision: Has the Time come for Timer.h?

In my last post I discussed using a low-pass filter to improve readings from my DHT11. One of the major benefits of using this instead of my earlier method is that it freed me from the requirement of going through a set number of read cycles before sending to Thingspeak. Why is that important? Because I don’t really care about the exact number of read cycles, I just want to send accurate data to Thingspeak every minute or so. Another problem is that this often requires the use of long, blocking delays which are annoying and limit the future possibilities of the Sketch.

The solution to this is a small library called Timer.h. Originally developed by Simon Monk and then taken over by Jack Christensen and Damian Philip, Timer.h is a library that radically simplifies the process of timing events.

At its core is a pair of lines:

In voidSetup()

  t.every(timeperiod, function);

and in voidLoop()

  t.update();

How this works, is that it checks every cycle to see if “timeperiod” has passed and if it has it runs “function.” Simple as that!

However, it does require the script to be re-factored with functions. More on that in my next post but click below for the script

Continue reading “Arduino, Thingspeak & an ESP8266 (Part VI)”

Advertisements

Arduino, Thingspeak & an ESP8266 (Part V)

Fourth Revision: Now We Are Getting Somewhere!

In the fourth revision of this project things finally started to click together for me.

The problem with my last Sketch was that it used a relatively simple mechanism for averaging the readings between two successive cycles of sending data to Thingspeak. This did a decent job of leveling out strange readings but suffered from a major problem: it was impossible to tune. Is this a problem? Probably not, but it really, really annoyed me.

Another problem with this approach was that it was cycle dependent.  That means that I had no effective way of measuring the averaged reading between cycles!

The standard approach to solving this problem would be to use a moving average as is implemented here. However, I happened to be reading a copy of Simon Monk’s superb Programming Arduino: Next Steps and realized that his simple low-pass filter would do the trick.

Here is the basic equation of the filter:

(alpha * runningaverage) + ((1 - alpha) * newreading)

One way to think of this is if alpha = 0.95 then on every cycle 5% (0.05) of the new value is added to the running average.

There are a couple of advantages to this approach: 1) it is easy to understand, 2) it is easy to tweak (just change alpha), 3) it does not use arrays so is fairly memory friendly (not that that matters on the ESP8266!)

I’ll show you the actual sketch in the next post as I also changed how timing works and want to put that under a different heading.

Arduino, Thingspeak & an ESP8266 (Part IV)

Third Revision: Refactoring

The third version of this sketch is pretty similar to the last one. It just uses a for loop instead of a counter and if. Honestly the main reason for this revision is that the if seemed kind of tacky, not sure why I wrote it that way to begin with.

#include <ThingSpeak.h>
#include <ESP8266WiFi.h>
#include <DHT.h>

#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht (DHTPIN, DHTTYPE);

const char* ssid = "ssid";
const char* pass = "password";
const int RED = 15;
const int WHITE = 14;
const int GREEN = 13;
const int BLUE = 12;

int i = 0;
int c = 0;
float h = 0;
float f = 0;
float hsum = 0;
float fsum = 0;

unsigned long myChannelNumber = "channel number";
const char* myWriteAPIKey = "API Number";
WiFiClient client;

void setup() {
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);
  pinMode(WHITE, OUTPUT);

  Serial.begin(9600);
  delay(10);
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    analogWrite(RED, 75);
    delay(500);
    Serial.print(".");
  }

  if (WiFi.status() == WL_CONNECTED) {
    analogWrite(RED, 0);
    analogWrite(BLUE, 75);
    delay(100);
    analogWrite(BLUE, 0);
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  ThingSpeak.begin(client);

}

void loop() {
  for (c = 0; c < 10; c++) {
    analogWrite(WHITE, 50);
    Serial.print("c= ");
    Serial.println(c);
    float h = dht.readHumidity();
    float f = dht.readTemperature(true);
    Serial.print("f= ");
    Serial.print(f);
    Serial.print(" h= ");
    Serial.println(h);
    hsum = h + hsum;
    fsum = f + fsum;
    Serial.print("fsum= ");
    Serial.print(fsum);
    Serial.print(" hsum= ");
    Serial.println(hsum);
    analogWrite(WHITE, 10);
    delay(6000);
  }
  
  analogWrite(WHITE, 0);
  analogWrite(BLUE, 50);
  h = hsum / 10;
  f = fsum / 10;
  Serial.println("Sending");
  Serial.print("f= ");
  Serial.print(f);
  Serial.print(" h= ");
  Serial.println(h);
  ThingSpeak.setField(1, f);
  ThingSpeak.setField(2, h);
  ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
  fsum = 0;
  hsum = 0;
  delay(100);
  analogWrite(BLUE, 0);
}


The resulting code is cleaner but it doesn’t really accomplish anything new. Oh well, this seems like the smarter, more sophisticated way to achieve the same task.

Continue reading “Arduino, Thingspeak & an ESP8266 (Part IV)”

Arduino, Thingspeak & an ESP8266 (Part III)

Second Revision

So my first attempt worked, but it wasn’t robust at all as it relied on the accuracy of a single reading. Since random air currents, electrical noise, and ghosts (maybe? probably not) can all cause strange readings, the data being sent to Thingspeak was pretty noisy. In reality my last sketch only worked right “most” of the time. Clearly something needed to be done!

#include <ThingSpeak.h>
#include <ESP8266WiFi.h>
#include <DHT.h>

#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht (DHTPIN, DHTTYPE);

const char* ssid = "ssid";
const char* pass = "password";
const int RED = 15;
const int WHITE = 14;
const int GREEN = 13;
const int BLUE = 12;

int i = 0;
int c = 0;
float h = 0;
float f = 0;
float hsum = 0;
float fsum = 0;

unsigned long myChannelNumber = "channel number";
const char* myWriteAPIKey = "API Key";
WiFiClient client;

void setup() {
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);
  pinMode(WHITE, OUTPUT);

  Serial.begin(9600);
  delay(10);
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    analogWrite(RED, 75);
    delay(500);
    Serial.print(".");
  }

  if (WiFi.status() == WL_CONNECTED) {
    analogWrite(RED, 0);
    analogWrite(BLUE, 75);
    delay(100);
    analogWrite(BLUE, 0);
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  ThingSpeak.begin(client);

}

void loop() {
  analogWrite(WHITE, 50);
  
  Serial.print("c= ");
  Serial.println(c);
  float h = dht.readHumidity();
  float f = dht.readTemperature(true);
  Serial.print("f= ");
  Serial.print(f);
  Serial.print(" h= ");
  Serial.println(h);
  
  hsum = h + hsum;
  fsum = f + fsum;
  Serial.print("fsum= ");
  Serial.print(fsum);
  Serial.print(" hsum= ");
  Serial.println(hsum);
  
  c = c + 1;
  
  analogWrite(WHITE, 10);
  delay(6000);
  
  if (c >= 10) {
    analogWrite(BLUE, 75);
    h = hsum / 10;
    f = fsum / 10;
    Serial.println("Sending");
    Serial.print("f= ");
    Serial.print(f);
    Serial.print(" h= ");
    Serial.println(h);
    ThingSpeak.setField(1, f);
    ThingSpeak.setField(2, h);
    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
    fsum = 0;
    hsum = 0;
    delay(100);
    analogWrite(BLUE, 0);
  }
  else {
    return;
  }
  c = 0;
}


The operation of this sketch is slightly more complex.

  1. Connect to WiFi
  2. Measure temperature and humidity in to variables f and h.
  3. Add f and h to fsum and hsum, respectively
  4. Repeat 2 & 3 ten times
  5. Divide fsum and hsum by 10 and store the results if f and h.
  6. Send variables f and h to two channels on Thingspeak.
  7. Repeat

Really all this does is take 10 sampless (one per second) and then average them before sending the numbers to Thingspeak. Though simple, this actually works pretty well, but it isn’t terribly easy to fine tune and can still be thrown off by extremely bad readings… Since the DHT-11 will sometimes report an erroneous zero, this isn’t a perfect solution. That said, if I increased the number of samples that it took, I wouldn’t be surprised if I could make this approach work fine.

Incidentally if I had seen it when I was writing this, I could have used this method to create a far more elegant running average. Oh well, I took a somewhat different approach eventually.

Continue reading “Arduino, Thingspeak & an ESP8266 (Part III)”

Arduino, Thingspeak & an ESP8266 (Part II)

First Revision

I always tell students that revision is the longest part of the writing process. From my (limited) experience the same thing is true when working with Arduino. It only took me an hour to hack something together out of various examples. It works. It isn’t robust or fancy, but there was a kind of elegance to its simplicity. Since then I’ve spent at least another 15 hours making relatively minor changes.

Here is the first draft of my Sketch.

#include <ThingSpeak.h>
#include <ESP8266WiFi.h>
#include <DHT.h>
#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht (DHTPIN, DHTTYPE);

const char* ssid = "ssid";
const char* pass = "password";
const int RED = 15;
const int WHITE = 14;
const int GREEN = 13;
const int BLUE = 12;

int i = 0;

unsigned long myChannelNumber = "channel number";
const char* myWriteAPIKey = "write api key";
WiFiClient client;

void setup() {
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);
  pinMode(WHITE, OUTPUT);
  Serial.begin(9600);
  delay(10);
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);  
  
  while (WiFi.status() != WL_CONNECTED) {
    analogWrite(RED, 175); 
    delay(500);
    Serial.print(".");
  }
  
  if (WiFi.status() == WL_CONNECTED) {
    analogWrite(RED, 0);
    analogWrite(BLUE, 75);
  }
  
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  ThingSpeak.begin(client);

}

void loop() {
    for (int i = 10; i < 255; i++){
    analogWrite(WHITE, i);
    delay(20);
  }
 
  while (WiFi.status() != WL_CONNECTED) {
    analogWrite(RED, 175); 
    Serial.print(".");
    delay(1000);
    analogWrite(RED, 0);
  }

  
  if (WiFi.status() == WL_CONNECTED) {
    delay(1000);
    analogWrite(BLUE, 150);
    delay(1000);
    analogWrite(BLUE, 0);
  }

 delay(1000);
  
  float h = dht.readHumidity();
  float f = dht.readTemperature(true); 
  
  if (isnan(h) || isnan(f)) {
    analogWrite(RED, 175);
    delay(1000);
    analogWrite(RED, 0);
  }
  else {
    analogWrite(GREEN, 100);
    delay(1000);
    analogWrite(GREEN, 0);
  }

  Serial.print("h= ");
  Serial.print(h);
  Serial.print(" f= ");
  Serial.println(f);

   for (int i = 255; i > 10; i--){
    analogWrite(WHITE, i);
    delay(20);
  }
    

  delay(60000);


}

The operation of this sketch is pretty simple:

  1. Connect to WiFi
  2. Measure temperature and humidity in to variables f and h.
  3. Send variables f and h to two channels on Thingspeak.
  4. Do nothing for a minute.
  5. Repeat

The biggest problem with this sketch is that the DHT-11 is not exactly a reliable device. Sometimes it simply takes a bad reading–like a random zero.  When that bad measurement is sent to thingspeak it adds significant noise to the graphs

The next revision will attempt to deal with this through a little simple math.

Continue reading “Arduino, Thingspeak & an ESP8266 (Part II)”

Arduino, Thingspeak & an ESP8266 (Part I)

I’ve been interested in working with Arduino for years, but I never could come up with a practical use of it. Since I’m one of those people who needs an excuse to start a project (even though, lets face it, it can be a pretty thin one), this was a major problem. However, with the recent porting of Arduino to the ESP8266 (a wifi-enabled microcontroller), I finally found a use.

You see, I have long wanted to track the historical temperature of my apartment to test to see if various changes (insulation, opening the windows for more of the day etc.) actually make a difference.  Plus there is just something that I think is nifty about temperature graphs!

Screenshot from 2016-07-05 21:19:25
Figure 1: If temperature graphs don’t look inherently nifty to you, we are very different people

The ESP8266 is the perfect platform for this kind of project because it is easy to hook-up to a DHT-11 (or other temperature / humidity sensor) and can easily be hooked up through wifi to an external server for logging data.  To make matters even easier there are several different cheap development boards on Ebay which have an ESP8266 and a DHT-11 already installed! Since I’m more interested in programming than in breadboarding, it seemed like an ideal way to break into Arduino. The one I ended up using is described in this super useful blog post. (Big thanks to the author of that post and also Scott Snowden.)

The only question was how should I store the data? For a long time I planned on using RDDTool and some kind of http get or maybe MQTT  to transfer the data to a local server. That would probably work great, but I wanted something simpler because I had a vague ambition of giving one of these to my father as a birthday present… since he wouldn’t be able to run his own server, I needed a cloud based solution.

After looking around for a bit, I finally settled on Thingspeak because they allow for basically unlimited data retention… that is pretty cool when you are hoping to graph temperature data over years!

Anyway, I now have a sketch that is working great, but instead of just jumping into that I am going to post each major version I made of the sketch. My hope is that it will be interesting for people who know more than I do to see how a novice (with basically a smattering of BASH and Python, no C experience at all) slowly learns how to better code in Arduino. Also, it is more grist for the blog mill, amiright?