Values not publishing if I sleep the machine

Hi I’m using as a base the Sparkfun weather station and I have a problem when I modify the code.

I could not leave the machine always open and I put in sleep mode. The problem is when I put in sleep the data from wind, direction etc did is 0, if I put in delay the data is received ok.

Thank’s

#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 = 5 * 60; 

void setup() {

    initializeTekphumidityAndPressure();
    initializeRainGauge();
    initializeAnemometer();
    initializeWindVane();

    // Schedule the next sensor reading and publish events
    timeNextSensorReading = millis() + sensorCapturePeriod;
    timeNextPublish = millis() + publishPeriod; 
}

void loop() {

        
        ///////////////////////// Sparkfun Weather Station /////////////////////////
        float wstempC = getAndResetTempF();
        float wshumidityRH = getAndResetHumidityRH();
        float wspressureHPa = getAndResetPressurePascals() / 100.0;
        float rainmm = getAndResetRainInches()*25.4;
        float gustKPH;
        float windKPH = (getAndResetAnemometerkph(&gustKPH))*1.609;
        float knots = windKPH*0.5399;
        float windDegrees = getAndResetWindVaneDegrees();
 
        
        /////////////////////////Battery level Reading/////////////////////////
        FuelGauge fuel;
        float batt;
        batt = fuel.getVCell();
        float battp = fuel.getSoC();
        delay(2000);
 
        //Timestamp
        float vtime = Time.now();
                              
        // Preparing the values to String
        
        String Svtime = String(vtime);

        //Battery
        String Sbatt = String(batt);
        String Sbattp = String(battp);
 
        //Sparkfun Weather station
        String SPKtemp = String(wstempC);
        String SPKhum = String(wshumidityRH);
        String SPKpress = String(wspressureHPa);
        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 JSON
            String dest = "{";
            if(Svtime.length() !=0){ dest = dest + "\"1\":\""+ "1" +"\",";}
            if(Svtime.length() !=0){ dest = dest + "\"2\":\""+ Svtime +"\",";}
            if(SPKtemp !="xxx"){ dest = dest + "\"28\":\""+ SPKtemp +"\",";}
            if(SPKhum !="xxx"){ dest = dest + "\"29\":\""+ SPKhum +"\",";}
            if(SPKpress!="xxx"){ dest = dest + "\"30\":\""+ SPKpress +"\",";}
            if(SPKrain !="xxx"){ dest = dest + "\"31\":\""+ SPKrain +"\",";}
            if(SPKgust !="xxx"){ dest = dest + "\"32\":\""+ SPKgust +"\",";}
            if(SPKwind !="xxx"){ dest = dest + "\"33\":\""+ SPKwind +"\",";}
            if(SPKknots !="xxx"){ dest = dest + "\"34\":\""+ SPKknots +"\",";}
            if(SPKdegrees !="xxx"){ dest = dest + "\"35\":\""+ SPKdegrees +"\",";}
            if(UBXamb !="xxx"){ dest = dest + "\"36\":\""+ UBXamb +"\",";}
            if(UBXfrozen !="xxx"){ dest = dest + "\"37\":\""+ UBXfrozen +"\",";}
            + "}";
            
            Particle.publish("test",dest ,60,PRIVATE);

           }

        
    //}
    delay(300000);
    //System.sleep(SLEEP_MODE_DEEP, sleepPeriode, SLEEP_NETWORK_STANDBY); //Sleep a while to save battery    
}


Weather sensor;

void initializeTekphumidityAndPressure() {
    //Initialize the I2C sensors and ping them
    sensor.begin();
    //Set to Barometer Mode
    sensor.setModeBarometer();
    // Set Oversample rate
    sensor.setOversampleRate(7); 
    //Necessary register calls to enble temp, baro and alt
    sensor.enableEventFlags(); 
    
    return;
}

float wshumidityRHTotal = 0.0;
unsigned int wshumidityRHReadingCount = 0;
float wstempCTotal = 0.0;
unsigned int wstempCReadingCount = 0;
float pressurePascalsTotal = 0.0;
unsigned int pressurePascalsReadingCount = 0;

