So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By 556duckvader
#69871 Hello,
I am working on a project that I am using an ESP8266 as a weather station that is reading temp, UV, wind speed, wind direction, and rain fall. I have most of it working but I am having issues with the anemometer and the wind speed not being correct. When I look at the serial console the wind speed looks to be just reading the number of rotations without resetting. I have a feeling it has something to do with the interrupt but I am not sure. Below is the current code that I am using. If anyone would be able to help me figure out my issue that would be great. Thanks for your help.

Code: Select all#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_SI1145.h>
#include <Adafruit_ADS1015.h>
#include <EEPROM.h>
#include <math.h>

extern "C" {
#include "user_interface.h"
}

#define SEALEVELPRESSURE_HPA (1013.25)

//--------------------GPIO Pin Map-------------------/
#define WindSensorPin (14)      // The pin location of the anemometer sensor
//#define WindVanePin ads.readADC_SingleEnded(0)       // The pin the wind vane sensor is connected to
#define vaneOffset 40        // define the anemometer offset from magnetic north

//--------------------ADS1115 Setup-------------------//
Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */

//--------------------BME280 Setup-------------------//
Adafruit_BME280 bme; // I2C

//--------------------SI11145 Setup-------------------//
Adafruit_SI1145 uv = Adafruit_SI1145();

//--------------------GPIO Pin Map-------------------/
int dataLED = 2;    //Sending Data LED
int statusLED = 0;    //Sending Data LED

//--------------------Program Variables-------------------//
//volatile unsigned long tipCount;    // bucket tip counter used in interrupt routine
volatile unsigned long contactTime; // Timer to manage any contact bounce in interrupt routine

volatile bool IsSampleRequired;       // this is set true every 2.5s. Get wind speed
volatile unsigned long rotations;     // cup rotation counter used in interrupt routine
volatile unsigned long contactBounceTime;  // Timer to avoid contact bounce in interrupt routine

//long lastTipcount;            // keeps track of bucket tips
//float totalRainfall;       // total amount of rainfall detected
float raincount = 0.00;
float raincount1h = 0.00;

unsigned long count5sec;
unsigned long count60sec;
unsigned long count5min;
unsigned long count1h;

String eepromstring = "0.00";

float windSpeed_sum = 0.00f;
float windDir_sum = 0.00f;
float sensor_count = 0.00f;
float tempOut_sum = 0.00f;
float humidity_sum = 0.00f;
float baro_sum = 0.00f;
float uvIndex_sum = 0.00f;
float pressure;

int temp_offset = 0;    // Temp Offset
int humi_offset = 0;    // Humidity Offset

//--------------------Weather Variables-------------------//
float windSpeed;
int vaneValue;       // raw analog value from wind vane
int vaneDirection;   // translated 0 - 360 direction
int calDirection;    // converted value with offset applied
int lastDirValue;    // last recorded direction value

// arayas we use for averaging sensor data
float temps[12];    // array of 12 temps to create a 2 minute average temp
float wspeeds[24];  // array of 24 wind speeds for 2 minute average wind speed
float wdirect[24];  // array of 24 wind directions for 2 minute average

float windSpeed_raw;
float windDir_raw;
float tempOut_raw;
float dewOut_raw;
float humidity_raw;
float baro_raw;
float uvIndex_raw;
float rain1h_raw;
float rain24h_raw;


//US
String windSpeedUS;
String windDirUS;
String tempOutUS;
String dewOutUS;
String humidityUS;
String baroUS;
String uvIndexUS;
String rain1hUS;
String rain24hUS;

//--------------------Wifi Variables-------------------//
const char* ssid     = "XX";
const char* password = "XX";

//--------------------WU PWS ID Info-------------------//
const char* WUID    = "XX";
const char* WUPASS   = "XX";
const char* host = "weatherstation.wunderground.com";

//--------------------NTP Variables-------------------//
unsigned int localPort = 2390;
IPAddress timeServerIP;
const char* ntpServerName = "time.nist.gov";
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[ NTP_PACKET_SIZE];
WiFiUDP udp;
unsigned long epoch;

//--------------------UDP NTP Setup-------------------//
void startudp()
{
  Serial.println("Starting UDP");
  udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(udp.localPort());
}

//--------------------Wifi Setup-------------------//
void startwifi()
{
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

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

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

  startudp();
}

