How to keep track of rain with photon and deep sleep?

@raenrfm, a low power CMOS D-type flip-flop will do the job and has a standby current of 900nA. However, being able to read the internal registers is betting IMO. :wink:

Just wondering if you could elaborate on how I would be able to read those registers when the photon isn’t awake? I see this as a chicken and egg problem, the photon needs to be on to read the event, but it’s the event that wakes the photon.

Unless their is a way to distinguish if the photon was woken by the pin or the expiring timer? Other than trying to extrapolate time periods to deduce whether or not the timer expired. I’m using several different sleep duration’s depending on the condition of the battery charge (SOC) and it would get quite cumbersome to try and figure out a rain event based purely on time.

@raenrfm, you only read the register AFTER the Photon wakes in order to find out what the wake event was. If you can’t read the register, then you need to read the WKP pin to see if it was the triggering event which may require an external latch for the bucket event.

Ok, so if my rain bucket is on D2 I could try to see if D2 was triggered by reading it’s state because I can’t read the WKP pin if I’m understanding you correctly. I’m thinking I will miss the read because it’s just a momentary reed switched device. I guess I’ll just have to experiment with it to see if it bears fruit. Otherwise I suppose I’m stuck with the latch idea.

I did a bit more research and I think the caveat is that there is no register to differentiate between a wakeup from RTC or the WKP pin, therefore I think I’m stuck with building a latch circuit and using an unused pin to read the status of the latch. Guess I’m off to get some discrete parts or maybe a 555 chip.

EDIT: Just googling some 555 timer circuits and I think what would work equally well for this is a time delay circuit. I could program the circuit to delay the trigger from the rain bucket say 5 seconds, then pulse an unused pin to register an interrupt. I would still have to wire the rain bucket pin to the WKP pin but once that happens I’ll know I woke up from sleep from the rain bucket because I’ll get a pulse on a different pin once the photon is awake. Problem solved.

1 Like

Have a look at my water usage monitor, it monitors a reed switch to count the water meter pulses. It looks at the difference between the expected wake time and the time it woke up

I’m thinking I’m going to have to employ a method like this. After thinking about building a latch circuit or even a delay circuit with a 555 timer IC, I’m back at square one because the current draw of the 555 is around 30 mA and that’s not gonna fly. I’m thinking all I have to do is timestamp just before it deep sleeps and when it wakes, timestamp again and compare to see if it woke from sleep timer or WKP pin, similar to what you are doing here. I really have to be careful with the battery where I live because it was -29 C this morning -37 with the wind chill, and batteries generally don’t like that kind of weather so I have to be aggressive with my battery charging to make sure their is enough juice overnight so it survives. I guess I’ll find out when I finally stop messing with this thing indoors and set it free into the wild.

@raenrfm, you can get a low power CMOS version of the 555 like these (there are more!):

http://www.digikey.com/product-detail/en/ICM7555ESA%2B/ICM7555ESA%2B-ND/1303147

http://www.digikey.com/product-detail/en/LMC555CMX%2FNOPB/LMC555CMX%2FNOPBTR-ND/334874

These only take 30-150uA and are direct replacements.

@peekay123, thanks for the tip. That is definitely more feasible in terms of power management. I think I will stick with the latch idea, because if I use the delay it will pulse in step with the rain bucket, then I don’t have any memory of the wakeup trigger through the next sleep cycle. Just as easy to implement the latch as the delay, just a couple more components.

1 Like

So I obtained some low power 555 timer IC’s and managed to get this somewhat working but it appears the big problem is how to get the photon to not reset the memory cell (555 timer ic is configured as a 1-bit memory), when woken by the WKP pin.

Here is the setup: I have D7 monitoring the status of the memory cell (pin 3 on the 555) so I can easily see if it’s stored a 0 or a 1 with the LED on the Photon. I have D2 providing the SET function of the memory cell (rain bucket causes a HIGH-LOW-HIGH transient briefly while the reed switch is active) so it’s doing double duty of registering bucket tips with the photon for rain counting and for triggering the SET function on my 1bit memory cell. D5 is providing a reset function to pin 4 of the 555 timer so that after a cycle is complete and I have posted weather data we need to reset the memory cell to wait for another bucket tip. The weather program will normally (depending on battery state of charge) cycle through monitoring weather for roughly 2 min then if the battery is full, sleep for 5 and then wake again. The bucket tip should, and does wake the photon but I used the output of the memory cell to trigger this because directly monitoring D2 doesn’t seem to provide a good enough leading edge to wake up the device.