void captureTekphumidityPressure() {
  // Read the humidity and pressure sensors, and update the running average
  // The running (mean) average is maintained by keeping a running sum of the observations,
  // and a count of the number of observations
  
  // Measure Relative Humidity from the HTU21D or Si7021
  float wshumidityRH = sensor.getRH();
  
  //If the result is reasonable, add it to the running mean
  if(wshumidityRH > 0 && wshumidityRH < 105) // It's theoretically possible to get supersaturation humidity levels over 100%
  {
      // Add the observation to the running sum, and increment the number of observations
      wshumidityRHTotal += wshumidityRH;
      wshumidityRHReadingCount++;
  }

  // Measure Temperature from the HTU21D or Si7021
  // Temperature is measured every time RH is requested.
  // It is faster, therefore, to read it from previous RH
  // measurement with getTemp() instead with readTemp()
  float wstempC = getAndResetTempF();
  
  //If the result is reasonable, add it to the running mean
  if(wstempC > -50 && wstempC < 150)
  {
      // Add the observation to the running sum, and increment the number of observations
      wstempCTotal += wstempC;
      wstempCReadingCount++;
  }

  //Measure Pressure from the MPL3115A2
  float pressurePascals = sensor.readPressure();
  
  //If the result is reasonable, add it to the running mean
  // What's reasonable? http://findanswers.noaa.gov/noaa.answers/consumer/kbdetail.asp?kbid=544
  if(pressurePascals > 80000 && pressurePascals < 110000)
  {
      // Add the observation to the running sum, and increment the number of observations
      pressurePascalsTotal += pressurePascals;
      pressurePascalsReadingCount++;
  }
  
  return;
}

float getAndResetTempF()
{
    if(wstempCReadingCount == 0) {
        return 0;
    }
    float result = (wstempCTotal/float(wstempCReadingCount))-32/1.8;
    wstempCTotal = 0.0;
    wstempCReadingCount = 0;
    return result;
}

float getAndResetHumidityRH()
{
    if(wshumidityRHReadingCount == 0) {
        return 0;
    }
    float result = wshumidityRHTotal/float(wshumidityRHReadingCount);
    wshumidityRHTotal = 0.0;
    wshumidityRHReadingCount = 0;
    return result;
}


float getAndResetPressurePascals()
{
    if(pressurePascalsReadingCount == 0) {
        return 0;
    }
    float result = pressurePascalsTotal/float(pressurePascalsReadingCount);
    pressurePascalsTotal = 0.0;
    pressurePascalsReadingCount = 0;
    return result;
}

//===========================================================================
// 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 timeRainEvent = millis(); // grab current time
    
    // ignore switch-bounce glitches less than 10mS after initial edge
    if(timeRainEvent - lastRainEvent < 10) {
      return;
    }
    
    rainEventCount++; //Increase this minute's amount of rain
    lastRainEvent = timeRainEvent; // 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: 1.492kph, 2Hz: 2.984kph, etc.
// We measure the average period (elaspsed time between pulses), and calculate the average windspeed since the last recording.

int AnemometerPin = D3;
float AnemometerScalekph = 1.492; // 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 timeAnemometerEvent = 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 = timeAnemometerEvent - 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 = timeAnemometerEvent; // 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;
}

In cases like these it’s always nice to present a minimalistic version of the code to represent the problem, to save us the hassle of going through a couple hundred lines of irrelevant code. Reducing the code to the minimum is also a good way to identify where the issue might be, since you can remove all non-relevant parts.

As to the issue; try a couple seconds delay after a publish before sleeping, so the module has the time needed to do whatever it needs to do to transmit the message. That often helps.

You are using STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY)); but I couldn’t see any variables marked as retained

Following @Moors7 Previously I erased some part of my code that is not relevant and that’s why there is retained there :wink:

Thank’s

Hi @Moors7
I put a 10 seconds delay after publishing and the result is the same

blank data if sleeps, data if uncomment delay and comment sleep

I don’t know why

Is all the data 0, including temperature and humidity? I see you have a method called captureTekphumidityPressure(), but I don’t see anywhere that you call that method. Reading the code as you posted it, I don’t see how you can get any data other than 0 even without the sleep, since the only place you increment the various ReadingCount variables you have is in captureTekphumidityPressure(). The ReadingCount variables are set to 0 at startup, and in getAndResetTempF(), getAndResetHumidityRH(), etc., you return 0 if the appropriate ReadingCount variable is 0.