//--------------------Send Data To WU-------------------//
void senddata()
{
  pinMode(dataLED, OUTPUT);
  digitalWrite(dataLED, LOW);

  Serial.println("Sending Data to WU");
  Serial.print("connecting to ");
  Serial.println(host);

  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    startwifi();
    return;
  }

  // We now create a URI for the request
  String url = "/weatherstation/updateweatherstation.php?ID=";
  url += WUID;
  url += "&PASSWORD=";
  url += WUPASS;
  url += "&dateutc=now";
  url += "&winddir=";
  url += windDirUS;
  url += "&windspeedmph=";
  url += windSpeedUS;
  url += "&humidity=";
  url += humidityUS;
  url += "&rainin=";
  url += rain1hUS;
  url += "&dailyrainin=";
  url += rain24hUS;
  url += "&tempf=";
  url += tempOutUS;
  url += "&baromin=";
  url += baroUS;
  url += "&dewptf=";
  url += dewOutUS;
  url += "&weather=&clouds=&softwaretype=Arduino-ESP8266&action=updateraw";

  Serial.print("Requesting URL: ");
  Serial.println(url);

  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  delay(10);

  // Read all the lines of the reply from server and print them to Serial
  while (client.available()) {
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }

  Serial.println();
  Serial.println("closing connection");
  digitalWrite(dataLED, HIGH);

  //wifi_set_sleep_type(NONE_SLEEP_T);
  //wifi_set_sleep_type(MODEM_SLEEP_T);
  wifi_set_sleep_type(LIGHT_SLEEP_T);
}

//--------------------NTP Request-------------------//
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();
}