Now, the big problem, and the whole reason for me doing this in the first place is I want to wake the photon with a bucket tip (it’s raining we need to start recording it). And it appears my memory cell does register a 1 while the photon is booting up (I see D7 is lit), but then as soon as the program starts it resets my memory cell and I’m thinking it’s because D5 is cycling somehow to give a reset pulse to the 555. I’ve experimented with various sized pull up resistors on pin 4 of the 555, but nothing seems to cure this problem. Can someone elaborate on what happens to pin states when the photon boots up from deep sleep?

1 Like

I’d have to look up what the JTAG pins on the Photon are, but this sounds a bit like an old known issue
Start-Up/Flashing “troubles” with D-pins (summarized)

OK, D5 (as D7 too) is still a JTAG pin with pull-up during bootup.
https://docs.particle.io/datasheets/photon-datasheet/#jtag

The common cure is to use A-pins instead.

2 Likes

This might have to do with the fact that D3-D7 are also used as JTAG interface pins. If you look at the note below the JTAG section in the Photon data sheet, it says that D5 is briefly set to pull-up after a reset. D4 is floating, and D6 is pull-down, so you might want to try D6 instead of D5.

3 Likes

Thanks @ScruffR as usual you provided gold. I will rejig my setup to use A pins instead.

1 Like

I’m going to use A pins because I’m using a sparkfun weather sheild and battery shield so D4 is being used by another function on these boards, but the A pins are unused in this application so will make sense to use those instead. But this is good info to know thanks!

Hey Peekay123, I read through all your replay and they are very usefully. So after that, I modified my code that it wakes up from deep sleep and record the time if the ball tilt switch moved/sharked. If it wakes up due to time, it should not record the time but upload the date. However, it does not work. What I really get: When I don’t connect to the ball tilt switch, it wakes up first time record the time, and second time upload the date.

I am a beginner for this.
Here are some question that I want to ask you:

  1. Do I need connect the Vbat in order to keep the RTC running when it is in deep sleep?
  2. Does the photon reset the time when it wakes up from deep sleep. (no wifi connected when it wakes up).
STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY)); // Enables backup RAM


STARTUP(WiFi.selectAntenna(ANT_EXTERNAL)); // choose external antenna
//STARTUP(WiFi.selectAntenna(ANT_AUTO)); //continually switches at high speed between antennas


SYSTEM_MODE(MANUAL); // Puts device in manual mode


#include <string.h> 
//#define d_length 4
int boardLed = D7; // This is the LED that is already on your device.
//int button = A0; // This is where push button is plugged in.




retained int counter = 0;
retained int list[4];
retained int ETA_Wake;

//retained bool is_open = true;
retained bool is_startup = true;


//retained int list[d_length];
//retained char strtime[255];


char buffer[10];
char all_times[255];
int wakeUpRange = 13;
int lower_ETA;
int higher_ETA;
int wakeTime;

void setup() {
  // This part is mostly the same:
  pinMode(boardLed,OUTPUT); // Our on-board LED is output
//  pinMode(button,INPUT);  // Our photoresistor pin is input 
  // Now flash the D7 LED on and off three times to let us know that we're ready to go!
  
}


