Hi all,
I am working on this code lot of hours.
The electron reads some sensors, but the problem is in the wind readings. This measurement returns all zero. I would like to read the wind and direction during 30 seconds, but I did not know how to do it
I’m desperate, tired and I’m looking for somebody could help me to find why did not work.
Thank’s for your support.
Thank’s
SYSTEM_MODE(SEMI_AUTOMATIC)
SYSTEM_THREAD(ENABLED)
#include <SparkFun_Photon_Weather_Shield_Library.h>
#include <math.h>
// Each time we loop through the main loop, we check to see if it's time to capture the sensor readings
unsigned int sensorCapturePeriod = 100;
unsigned int timeNextSensorReading;
// Each time we loop through the main loop, we check to see if it's time to publish the data we've collected
unsigned int publishPeriod = 90000;
unsigned int timeNextPublish;
const int sleepPeriode = 4 * 60;
void setup() {
initializeRainGauge();
initializeAnemometer();
initializeWindVane();
}
void loop() {
Particle.connect();
Particle.publish("weatherstation", "start", 60, PRIVATE);
/////////power on led switch
digitalWrite(D7, HIGH);
//Timestamp
float vtime = Time.now();
String Svtime = String(vtime);
///////////////////////// Sparkfun Weather Station /////////////////////////
float rainmm = getAndResetRainInches()*25.4;
float gustKPH;
float windKPH = (getAndResetAnemometerkph(&gustKPH))*1.609;
float knots = windKPH * 0.5399;
float windDegrees = getAndResetWindVaneDegrees();
//Sparkfun Weather station
String SPKwind = String(windKPH);
String SPKdegrees = String(windDegrees);
String SPKrain = String(rainmm);
String SPKgust = String(gustKPH);
String SPKknots = String(knots);
//Particle.connect();
//if (waitFor(Particle.connected, 300000 ))
// { // proceede only if a connection could be established within 60 seconds
//////////////////////////////////Building JSON3///////////////////////////////////
String dest2 = "{";
if (Svtime.length() != 0) { dest2 = dest2 + "\"1\":\"" + "1" + "\","; }
if (Svtime.length() != 0) { dest2 = dest2 + "\"31\":\"" + SPKrain + "\","; }
if (Svtime.length() != 0) { dest2 = dest2 + "\"32\":\"" + SPKgust + "\","; }
if (Svtime.length() != 0) { dest2 = dest2 + "\"33\":\"" + SPKwind + "\","; }
if (Svtime.length() != 0) { dest2 = dest2 + "\"34\":\"" + SPKknots + "\","; }
if (Svtime.length() != 0) { dest2 = dest2 + "\"35\":\"" + SPKdegrees + "\""; }
dest2 = dest2 + "}";
delay(5000);
Particle.publish("weatherstation", dest2, 60, PRIVATE);
delay(10);
//}
System.sleep(SLEEP_MODE_DEEP, sleepPeriode, SLEEP_NETWORK_STANDBY); //Sleep a while to save battery
}
Weather sensor;
//===========================================================================
// Rain Guage
//===========================================================================
int RainPin = D2;
volatile unsigned int rainEventCount;
unsigned int lastRainEvent;
float RainScaleInches = 0.011; // Each pulse is .011 inches of rain
void initializeRainGauge() {
pinMode(RainPin, INPUT_PULLUP);
rainEventCount = 0;
lastRainEvent = 0;
attachInterrupt(RainPin, handleRainEvent, FALLING);
return;
}
void handleRainEvent() {
// Count rain gauge bucket tips as they occur
// Activated by the magnet and reed switch in the rain gauge, attached to input D2
unsigned int vtimeRainEvent = millis(); // grab current time
// ignore switch-bounce glitches less than 10mS after initial edge
if (vtimeRainEvent - lastRainEvent < 10) {
return;
}
rainEventCount++; //Increase this minute's amount of rain
lastRainEvent = vtimeRainEvent; // set up for next event
}
float getAndResetRainInches()
{
float result = RainScaleInches * float(rainEventCount);
rainEventCount = 0;
return result;
}
//===========================================================================
// Wind Speed (Anemometer)
//===========================================================================
// The Anemometer generates a frequency relative to the windspeed. 1Hz: 2.4 kph
// We measure the average period (elaspsed time between pulses), and calculate the average windspeed since the last recording.
int AnemometerPin = D3;
float AnemometerScalekph = 2.4; // Windspeed if we got a pulse every second (i.e. 1Hz)
volatile unsigned int AnemoneterPeriodTotal = 0;
volatile unsigned int AnemoneterPeriodReadingCount = 0;
volatile unsigned int GustPeriod = UINT_MAX;
unsigned int lastAnemoneterEvent = 0;
void initializeAnemometer() {
pinMode(AnemometerPin, INPUT_PULLUP);
AnemoneterPeriodTotal = 0;
AnemoneterPeriodReadingCount = 0;
GustPeriod = UINT_MAX; // The shortest period (and therefore fastest gust) observed
lastAnemoneterEvent = 0;
attachInterrupt(AnemometerPin, handleAnemometerEvent, FALLING);
return;
}
void handleAnemometerEvent() {
// Activated by the magnet in the anemometer (2 ticks per rotation), attached to input D3
unsigned int vtimeAnemometerEvent = millis(); // grab current time
//If there's never been an event before (first time through), then just capture it
if (lastAnemoneterEvent != 0) {
// Calculate time since last event
unsigned int period = vtimeAnemometerEvent - lastAnemoneterEvent;
// ignore switch-bounce glitches less than 10mS after initial edge (which implies a max windspeed of 149kph)
if (period < 10) {
return;
}
if (period < GustPeriod) {
// If the period is the shortest (and therefore fastest windspeed) seen, capture it
GustPeriod = period;
}
AnemoneterPeriodTotal += period;
AnemoneterPeriodReadingCount++;
}
lastAnemoneterEvent = vtimeAnemometerEvent; // set up for next event
}
float getAndResetAnemometerkph(float * gustKPH)
{
if (AnemoneterPeriodReadingCount == 0)
{
*gustKPH = 0.0;
return 0;
}
// Nonintuitive math: We've collected the sum of the observed periods between pulses, and the number of observations.
// Now, we calculate the average period (sum / number of readings), take the inverse and muliple by 1000 to give frequency, and then mulitply by our scale to get kph.
// The math below is transformed to maximize accuracy by doing all muliplications BEFORE dividing.
float result = AnemometerScalekph * 1000.0 * float(AnemoneterPeriodReadingCount) / float(AnemoneterPeriodTotal);
AnemoneterPeriodTotal = 0;
AnemoneterPeriodReadingCount = 0;
*gustKPH = AnemometerScalekph * 1000.0 / float(GustPeriod);
GustPeriod = UINT_MAX;
return result;
}
//===========================================================
// Wind Vane
//===========================================================
void initializeWindVane() {
return;
}
// For the wind vane, we need to average the unit vector components (the sine and cosine of the angle)
int WindVanePin = A0;
float windVaneCosTotal = 0.0;
float windVaneSinTotal = 0.0;
unsigned int windVaneReadingCount = 0;
void captureWindVane() {
// Read the wind vane, and update the running average of the two components of the vector
unsigned int windVaneRaw = analogRead(WindVanePin);
float windVaneRadians = lookupRadiansFromRaw(windVaneRaw);
if (windVaneRadians > 0 && windVaneRadians < 6.14159)
{
windVaneCosTotal += cos(windVaneRadians);
windVaneSinTotal += sin(windVaneRadians);
windVaneReadingCount++;
}
return;
}
float getAndResetWindVaneDegrees()
{
if (windVaneReadingCount == 0) {
return 0;
}
float avgCos = windVaneCosTotal / float(windVaneReadingCount);
float avgSin = windVaneSinTotal / float(windVaneReadingCount);
float result = atan(avgSin / avgCos) * 180.0 / 3.14159;
windVaneCosTotal = 0.0;
windVaneSinTotal = 0.0;
windVaneReadingCount = 0;
// atan can only tell where the angle is within 180 degrees. Need to look at cos to tell which half of circle we're in
if (avgCos < 0) result += 180.0;
// atan will return negative angles in the NW quadrant -- push those into positive space.
if (result < 0) result += 360.0;
return result;
}
float lookupRadiansFromRaw(unsigned int analogRaw)
{
// The mechanism for reading the weathervane isn't arbitrary, but effectively, we just need to look up which of the 16 positions we're in.
if (analogRaw >= 2200 && analogRaw < 2400) return (3.14);//South
if (analogRaw >= 2100 && analogRaw < 2200) return (3.53);//SSW
if (analogRaw >= 3200 && analogRaw < 3299) return (3.93);//SW
if (analogRaw >= 3100 && analogRaw < 3200) return (4.32);//WSW
if (analogRaw >= 3890 && analogRaw < 3999) return (4.71);//West
if (analogRaw >= 3700 && analogRaw < 3780) return (5.11);//WNW
if (analogRaw >= 3780 && analogRaw < 3890) return (5.50);//NW
if (analogRaw >= 3400 && analogRaw < 3500) return (5.89);//NNW
if (analogRaw >= 3570 && analogRaw < 3700) return (0.00);//North
if (analogRaw >= 2600 && analogRaw < 2700) return (0.39);//NNE
if (analogRaw >= 2750 && analogRaw < 2850) return (0.79);//NE
if (analogRaw >= 1510 && analogRaw < 1580) return (1.18);//ENE
if (analogRaw >= 1580 && analogRaw < 1650) return (1.57);//East
if (analogRaw >= 1470 && analogRaw < 1510) return (1.96);//ESE
if (analogRaw >= 1900 && analogRaw < 2000) return (2.36);//SE
if (analogRaw >= 1700 && analogRaw < 1750) return (2.74);//SSE
if (analogRaw > 4000) return(-1); // Open circuit? Probably means the sensor is not connected
Particle.publish("error", String::format("Got %d from Windvane.", analogRaw), 60, PRIVATE);
return -1;
}