//--------------------NTP Time-------------------//
unsigned long ntptime()
{
  WiFi.hostByName(ntpServerName, timeServerIP);
  sendNTPpacket(timeServerIP);
  delay(1000);

  int cb = udp.parsePacket();
  if (!cb) {
    Serial.println("no NTP packet yet");
  }
  else {
    Serial.print("NTP 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;
    // now convert NTP time into everyday time:
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    epoch = secsSince1900 - seventyYears;
  }
}

int localhour()
{
  return (((epoch - (3600 * 5))  % 86400L) / 3600);
}

int localmin()
{
  return (((epoch - (3600 * 5))  % 3600) / 60);
}

int localsec()
{
  return ((epoch - (3600 * 5)) % 60);
}
//--------------------EEPROM-------------------//
void eepromSet(String name, String value) {
  Serial.println("eepromSet");

  String list = eepromDelete(name);
  String nameValue = "&" + name + "=" + value;
  //Serial.println(list);
  //Serial.println(nameValue);
  list += nameValue;
  for (int i = 0; i < list.length(); ++i) {
    EEPROM.write(i, list.charAt(i));
  }
  EEPROM.commit();
  Serial.print(name);
  Serial.print(":");
  Serial.println(value);
}

String eepromDelete(String name) {
  Serial.println("eepromDelete");

  int nameOfValue;
  String currentName = "";
  String currentValue = "";
  int foundIt = 0;
  char letter;
  String newList = "";
  for (int i = 0; i < 512; ++i) {
    letter = char(EEPROM.read(i));
    if (letter == '\n') {
      if (foundIt == 1) {
      } else if (newList.length() > 0) {
        newList += "=" + currentValue;
      }
      break;
    } else if (letter == '&') {
      nameOfValue = 0;
      currentName = "";
      if (foundIt == 1) {
        foundIt = 0;
      } else if (newList.length() > 0) {
        newList += "=" + currentValue;
      }


    } else if (letter == '=') {
      if (currentName == name) {
        foundIt = 1;
      } else {
        foundIt = 0;
        newList += "&" + currentName;
      }
      nameOfValue = 1;
      currentValue = "";
    }
    else {
      if (nameOfValue == 0) {
        currentName += letter;
      } else {
        currentValue += letter;
      }
    }
  }
  for (int i = 0; i < 512; ++i) {
    EEPROM.write(i, '\n');
  }
  EEPROM.commit();
  for (int i = 0; i < newList.length(); ++i) {
    EEPROM.write(i, newList.charAt(i));
  }
  EEPROM.commit();
  Serial.println(name);
  Serial.println(newList);
  return newList;
}
void eepromClear() {
  Serial.println("eepromClear");
  for (int i = 0; i < 512; ++i) {
    EEPROM.write(i, '\n');
  }
}
String eepromList() {
  Serial.println("eepromList");
  char letter;
  String list = "";
  for (int i = 0; i < 512; ++i) {
    letter = char(EEPROM.read(i));
    if (letter == '\n') {
      break;
    } else {
      list += letter;
    }
  }
  Serial.println(list);
  return list;
}
String eepromGet(String name) {
  Serial.println("eepromGet");

  int nameOfValue;
  String currentName = "";
  String currentValue = "";
  int foundIt = 0;
  String value = "";
  char letter;
  for (int i = 0; i < 512; ++i) {
    letter = char(EEPROM.read(i));
    if (letter == '\n') {
      if (foundIt == 1) {
        value = currentValue;
      }
      break;
    } else if (letter == '&') {
      nameOfValue = 0;
      currentName = "";
      if (foundIt == 1) {
        value = currentValue;
        break;
      }
    } else if (letter == '=') {
      if (currentName == name) {
        foundIt = 1;
      } else {
      }
      nameOfValue = 1;
      currentValue = "";
    }
    else {
      if (nameOfValue == 0) {
        currentName += letter;
      } else {
        currentValue += letter;
      }
    }
  }
  Serial.print(name);
  Serial.print(":");
  Serial.println(value);
  return value;
}

// isr routine for timer interrupt
os_timer_t timerCount;

// start of timerCallback
void timerCallback(void *pArg) {

  IsSampleRequired = true;

} // End of timerCallback

void isr_timer(void) {
  os_timer_setfn(&timerCount, timerCallback, NULL);
  os_timer_arm(&timerCount, 2000, true);
} // End of user_init


// interrupt handler to increment the rotation count for wind speed
void isr_rotation ()   {

  if ((millis() - contactBounceTime) > 15 ) {  // debounce the switch contact.
    rotations++;
    contactBounceTime = millis();
  }
}

//--------------------Get Wind Direction-------------------//
void getWindDirection() {

  vaneValue = ads.readADC_SingleEnded(0);
  vaneDirection = map(vaneValue, 0, 17430, 0, 360);
  calDirection = vaneDirection + vaneOffset;

  if (calDirection > 360)
    calDirection = calDirection - 360;

  if (calDirection < 0)
    calDirection = calDirection + 360;

}

//--------------------Get Wind Speed-------------------//
void getWindSpeed() {
  if (IsSampleRequired)
  {
    // convert to mp/h using the formula V=P(2.25/T)
    // V = P(2.25/2.5) = P * 0.9
    windSpeed = rotations * 0.9;
    rotations = 0; // Reset count for next sample
    IsSampleRequired = false;

  }
}
void setup() {

  pinMode(WindSensorPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(WindSensorPin), isr_rotation, FALLING);

  //wifi_set_sleep_type(NONE_SLEEP_T);
  //wifi_set_sleep_type(MODEM_SLEEP_T);
  wifi_set_sleep_type(LIGHT_SLEEP_T);
  Serial.begin(115200);
  Serial.println("");
  Serial.print("Starting Weather Station ");
  Serial.println(WUID);
 
  //--------------------Setup Rain Sensor Values-------------------//
  //lastTipcount = 0;
  //tipCount = 0;
  //totalRainfall = 0;

  IsSampleRequired = false;
  isr_timer();

  //--------------------Setup Anemometer Values-------------------//
  lastDirValue = 0;
  //rotations = 0;

  startwifi();
  Wire.begin();
  //--------------------Check If BME280 Is Connected-------------------//
  if (!bme.begin()) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    ESP.restart();
  }
  //--------------------Check If UV Is Connected-------------------//
  if (!uv.begin()) {
    Serial.println("Could not find a valid Si1145 sensor, check wiring!");
    ESP.restart();
  }
  //--------------------Start ADC-------------------//
  ads.begin();

  EEPROM.begin(512);

  //RESET EEPROM CONTENT - ONLY EXECUTE ONE TIME - AFTER COMMENT
  Serial.println("CLEAR ");
  eepromClear();
  Serial.println("SET ");
  eepromSet("raincount", "0.00");
  eepromSet("raincount1h", "0.00");
  Serial.println("LIST ");
  Serial.println(eepromList());
  //END - RESET EEPROM CONTENT - ONLY EXECUTE ONE TIME - AFTER COMMENT

  //GET STORED RAINCOUNT IN EEPROM
  Serial.println("GET EEPROM");
  eepromstring = eepromGet("raincount");
  raincount = eepromstring.toFloat();
  Serial.print("RAINCOUNT VALUE FROM EEPROM: ");
  Serial.println(raincount);
  eepromstring = eepromGet("raincount1h");
  raincount1h = eepromstring.toFloat();
  Serial.print("RAINCOUNT1H VALUE FROM EEPROM: ");
  Serial.println(raincount1h);
  //END - GET STORED RAINCOUNT IN EEPROM

  if (raincount1h == 0)
  {
    count1h = millis();
  }
  count60sec = millis();

  sei();// Enable Interrupts
}