void loop() {
    wakeTime = Time.now();
    lower_ETA = ETA_Wake - wakeUpRange;
    higher_ETA = ETA_Wake + wakeUpRange;

    if (wakeTime > higher_ETA || wakeTime < lower_ETA)
    {
        if (counter < 3) {
            /*
            Particle.connect();
            Particle.process();
            delay(5000);
            int diff = wakeTime-ETA_Wake-wakeT;
            Spark.publish("still alive", all_times, diff, PRIVATE);
            delay(600);
            */
            list[counter] = Time.now();
            counter++;
            // And flash the on-board LED on and off.
            digitalWrite(boardLed,HIGH);
            delay(300);
            digitalWrite(boardLed,LOW);
            delay(300);
            digitalWrite(boardLed,HIGH);
            delay(300);
            digitalWrite(boardLed,LOW);
        } 
        
        else {
            list[counter] = Time.now();
            counter++;
            digitalWrite(boardLed,HIGH); delay(100);
            digitalWrite(boardLed,LOW); delay(100);
            digitalWrite(boardLed,HIGH); delay(100);
            digitalWrite(boardLed,LOW); delay(100);
            digitalWrite(boardLed,HIGH); delay(100);
            digitalWrite(boardLed,LOW);
            
            Particle.connect();
            Particle.process();
            delay(5000);
            
            
            for(int i=0; i<counter ; i++) {
                itoa(list[i], buffer, 10);
                
                //for(int j=1; j<9 ; j++) {
                for(int j=1; j<9 ; j++) {
                    //all_times[i*9+j] = buffer[j+1];
                    all_times[i*9+j-1] = buffer[j+1];
                }
                //all_times[(i+1)*9] = ',';
                all_times[(i+1)*9-1] = ',';
            }
            
            Spark.publish("Operation", all_times, 60, PRIVATE);
            delay(600);
            
            /*
            if (counter%2 != 0) {
                is_open = !is_open;
            }
            */
            counter = 0;
            memset(&all_times[0], 0, sizeof(all_times));
            memset(&list[0], 0, sizeof(all_times));
            memset(&buffer[0],0,sizeof(buffer));
            //Particle.disconnect();
            //WiFi.off();
            //delay(100);
        }
        
    }

else
    {
        if(counter == 0){
            Particle.connect();
            Particle.process();
            delay(5000);
            Spark.publish("still alive", all_times, 60, PRIVATE);
            delay(600);
            //Particle.disconnect();
            //WiFi.off();
            
            
        }
        
        else{
            
            
            Particle.connect();
            Particle.process();
            delay(5000);
            
            for(int i=0; i<counter ; i++) {
                itoa(list[i], buffer, 10);
                
                //for(int j=1; j<9 ; j++) {
                for(int j=1; j<9 ; j++) {
                    //all_times[i*9+j] = buffer[j+1];
                    all_times[i*9+j-1] = buffer[j+1];
                }
                //all_times[(i+1)*9] = ',';
                all_times[(i+1)*9-1] = ',';
            }
            
            Spark.publish("Operation", all_times, 60, PRIVATE);
            //delay(600);
            delay(1000);
            
           
            counter = 0;
            memset(&all_times[0], 0, sizeof(all_times));
            memset(&list[0], 0, sizeof(all_times));
            memset(&buffer[0],0,sizeof(buffer));
            //Particle.disconnect();
            //WiFi.off();
            //delay(100);
        
        }
    }  

    //is_startup = false;
    //System.sleep(A0,RISING,30); 
    delay(300);
    ETA_Wake = Time.now()+40;
    System.sleep(SLEEP_MODE_DEEP, 40);
}

@Joe1, you DO need to power Vbat for the RTC and SRAM to be retained. Typically, if the Photon remains powered while sleeping, you can just connect Vbat to 3V3. Otherwise, you will need a 3v lithium batter connected to Vbat.

I also noticed that you never connect to the cloud on startup so the RTC is not synchronized to cloud time and Time.now() will be random. Having code that syncs the RTC to the cloud once (use a retained flag) would make time correct as long as you don’t remove power to the Photon. You can also resync the time every day to keep accuracy.

BTW, instead of using:

            Particle.connect();
            Particle.process();
            delay(5000);

You can replace with:

            Particle.connect();
            while (!Particle.connected()) Particle.process();

This will ensure that the connection occurs, even if it takes longer than 5 secs.

You may also want to consider using SYSTEM_THREAD(ENABLED) to allow the user app to run in its own thread.

Thx you very much peekay123. With your help I can differentiates when it wake up due to time. I run a simple code without publish anything, everything work perfect. I dont know how to thx you for. without you, i will not able to finish my work.

@peekay123, any particular reason for not going with watiUntil(Particle.connected); instead of the while() approach?

@ScruffR, nope, just wanted to keep a familiar for the user. I also didn’t put a timeout to keep things simple.

@Joe1, I’m glad I could help. As @ScruffR pointed out, you can also use the waitUntil() or waitFor() functions :smile:

1 Like

@Joe1 @Peekay123 Here is some Particle connect code that puts the device back to sleep if it does not connect to the Particle Cloud within five mins due to network or Wifi issues.

I used this because my cell phone is my wifi hotspot and when I leave there is no WiFi to connect to so I didn’t want the Photon sitting there wasting battery trying to connect for hours to a WiFi network that is not there.

Figured it might be helpful if you’re running on batteries :smiley:

void loop()
{

Particle.connect();

  if (!waitFor(Particle.connected, 60000)) { // If we do not connect to Particle Clould in 5 mins run the following sleep code. 
      
    System.sleep(SLEEP_MODE_DEEP, 300);
}
   
    // If we do connect to the Particle Clould then we run the code below. 
    
  // Read values from the sensor
    
    temp_f = sht1x.readTemperatureF();
    humidity = sht1x.readHumidity();
    
    Particle.publish("TempSensor1", String::format("Temp=%dF; Humidity=%d%%; Time=%s", temp_f, humidity, Time.timeStr().c_str()));
    

    
    System.sleep(SLEEP_MODE_DEEP, 300);
}
1 Like