Hi @Ric

Thank’s for you help. I’m agree with you, but why when I put a delay at the end of loop the data is sent and why when I put the machine in sleep, the data is not received.Values=0

Has no sense

I can’t tell without seeing the complete code. I assume that in the complete code, you are calling captureTekphumidityPressure() from somewhere. Please edit your original post to show the complete code that gives the results that you’re talking about (either that, or a minimalistic version of the code that demonstrates the problem, as @Moors7 suggested).

1 Like

Hi @Ric

I upload the complete code, but what I did not understand is why when I sleep the data from wind and direction are zero, if it’s delay the values are correct

thank’s for your help

First, you never did directly answer my question. Is it only the wind data that is 0, or is all the data, including temperature and humidity also 0 if you sleep?

Secondly, The updated code you posted still doesn’t look like the complete code that would give you the results you claim to get. There’s still nowhere in that code where you call either captureTekphumidityPressure() or captureWindVane().

1 Like

Hi @Ric

The data with 0 is from windstation: wind, rain and wind vane.

The code is complete, but if any case I re-update again. The wind, rain and direction is after loop section, and a tittle for each section is commented

Thank’s again

Eduard

    // This #include statement was automatically added by the Particle IDE.
    #include <Adafruit_BME280.h>
    #include <SparkFun_Photon_Weather_Shield_Library.h>
    #include <math.h>
    #include <Adafruit_SI1145.h>
    #include <SHT1x.h>

    #define BME_SCK D4
    Adafruit_BME280 bme; // I2C
    Adafruit_SI1145 uv = Adafruit_SI1145();

    // Pins fro SHT10
    #define dataPin  D2
    #define clockPin D3
    SHT1x sht1x(dataPin, clockPin);

    // 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 = 15 * 60; 

    void setup() {

        initializeTekphumidityAndPressure();
        initializeRainGauge();
        initializeAnemometer();
        initializeWindVane();
        bme.begin();
        uv.begin();
        // Schedule the next sensor reading and publish events
        timeNextSensorReading = millis() + sensorCapturePeriod;
        timeNextPublish = millis() + publishPeriod; 
    }

    void loop() {

        // Capture any sensors that need to be polled (temp, humidity, pressure, wind vane)
        // The rain and wind speed sensors use interrupts, and so data is collected "in the background"
    /*    if(timeNextSensorReading <= millis()) {
            captureTekphumidityPressure();
            captureWindVane();
            // Schedule the next sensor reading
            timeNextSensorReading = millis() + sensorCapturePeriod;
        }*/
        
        // Publish the data collected to Particle
        //if(timeNextPublish <= millis()) {
            
            ///////////////////////// Sparkfun Weather Station /////////////////////////
            float wstempC = getAndResetTempF();
            float wshumidityRH = getAndResetHumidityRH();
            float wspressureHPa = getAndResetPressurePascals() / 100.0;
            float rainmm = getAndResetRainInches()*25.4;
            float gustKPH;
            float windKPH = (getAndResetAnemometerkph(&gustKPH))*1.609;
            float knots = windKPH*0.5399;
            float windDegrees = getAndResetWindVaneDegrees();
            
            ///////////////////////// SI1145 UV Sensor /////////////////////////
            digitalWrite(D0, HIGH);
            digitalWrite(D1, HIGH);
            float vis = uv.readVisible();
            float UV = uv.readUV();
            // the index is multiplied by 100 so to get the
            // integer index, divide by 100!
            UV *= 100.0;  
            digitalWrite(D0, LOW);
            digitalWrite(D1, LOW);
            delay(4000);
            
            ///////////////////////// BME 280 reading /////////////////////////
            digitalWrite(D0, HIGH);
            digitalWrite(D1, HIGH);
            float bmetempC = bme.readTemperature();
            float bmehum = (bme.readPressure() / 100.0F);
            float bmepress =bme.readHumidity();
            digitalWrite(D0, LOW);
            digitalWrite(D1, LOW);
            delay(4000);
            
            /////////////////////////Battery level Reading/////////////////////////
            FuelGauge fuel;
            float batt;
            batt = fuel.getVCell();
            float battp = fuel.getSoC();
            delay(2000);
            /////////////////////////SHT10 Reading/////////////////////////
            digitalWrite(D2, HIGH);
            digitalWrite(D3, HIGH);
            float tempsoil1 = sht1x.readTemperatureC();
            float humsoil1 = sht1x.readHumidity();
            digitalWrite(D2, LOW);
            digitalWrite(D3, LOW);
            //Timestamp
            float vtime = Time.now();
                                  
            // Preparing the values to String
            
            String Svtime = String(vtime);
            String Stemp = String(bmetempC);
            String Spress = String(bmehum); //String(press);
            String Shum = String(bmepress); //String(hum);
            //SI1145
            String Svis = String(vis);//String(UVvis);
            String SUV = String(UV);//String(UVindex);
            //SHT10
            String Stempsoil1 =String(tempsoil1);//String(tempsoil);
            String Shumsoil1 =String(humsoil1);//String(humsoil);
            String Stempsoil2 =String("xxx");//String("");
            String Shumsoil2 =String("xxx");//String("");
            //Battery
            String Sbatt = String(batt);
            String Sbattp = String(battp);
            //Water Mark
            String Ssoil1 = String("xxx");//String(WMValue1);
            String Ssoilp1 = String("xxx");//String(WMValueP1);
            String Ssoil2 = String("xxx");//String(WMValue2);
            String Ssoilp2 = String("xxx");//String(WMValueP2);
            //Decagon leaf
            String Sleaf1 = String("xxx");//String(leaf1);
            String Sleafp1 = String("xxx");//String(leafP1);
            String Sleaf2 = String("xxx");//String(leaf2);
            String Sleafp2 = String("xxx");//String(leafP2);
            //Capacitive
            String Scapacv1 = String("xxx");//String(capacitive1);
            String Scapacp1 = String("xxx");//String(capacitive1P);
            String Scapacv2 = String("xxx");//String(capacitive2);
            String Scapacp2 = String("xxx");//String(capacitive2P);
            //Sparkfun Weather station
            String SPKtemp = String(wstempC);
            String SPKhum = String(wshumidityRH);
            String SPKpress = String(wspressureHPa);
            String SPKwind =String(windKPH);
            String SPKdegrees =String(windDegrees);
            String SPKrain =String(rainmm);
            String SPKgust =String(gustKPH);
            String SPKknots =String(knots);
            //Ulatracker
            String UBXamb = String("xxx");//String(tempeatureFresh);
            String UBXfrozen = String("xxx");//String(temperatureFrozen);

            Particle.connect();
            if (waitFor(Particle.connected, 300000 ))
                { // proceede only if a connection could be established within 60 seconds 
                //Building JSON
                String dest = "{";
                if(Svtime.length() !=0){ dest = dest + "\"1\":\""+ "1" +"\",";}
                if(Svtime.length() !=0){ dest = dest + "\"2\":\""+ Svtime +"\",";}
                if(Stemp.length() !=0){ dest = dest + "\"5\":\""+ Stemp +"\",";}
                if(Spress.length() !=0){ dest = dest + "\"6\":\""+ Spress +"\",";}
                if(Shum.length() !=0){ dest = dest + "\"7\":\""+ Shum +"\",";}
                //if(Svis.length() !=0){ dest = dest + "\"8\":\""+ Svis +"\",";}
                //if(SUV.length() !=0){ dest = dest + "\"9\":\""+ SUV +"\",";}
                if(Stempsoil1 !=0){ dest = dest + "\"10\":\""+ Stempsoil1 +"\",";}
                if(Shumsoil1 !=0){ dest = dest + "\"11\":\""+ Shumsoil1 +"\",";}
                //if(Stempsoil2 !="xxx"){ dest = dest + "\"12\":\""+ Stempsoil2 +"\",";}
                //if(Shumsoil2 !="xxx"){ dest = dest + "\"13\":\""+ Shumsoil2 +"\",";}
                if(Sbatt.length() !=0){ dest = dest + "\"14\":\""+ Sbatt +"\",";}
                if(Sbattp.length() !=0){ dest = dest + "\"15\":\""+ Sbattp +"\",";}
                /*if(Ssoil1 !="xxx"){ dest = dest + "\"16\":\""+ Ssoil1 +"\",";}
                if(Ssoilp1 !="xxx"){ dest = dest + "\"17\":\""+ Ssoilp1 +"\",";}
                if(Ssoil2 !="xxx"){ dest = dest + "\"18\":\""+ Ssoil2 +"\",";}
                if(Ssoilp2 !="xxx"){ dest = dest + "\"19\":\""+ Ssoilp2 +"\",";}
                if(Sleaf1 !="xxx"){ dest = dest + "\"20\":\""+ Sleaf1 +"\",";}
                if(Sleafp1 !="xxx"){ dest = dest + "\"21\":\""+ Sleafp1 +"\",";}
                if(Sleaf2 !="xxx"){ dest = dest + "\"22\":\""+ Sleaf2 +"\",";}
                if(Sleafp2 !="xxx"){ dest = dest + "\"23\":\""+ Sleafp2 +"\",";}
                if(Scapacv1 !="xxx"){ dest = dest + "\"24\":\""+ Scapacv1 +"\",";}
                if(Scapacp1 !="xxx"){ dest = dest + "\"25\":\""+ Scapacp1 +"\",";}
                if(Scapacv2 !="xxx"){ dest = dest + "\"26\":\""+ Scapacv2 +"\",";}
                if(Scapacp2 !="xxx"){ dest = dest + "\"27\":\""+ Scapacp2 +"\",";}*/
                //dest = dest + "\"28\":\""+ SPKtemp +"\",";
                //dest = dest + "\"29\":\""+ SPKhum +"\",";
                //dest = dest + "\"30\":\""+ SPKpress +"\",";
                dest = dest + "\"31\":\""+ SPKrain +"\",";
                dest = dest + "\"32\":\""+ SPKgust +"\",";
                dest = dest + "\"33\":\""+ SPKwind +"\",";
                dest = dest + "\"34\":\""+ SPKknots +"\",";
                dest = dest + "\"35\":\""+ SPKdegrees +"\"";
                //if(UBXamb !="xxx"){ dest = dest + "\"36\":\""+ UBXamb +"\",";}
                //if(UBXfrozen !="xxx"){ dest = dest + "\"37\":\""+ UBXfrozen +"\",";}
                dest = dest + "}";
                
                Particle.publish("weatherstation",dest ,60,PRIVATE);
                delay(10000);

               }

            
        //}
        //delay(300000);
        System.sleep(SLEEP_MODE_DEEP, sleepPeriode, SLEEP_NETWORK_STANDBY); //Sleep a while to save battery    
    }


    Weather sensor;

    void initializeTekphumidityAndPressure() {
        //Initialize the I2C sensors and ping them
        sensor.begin();
        //Set to Barometer Mode
        sensor.setModeBarometer();
        // Set Oversample rate
        sensor.setOversampleRate(7); 
        //Necessary register calls to enble temp, baro and alt
        sensor.enableEventFlags(); 
        
        return;
    }

    float wshumidityRHTotal = 0.0;
    unsigned int wshumidityRHReadingCount = 0;
    float wstempCTotal = 0.0;
    unsigned int wstempCReadingCount = 0;
    float pressurePascalsTotal = 0.0;
    unsigned int pressurePascalsReadingCount = 0;

    void captureTekphumidityPressure() {
      // Read the humidity and pressure sensors, and update the running average
      // The running (mean) average is maintained by keeping a running sum of the observations,
      // and a count of the number of observations
      
      // Measure Relative Humidity from the HTU21D or Si7021
      float wshumidityRH = sensor.getRH();
      
      //If the result is reasonable, add it to the running mean
      if(wshumidityRH > 0 && wshumidityRH < 105) // It's theoretically possible to get supersaturation humidity levels over 100%
      {
          // Add the observation to the running sum, and increment the number of observations
          wshumidityRHTotal += wshumidityRH;
          wshumidityRHReadingCount++;
      }

      // Measure Temperature from the HTU21D or Si7021
      // Temperature is measured every time RH is requested.
      // It is faster, therefore, to read it from previous RH
      // measurement with getTemp() instead with readTemp()
      float wstempC = getAndResetTempF();
      
      //If the result is reasonable, add it to the running mean
      if(wstempC > -50 && wstempC < 150)
      {
          // Add the observation to the running sum, and increment the number of observations
          wstempCTotal += wstempC;
          wstempCReadingCount++;
      }

      //Measure Pressure from the MPL3115A2
      float pressurePascals = sensor.readPressure();
      
      //If the result is reasonable, add it to the running mean
      // What's reasonable? http://findanswers.noaa.gov/noaa.answers/consumer/kbdetail.asp?kbid=544
      if(pressurePascals > 80000 && pressurePascals < 110000)
      {
          // Add the observation to the running sum, and increment the number of observations
          pressurePascalsTotal += pressurePascals;
          pressurePascalsReadingCount++;
      }
      
      return;
    }

    float getAndResetTempF()
    {
        if(wstempCReadingCount == 0) {
            return 0;
        }
        float result = (wstempCTotal/float(wstempCReadingCount))-32/1.8;
        wstempCTotal = 0.0;
        wstempCReadingCount = 0;
        return result;
    }

    float getAndResetHumidityRH()
    {
        if(wshumidityRHReadingCount == 0) {
            return 0;
        }
        float result = wshumidityRHTotal/float(wshumidityRHReadingCount);
        wshumidityRHTotal = 0.0;
        wshumidityRHReadingCount = 0;
        return result;
    }


    float getAndResetPressurePascals()
    {
        if(pressurePascalsReadingCount == 0) {
            return 0;
        }
        float result = pressurePascalsTotal/float(pressurePascalsReadingCount);
        pressurePascalsTotal = 0.0;
        pressurePascalsReadingCount = 0;
        return result;
    }

    //===========================================================================
    // 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 timeRainEvent = millis(); // grab current time
        
        // ignore switch-bounce glitches less than 10mS after initial edge
        if(timeRainEvent - lastRainEvent < 10) {
          return;
        }
        
        rainEventCount++; //Increase this minute's amount of rain
        lastRainEvent = timeRainEvent; // 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: 1.492kph, 2Hz: 2.984kph, etc.
    // We measure the average period (elaspsed time between pulses), and calculate the average windspeed since the last recording.

    int AnemometerPin = D3;
    float AnemometerScalekph = 1.492; // 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 timeAnemometerEvent = 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 = timeAnemometerEvent - 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 = timeAnemometerEvent; // 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;
    }

