Code Verification/Troubleshooting for Weather Station
Posted: Mon Sep 11, 2017 12:20 am
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.
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();
}
}