void loop() {
  // Blink red LED to verify device is on
  pinMode(statusLED, OUTPUT);
  digitalWrite(statusLED, LOW);
  delay(50);
  digitalWrite(statusLED, HIGH);
  delay(50);
  digitalWrite(statusLED, LOW);
  delay(50);
  digitalWrite(statusLED, HIGH);
  delay(150000);

  //--------------------Get Wind Speed-------------------//
  getWindSpeed();
  //--------------------Get Wind Direction-------------------//
  getWindDirection();

  // Only update the display if change greater than 5 degrees.
  if (abs(calDirection - lastDirValue) > 5)
  {
    lastDirValue = calDirection;
  }
 
  // update rainfall total if required
  //  if (tipCount != lastTipcount) {
  //    cli();  // disable intterupts
  //    lastTipcount = tipCount;
  //    totalRainfall = tipCount * Bucket_Size;
  //    sei();  // enable interrupts
  //  }

  if ((millis() - count5sec) >= 5000)
  {
    windSpeed_sum = windSpeed_sum + windSpeed;
    windDir_sum = windDir_sum + calDirection;
    tempOut_sum = tempOut_sum + ( bme.readTemperature() + temp_offset );
    humidity_sum = humidity_sum + ( bme.readHumidity() + humi_offset );
    baro_sum = baro_sum + ( bme.readPressure() / 100.00f );
    uvIndex_sum = uvIndex_sum + uv.readUV();
    sensor_count = sensor_count + 1.00f;
    count5sec = millis();
  }

  if ((millis() - count60sec) >= 60000)
    //if ((millis() - count5min) >= 300000)
  {
    ntptime();
    Serial.println("");
    Serial.println("Actual Local Time:");
    Serial.print("Hour: ");
    Serial.println(localhour());
    Serial.print("Min: ");
    Serial.println(localmin());
    Serial.print("Sec: ");
    Serial.println(localsec());
    Serial.println("");
    Serial.println("Convert and store all sensor value for WU each 5min");

    //reset Daily Rain each 24h
    if ((localhour() >= 23) && (localmin() >= 55))
    {
      Serial.println("Reset Daily Rain");
      raincount = 0;
      rain24h_raw = 0.00;
    }

    //Get All Values of Sensor
    windDir_raw = windDir_sum;
    windSpeed_raw = windSpeed_sum;
    tempOut_raw = tempOut_sum / sensor_count;
    humidity_raw = humidity_sum / sensor_count;
    dewOut_raw = ( tempOut_raw - ((100.00f - humidity_raw) / 5.00f) );
    baro_raw = baro_sum / sensor_count;
    uvIndex_raw = uvIndex_sum / sensor_count;
    rain1h_raw = 0.80f * raincount1h;
    rain24h_raw = 0.800f * raincount;
    windDir_sum = 0.00f;
    tempOut_sum = 0.00f;
    humidity_sum = 0.00f;
    baro_sum = 0.00f;
    uvIndex_sum = 0.00f;
    sensor_count = 0.00f;

    //Make conversion to US for Wunderground
    windDirUS = windDir_raw;
    windSpeedUS = windSpeed_raw;
    tempOutUS = (tempOut_raw * 1.8 + 32);
    dewOutUS = (dewOut_raw * 1.8 + 32);
    humidityUS = humidity_raw;
    baroUS = 0.02952998307 * baro_raw;
    uvIndexUS = uvIndex_raw / 100.00;
    rain1hUS = rain1h_raw / 25.40 ;
    rain24hUS = rain24h_raw / 25.40 ;

    Serial.println(" ");
    Serial.println("US:  ");
    Serial.print("Temp: ");
    Serial.println(tempOutUS);
    Serial.print("Dew Point: ");
    Serial.println(dewOutUS);
    Serial.print("Humidity: ");
    Serial.println(humidityUS);
    Serial.print("Pressure: ");
    Serial.println(baroUS);
    Serial.print("UV Index: ");
    Serial.println(uvIndexUS);
    Serial.print("Wind Speed: ");
    Serial.println(windSpeedUS);
    Serial.print("Wind Direction: ");
    Serial.println(windDirUS);
    Serial.print("Rain 1h: ");
    Serial.println(rain1hUS);
    Serial.print("Rain 24h: ");
    Serial.println(rain24hUS);
    Serial.println(" ");
    Serial.println("Send Data to WU each 5min");
    //STORE RAINCOUNT IN EEPROM
    Serial.println("SET EEPROM");
    eepromstring = String(raincount, 2);
    eepromSet("raincount", eepromstring);
    eepromstring = String(raincount1h, 2);
    eepromSet("raincount1h", eepromstring);
    //END - STORE RAINCOUNT IN EEPROM

    //senddata();  //Uncomment this to send data to WU

    count60sec = millis();
    //count5min = millis();
  }
  if ( ((millis() - count1h) >= (60000 * 60 * 1)) && (raincount1h != 0))
  {
    Serial.println("Reset hourly rain each hour");
    raincount1h = 0;
    rain1h_raw = 0.00;
  }

  if ( millis() >= (60000 * 60 * 24 * 3))
  {
    Serial.println("task each week");
    ESP.restart();
  }
}