This version of the code is different, since you now show where you call those two functions (though you have it commented out at the top of loop). It’s nearly midnight here, so I’ll take a look at it tomorrow if someone else doesn’t get to it first.

It’s still not clear to me what version of the software (what was commented out, what was not) gave you the results you’re talking about. I assume that the commented out stuff at the top of loop was not commented out when you got those results.

The thing you have to realize, is that when you put the device into deep sleep, the device resets and starts the program over again when it wakes up; that means all your global variables (unless they’re marked retained) are reset, and setup() runs again. You have this code,

   void setup() {

        initializeTekphumidityAndPressure();
        initializeRainGauge();
        initializeAnemometer();
        initializeWindVane();
        bme.begin();
        uv.begin();
        // Schedule the next sensor reading and publish events
        timeNextSensorReading = millis() + sensorCapturePeriod;
        timeNextPublish = millis() + publishPeriod;
    }
   
    

    void loop() {

        // Capture any sensors that need to be polled (temp, humidity, pressure, wind vane)
        // The rain and wind speed sensors use interrupts, and so data is collected "in the background"
        if(timeNextSensorReading <= millis()) {
            captureTekphumidityPressure();
            captureWindVane();
            // Schedule the next sensor reading
            timeNextSensorReading = millis() + sensorCapturePeriod;
        }

That if-statement in loop() will not be true at startup (or when the device awakens from deep sleep), so captureTekphumidityPressure() and captureWindVane() will never be called. That is your problem (or one of them anyway).

Since loop() runs only once before the device goes to sleep, you should be able to remove the if-statement (and delete timeNextSensorReading), and just call those two functions directly.

1 Like