-->
Page 1 of 1

Feather Huzzah Weather Station

PostPosted: Fri Sep 01, 2017 9:58 am
by 556duckvader
I am building my own personal weather station with using a Davis Anemometer and I have almost everything functioning correctly but I can't seem to get it to read the wind speed correctly. I can read the wind direction just fine but one the wind speed it looks like it just counting the number of rotations and not reseting it like its supposed to so. Below is a code that I am using. If someone could please look at this and see what I am not seeing that would be great. I have included a screen shot of the output as well.

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-------------------//
volatile 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     = "XXXX";
const char* password = "XXXXX";
//const char* ssid     = "XXXXXX";
//const char* password = "XXXXXX";

//--------------------WU PWS ID Info-------------------//
const char* WUID    = "XXXXX";
const char* WUPASS   = "XXXXX";
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;
    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;

  lastDirValue = 0;

  IsSampleRequired = false;
  isr_timer();

  // setup anemometer values
  rotations = 0;

  startwifi();
  Wire.begin();
  if (!bme.begin()) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    ESP.restart();
  }

  //if (!uv.begin()) {
  //Serial.println("Could not find a valid Si1145 sensor, check wiring!");
  //ESP.restart();
  //}

  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 Direction-------------------//
  getWindDirection();

  // Only update the display if change greater than 5 degrees.
  if (abs(calDirection - lastDirValue) > 5)
  {
    lastDirValue = calDirection;
  }
  //--------------------Get Wind Speed-------------------//
  getWindSpeed();
 
  // 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 / 100.00;
    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();
  }
}