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)”