WiFi.off(), WiFi.on(); issues and question to conserve battery

Hello.

What do I need to do to turn off the wifi module for minimum power consumption… And then to turn it back on and connect to the particle cloud??? I am unable to get past the waitFor… not even the timeout of the waitfor Works… Is there anything else I should do?

I am trying in semi automatic mode :

This function runs every minute or so, by being called from a software timer…

void everyMinute() {
  if (WiFi.ready() == false) {
    WiFi.on();
  }

  if (waitFor(Particle.connected, 60000)) {
    //Connected
    // ---> Publish to the cloud!
    WiFi.off();   // Turn off the wiFi module after reset...
  } else {
    //Timeout... Lets reset.
    System.reset();
  }
}

If you want to connect to the cloud you need to call Particle.connect() - WiFi.on() only turns the radio on (e.g. for cloudless TCP communication) but does not connect to the cloud.

Please read the docs - it’s clearly stated there!

Understood…

However…

Here’s the issue:

After I turn on the radio WiFi.on() and after I run Particle.connect()… it is not connecting to the cloud if called from a software timer ISR… So that’s why I am asking… (Haven’t tried without calling it within an ISR call)

How would you turn off wifi… Then turn it on, and connect to the cloud with a timeout.

The code I wrote does not work, even if I add a Particle.connect() statement before the if (waitFor…

I am guessing now that this is an ISR issue.

Although these are no real ISRs, you should treat them like ISRs and ISRs are not meant for doing things that way.
The docs clearly state

If you want to time-trigger such blocking actions, do it via a flag being set in the timer callback and polled in loop().

And to properly judge your code, we'd need to see it all - including the timer setup.

Furthermore, if you look at your RGB-LED, I guess you see white breathing, so your if (WiFi.ready() == false) will never catch, since WiFi.ready() is true.

This is the code with the changes you suggested. Now polling and performing actions in the loop() function instead of in the ISR function… I will try this in a little bit… I am far away from the photon… At this point I am planning on switching to mills technique instead of the ISR.

The code that runs the wifi and connect code is in the performReportDuties function near the bottom of the code.

    #include "LEDControl.h"    
    #include "SparkFunMAX17043/SparkFunMAX17043.h"
    #include "SparkFun_Photon_Weather_Shield_Library/SparkFun_Photon_Weather_Shield_Library.h"
    #include "math.h"
    
    #define PIN_SOLARNRG A2
    #define PIN_POWERALERT_ISR D6
    
    #define version "2.0a"    

    //WX STUFF
    Weather sensor;    
    float humidity = 0;
    float tempc = 0;
    float tempf = 0;
    float dewtf = 0;
    float dewtc = 0;
    float pascals = 0;
    float baroTempc = 0;
    float baroInches = 0;
    float altimeter = 0;
    
    //OPTIONS
    const int pulseLEDEvery = 30;
    const int pulseLEDDuration = 2;
    const int reportToCloudEvery = 30;
    const int lowPowerAlert = 30;
    
    //STATION SETUP
    const int station_elevation_m = 1638;
    
    unsigned long int pulseSeconds=0;
    unsigned long int seconds=0;
    
    //Battery Shield
    float voltage = 0.0; 
    float soc = 0.0; 
    bool alert = false;
    float solarNrg = 0.0;
    float solarNrgRaw = 0.0;
    
    Timer heartTimer(1000, heartBeat);
    
    void heartBeat() {
        if (seconds>=UINT_MAX) {seconds=0;}
        seconds++;
        pulseSeconds++;
    }
    
    
    //DUTY METHODS
    void publishBatteryEvents() 
    {
       String msg = String::format("{ \"SOLNRG\":%f, \"VTS\":%f, \"SOC\":%f, \"LOWP\":%d}", solarNrg, voltage, soc, alert);
       Particle.publish("POWSTAT", msg); 
    }
    
    void publishWeatherEvents() 
    {
       String msg = String::format("{ \"TEMP\":%f, \"DEW\":%f, \"PASC\":%f, \"ALT\":%f, \"HUM\":%f}", tempc, dewtc, pascals, altimeter, humidity);
       Particle.publish("WXSTAT", msg); 
    }
    
    
    // SHIELDS >>>>>>>>>>>>>>>>  >>>>>>>>>>>>>>>>  >>>>>>>>>>>>>>>>
    
    //BATTERY-POWER
    void readBattery()
    {
        lipo.wake();
        delay(300);
    	voltage = lipo.getVoltage();
    	soc = lipo.getSOC();
    	alert = lipo.getAlert(true);
    	solarNrgRaw = ((analogRead(PIN_SOLARNRG) * 3.0)/4095);
        solarNrg = (100 / 3) * solarNrgRaw;
    }
    
    //WEATHER
    void readWeather()
    {
        
      humidity = sensor.getRH();
      float rawTempc = sensor.getTemp();
      
      tempf = sensor.getTemp();
      baroTempc = sensor.readBaroTemp();
      pascals = sensor.readPressure();
      tempc = (rawTempc+baroTempc)/2;
      tempf = (tempc * 9)/5 + 32;
      
      baroInches = pascals * 0.0002953;
      
      dewtc = dewPoint(tempc, humidity);
      dewtf = (dewtc * 9.0)/ 5.0 + 32.0;
      altimeter = altimeterSetting(pascals);
    }
    
    double dewPoint(double celsius, double humidity)
    {
    	// (1) Saturation Vapor Pressure = ESGG(T)
    	double RATIO = 373.15 / (273.15 + celsius);
    	double RHS = -7.90298 * (RATIO - 1);
    	RHS += 5.02808 * log10(RATIO);
    	RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ;
    	RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
    	RHS += log10(1013.246);
    
      // factor -3 is to adjust units - Vapor Pressure SVP * humidity
    	double VP = pow(10, RHS - 3) * humidity;
    
      // (2) DEWPOINT = F(Vapor Pressure)
    	double T = log(VP/0.61078);   // temp var
    	return (241.88 * T) / (17.558 - T);
    }
    
    float altimeterSetting(float pascalsIn)
    {
        float pressure = pascalsIn;
        pressure /= 100; //pressure is now in millibars
    
        float part1 = pressure - 0.3; //Part 1 of formula
      
        const float part2 = 8.42288 / 100000.0;
        float part3 = pow((pressure - 0.3), 0.190284);
        float part4 = (float)station_elevation_m / part3;
        float part5 = (1.0 + (part2 * part4));
        float part6 = pow(part5, (1.0/0.190284));
        float altimeter_setting_pressure_mb = part1 * part6; //Output is now in adjusted millibars
        float baroin = altimeter_setting_pressure_mb * 0.02953;
    
      return baroin;
    }
    
    
    
    // >>>>>>>>>>>>>>>>  >>>>>>>>>>>>>>>>  >>>>>>>>>>>>>>>>
    // PHOTON METHODS
    void setup() 
    {
        pinMode(PIN_SOLARNRG, INPUT);
        pinMode(PIN_POWERALERT_ISR, INPUT_PULLUP);
        Time.zone(-5);
        
        Serial.begin(9600);
        
        //BatteryShield
        lipo.begin(); 
    	lipo.quickStart();
    	lipo.setThreshold(lowPowerAlert);
    	
    	//WeatherShield
    	sensor.begin();
        sensor.setModeBarometer();
        sensor.setOversampleRate(100);
        sensor.enableEventFlags(); 
    	
        RGB.control(true);
        
    	String bootStatusString; 
    	String ip = WiFi.localIP();
    	Serial.println("*************************");
        Serial.println("        WXMAN");
        Serial.print("Version: ");
        Serial.println(version);
        Serial.println("By Lobo:Labs 2015");
        Serial.println("System Ready......");
        Serial.println("*************************");
        
        bootStatusString  = String::format("{\"VER\": \"%s\", \"RSSI\": %d, \"SSID\":\"%s\", \"IP\":\"%s\"}", version, WiFi.RSSI(), WiFi.SSID(), ip.c_str()); 
        Serial.println(bootStatusString);
        
        //waitUntil(Particle.connected);
    	Particle.publish("BOOT", bootStatusString);
    	
    	readBattery();
    	readWeather();
    	performReportDuties(); 
    	
        heartTimer.start();
    }
    
    void performReportDuties() {
        setLED(WHITE);
        
        Particle.connect();
        if (waitFor(Particle.connected, 60000)) {
            setLED(BLUE);
            publishBatteryEvents();
            publishWeatherEvents();
            setLED(OFF);    
            delay(200); 
            Wifi.off();  
        } else {
            Serial.println("[Cloud] Connection Timed Out. Resetting device");
            System.reset();
        }
        
        
        
    }
    
    void timedEvents() {
        
        if (pulseSeconds==pulseLEDEvery) { setLED(GREEN); }
        if (pulseSeconds>=pulseLEDEvery+pulseLEDDuration) { setLED(OFF); pulseSeconds=0; }
        
        if (seconds % 2 == 0) { //Read Values every 2 seconds. 
            readBattery();
            readWeather();
        } 
        
        if (seconds % reportToCloudEvery == 0) {
            performReportDuties();
        }
        
    }
    
    void loop() {
        timedEvents();
    }

If this is the case, then it means that the wifi is connected and all it's left to do is connect to the cloud....

Yes, that is one part of it, so you’d need to call Particle.connect() in a seperate if (!Particle.connected()).

This is my test code, that just works as expected

SYSTEM_MODE(SEMI_AUTOMATIC)

Timer timer(60000, everyMinute);

void setup()
{
    Serial.begin(115200);
    timer.start();
}

volatile bool triggered;
void loop()
{
    if(triggered)
    {
      triggered = false;
      Serial.println("Timer triggered");
      if (!Particle.connected()) 
      {
        Serial.println("connecting");      
        Particle.connect();
      }
    
      if (waitFor(Particle.connected, 30000)) {
        Serial.println("connected");      
        delay(10000);
        //Connected
        // ---> Publish to the cloud!
        WiFi.off();   // Turn off the wiFi module after reset...
      } else {
        Serial.println("reseting");      
        //Timeout... Lets reset.
        System.reset();
      }
    }
}

void everyMinute() {
    triggered = !Particle.connected();
}

But there is something that definetly has to be either explicitly documented or changed if this is not intended (@mdma please comment)
When calling Particle.connect() from within a soft timer callback, it does not seem do anything if it’s followed by a waitFor(Particle.connected, 1)
Test callback

void everyMinute() {
      if (!Particle.connected()) 
      {
        Serial.println("connecting");      
        Particle.connect();
      }
      if (waitFor(Particle.connected, 1)) { // any other timeout just the same }
}

Actually… After several attempts, i think there’s something wrong too with the waitFor()… Either in my implementation or in the system.

This works (Called from the main loop, not ISR) :

    
    if (!Particle.connected()) {
        Serial.println("[Cloud] Connecting to cloud");
        Particle.connect();
    }            
        waitUntil(Particle.connected);
        publishBatteryEvents();
        delay(1100); 
        publishWeatherEvents();
        delay(1100);
        WiFi.off();

This doesn’t work… (In exactly the same surrounding code and context):



    if (!Particle.connected()) {
        Serial.println("[Cloud] Connecting to cloud");
        Particle.connect();
    }            

    if (waitFor(Particle.connected, 60000)) {
        publishBatteryEvents();
        delay(1100); 
        publishWeatherEvents();
        delay(1100);
        WiFi.off();
    }  else {
       Serial.println("[Cloud] Connection Timed Out. Resetting device");
       System.reset();
    } 

By the way: thank you very much for all your help @ScruffR

1 Like