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;
}