Sending data without using timers

Hello,

I am doing a project where I query data from two sensors using a Particle Photon. The device is offline (no internet connection) most of the time, but I log in once every 10 mins to send data to Blynk. To further save on power, the device goes to sleep if it isn’t being used (no sensor data) for 10 seconds. From my understanding, Blynk only works off of Blynk. timer() and Blynk.run(). Is there anyway I can use VirtualWrite or use some other function to send data on my command, instead of using the Blynk timer routine?

Note: I have basically coded my own “timer” using the on board RTC, by using Time.hour() and Time.minute(), this is because the on board RTC is still on when the device is in sleep mode.

The community’s help is highly appreciated!! Please let me know if anything isn’t clear.

Thanks,
Mohamed

First, Blynk does need Blynk.run() and a network connection to a server to run, but BlynkTimer is all internal to the library, so all timers will keep working even if you are not connected to a server… that said, without connection, Blynk.virtualWrite() will have no server to send the data too, thus it will be “lost”.

@Gunner, Thank you for the prompt and elaborate explanation for timers. In this post I am including my “Internet” function (I changed it a little bit to hide auth…etc.), and as of now it doesn’t send data to my phone app. I believe the main problem is with Blynk.run(), since this is the only place it is being called (not called in void loop)! I am not calling it anywhere else because this function is the only place in the code where I have internet and Blynk connection established. However, when I run Blynk.run and Blynk.Timer in the void loop, it sends data just fine. Go ahead and take a look:

void Internet(){
    if (checktime() == 1){       // if X amount of time has passed
        Serial.println("Signing into the internet");
        WiFi.on();   Serial.println ("WiFi On ");
        while (WiFi.ready() == FALSE) {
            WiFi.connect();  Serial.println ("WiFi Connecting");
            delay(100);
        }
        Blynk.config("auth");
        if (!Blynk.connected() & (WiFi.ready() == TRUE)){
            Blynk.connect(30); // time out set to 30 seconds
            Serial.println("Blynk connection occured");
        }
        
        Blynk.virtualWrite(V1, PIRCount);
        Blynk.virtualWrite(V2, WheelCount);
        Blynk.virtualWrite(V3, soc);
        
        Blynk.run();
        
        previous_h= Time.hour(); Serial.print("Previous hour is:   "); Serial.print(previous_h);
        previous_m= Time.minute();Serial.print("Previous minute is:   ");Serial.print(previous_m);
        soc= lipo.getSOC();Serial.print("State of charge is:   ");Serial.println(soc);
        
        
        WheelCount = 0;
        PIRCount = 0;
    }
    else{
        WiFi.off();
    }
}

Is there anyway I can perhaps have Blynk.run() return a bool when it is done sending data, in this case I can do something like this:

bool x = 0;
while (x==0){
x= Blynk.run();
delay (100);
}

Also if I do something with a ‘for’ loop, will this send the data several times:
Is there anyway I can have Blynk.run return a bool when it is done sending data, in the case I can do something like this:

for(i=0; i< 10; i++){
Blynk.run();
delay (100);
}

To clarify: I am trying to find a way to send the data when I am commanding it to or when I call Blynk.run() once or in a loop without writing the data twice and without calling Blynk.run() ubiquitously in my code’s void loop() .

Thanks a lot,
Mohamed

i have read all the topic, but i still do not understand what is the main problem you are trying to solve?

could you explain again, very simplified, what would you like to achieve?

you would like to know for how long to keep device “on” to make sure all the data is sent, or what?

@wanek Sure, I am basically trying to use Blynk.run() without having it in a void loop. I guess you’ve posed my question in a different way you would like to know for how long to keep device "on" to make sure all the data is sent, or what?

I thought of it based on the number of times I call the function Blynk.run(), and not necessarily the “time/duration” that the device & WiFi need to be ‘on.’

Does that clarify my question?

yes, i understand now what you want to do.
but i do not understand why? :slight_smile:

i think there should be a better solution than “managing” how many time to run blynk.run…
if you give more detail what is the main objective, i’m sure we could find a better / simpler way.

you could simply send a bool value to a display widget or button to the phone as the last blynk.write command, after all your other blynk.write commands.

then check with a blynk.read if the respective widget has the correct value. it means the transfer was finished, and you can put to sleep the wifi / mcu.

edit:
or, the technically more advanced solution to send the values directly to the blynk api, then look for the http response. if 200, than should be ok.

@wanek from his / her other posts I think it relates to deepSleep but they are not being very clear.

Ok, so I am making a device that quantifies motion data and wheel cycles using two sensors, a PIR and a hall effect. The device is in sleep mode unless someone is running on the wheel or moving in front of the device in which case an interrupt on a digital pin wakes the device up. I quarry the data offline without logging to the internet, and once every 10 mins I would like to log on the internet and send data to Blynk.

The device is battery powered it uses a 3.7 volt LiPo, so it needs to be power efficient. The most power hungry aspect of a Particle photon is logging to the internet, sending data and maintaining internet connection. That’s why when I am querying data from the sensors, I am doing it offline (not connected to the internet). So the purpose of the function I shared earlier on ^^ is to log on to the internet, log on to Blynk servers and send the data using Blynk.run(). Once the data is sent, I’d like to log off the internet and quarry the sensors offline again.

Would it be easier to share my full code?

Presumably the data is sent to Blynk very quickly.

So I would use BLYNK_CONNECTED() to call the data sending function and at the end of the function call deepSleep().

@Costas My main problem is with Blynk not sending data to the phone app. Blynk.run isn’t executing in the following code!

Here is my code as of now:

    #include <SparkFunMAX17043.h>
    #include <blynk.h>
    #include <SparkCorePolledTimer.h>
    #include "Particle.h"
    #include "application.h"
    SYSTEM_THREAD(ENABLED);
    SYSTEM_MODE(SEMI_AUTOMATIC);


    //////Variable decleration for wheel
    int WheelCount = 0; 
    int previous_state=1; 
    int current_state= 1;

    int previous_h; int h;
    int previous_m; int m;
    int t;
    bool c = FALSE;
    int T_sleep;

    double soc =0;

    /////variable decleration for PIR
    unsigned int PIR_start;
    unsigned int PIR_Timer;
    int PIRCount;
    unsigned int T_lapse_sleep= 0;

    void setup() {
        Serial.begin(9600);
        lipo.begin();
        lipo.quickStart();
        t = Time.now();
        
        pinMode(D4, INPUT);
        pinMode(D2,INPUT_PULLUP);
        pinMode(D7, OUTPUT);
        pinMode(D5, OUTPUT);
        pinMode(D3, OUTPUT);
        digitalWrite(D5, HIGH);
        digitalWrite(D3, LOW);


        previous_h= Time.hour(); Serial.print("Previous hour is:   "); Serial.print(previous_h);
        previous_m= Time.minute();Serial.print("Previous minute is:   ");Serial.print(previous_m);
    }

    void loop() {
        PIR(30000);
        Wheel();
        
        c= check_time(10); //has (x)) mins passed?
        Internet();    
        delay(10);

    }

    void PIR (unsigned int Sleep_timeout){
        Serial.print("D4 is:    ");Serial.println(digitalRead(D1));
        if (digitalRead(D4) == 1){ // if PIR is ON
        Serial.print("D4 is:    ");Serial.println(digitalRead(D1));
            PIR_Timer= millis() - PIR_start;
            //Serial.print("PIR time:   "); Serial.println(PIR_Timer);
            if (PIR_Timer >= 1000){
                PIRCount += 1;
                Serial.print("PIR Count (Seconds):   ");Serial.println(PIRCount);
                PIR_start= millis();
                T_sleep= millis();
            }
        }
        else{  // if PIR is OFF
            T_lapse_sleep = millis() - T_sleep;
            Serial.print("Sleep time:  "); Serial.println(T_lapse_sleep);
            if ((T_lapse_sleep > Sleep_timeout) & (digitalRead(D4) == 0)){ // sleep if mice didn't move within x amount of seconds
                delay (1000);
                Sleep();
            }
        }

    }

    void Wheel(){
        current_state = digitalRead(D2);
        if ((current_state == 0) & (previous_state != current_state)){ // on the rising edge of a cycle is read
            WheelCount += 1;
            Serial.print("Wheel Count is:   ");Serial.println(WheelCount);
            digitalWrite(D7, HIGH); 
            delay (20); 
            digitalWrite(D7,LOW);
            previous_state= current_state ;
            T_sleep= millis();
        }
        
        else{ // a cycle isn't read
            previous_state= current_state;
        }
    }

    void Internet(){
        if (c == 1){ // if X amount of time has passed
            //Serial.println("Signing into the internet");
            WiFi.on();
            Serial.println ("WiFi On ");
            while (WiFi.ready() == FALSE) {
                WiFi.connect();
                Serial.println ("WiFi Connecting");
                delay(100);
            }
            Blynk.config("auth");
            while (!Blynk.connected() & (WiFi.ready() == TRUE)){
                Blynk.connect(30); // time out set to 30 seconds
                Serial.println("Blynk connection occured");
            }
            Blynk.run();
            Blynk.virtualWrite(V1, PIRCount);
            Blynk.run();
            Blynk.virtualWrite(V2, WheelCount);
            Blynk.run();
            Blynk.virtualWrite(V3, soc);
            Blynk.run();
            
            previous_h= Time.hour(); Serial.print("Previous hour is:   "); Serial.print(previous_h);
            previous_m= Time.minute();Serial.print("Previous minute is:   ");Serial.print(previous_m);
            soc= lipo.getSOC();Serial.print("State of charge is:   ");Serial.println(soc);
            
            WheelCount = 0;
            PIRCount = 0;
        }
        // else{
        //     WiFi.off();
        // }
    }

    bool check_time(int Delay_Duration){
        h= Time.hour();
        m= Time.minute();
        if ((h >= previous_h) & (m >= previous_m + Delay_Duration)){return TRUE;}
        else{ return FALSE;}
    }

    void Sleep(){
        previous_h= Time.hour(); Serial.print("Previous hour is:   "); Serial.print(previous_h);
        previous_m= Time.minute();Serial.print("Previous minute is:   ");Serial.print(previous_m);
        
        digitalWrite(D5, LOW);
        Serial.println("Going to Sleep");
        delay (100);
        System.sleep(D4, RISING, 600);
        
        Serial.begin(9600);
        
        lipo.begin();
        lipo.quickStart();
        
        Serial.println("Waking up from Sleep");
        SYSTEM_THREAD(ENABLED);
        SYSTEM_MODE(SEMI_AUTOMATIC);
        digitalWrite(D3, LOW);
        digitalWrite(D5, HIGH);
        PIR_start= millis();
        T_sleep= millis();
    }

for the situation as you described, it perfectly applies the solutions i have mentioned in my previous posts.

probably using the blynk api would be the fastest / most energy efficient.

http://docs.blynkapi.apiary.io/#reference/0/write-pin-value-via-get

I am not very familiar with Blynk API, or APIs in general for that matter. I’ll read up on it, try it and get back to you.

Thanks for your help so far.

Feel free to suggest any links that would help me with background knowledge…etc.

Mohamed

relax, it is not too complicated. i do not use it actually, but tested a long time before, and made it to work quite easy.

basically when you want to send the string of data from mcu, you just make a http get request and thats all. afaik it should be much more faster than via the blynk.run, this is why i think it is more energy saving.

1 Like

@Mohamed_Amr_Ali, i’ve wrote a simple example function for testing blynk api on esp8266.

please try it, and report back how it works. this function you can call from anywhere, you do not need blynk.run, neither blynk.begin. the only requirement is to have wifi internet connected. you can also send multiple values in the url string.

/*
    by wanek t, 2017.
    send data from esp8266 to blynk, using the blynk api. for more details, see:

    http://docs.blynkapi.apiary.io/#reference/0/write-pin-value-via-put/write-pin-value-via-get
    https://techtutorialsx.com/2016/07/17/esp8266-http-get-requests/

    include these 2 libs:
    #include <ESP8266WiFi.h>
    #include <ESP8266HTTPClient.h>
*/

void APIget()
{
  HTTPClient http;                                   // create http object

  String url = "http://blynk-cloud.com/";            // url
  url += "blynk token here";                         // your project token
  url += "/update/";
  url += "V14";                                      // pin to update
  url += "?value=";
  url += "HAHA";                                     // value to send

  http.begin(url);
  http.GET();
  delay(10);
  http.end();
}
2 Likes

Awesome! I’ll implement it soon and let you know!

Thanks a lot,
Mohamed

So I have tried the sample code using the HTTPClient library (https://github.com/nmattisson/HttpClient/blob/master/firmware/HttpClient.h) but I am getting no where with it :sweat:

Here is the code, I took out the Auth tocken out of it.

The things I am not sure about is the Port # and the header format that I should be using with with http://blynk-cloud.com/

In Blynk documentation there are several port numbers that you guys have here: https://github.com/blynkkk/blynk-server

#include <HttpClient.h>
/**
* Declaring the variables.
*/
unsigned int nextTime = 0;    // Next time to contact the server
HttpClient http;

// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
    //  { "Content-Type", "application/json" },
    // { "Accept" , "application/json" },
    { "Content-Type", "plain/text"},
    { "Accept" , "*/*"},
    { NULL, NULL } // NOTE: Always terminate headers will NULL
};

http_request_t request;
http_response_t response;

void setup() {
    Serial.begin(9600);
}

void loop() {
    if (nextTime > millis()) {
        return;
    }
    Serial.println();
    Serial.println("Application>\tStart of Loop.");
    // Request path and body can be set at runtime or at setup.
    request.hostname = "http://blynk-cloud.com/"; //blynk-cloud.com
    request.port = 80; 
    request.path = "authtocken/update/V1?value=12";

    // The library also supports sending a body with your request:
    //request.body = "{\"key\":\"value\"}";

    // Get request
    http.get(request, response, headers);
    Serial.print("Application>\tResponse status: ");
    Serial.println(response.status);

    Serial.print("Application>\tHTTP Response Body: ");
    Serial.println(response.body);

    nextTime = millis() + 10000;
}

Thanks for all the help!!
Mohamed

@Mohamed_Amr_Ali, did you tried the exact example i gave?

just turn on the wifi in your sketch (without blynk)
and try the function. you do not need any port numbers, header formats etc for this to work.

please, first just try with a very basic sketch, and see if it works. i use the above method in one of my current projects, and it works 24h, sending some values every minute, without blynk.run, so it works 100% sure!

i’m not at my pc, but tomorrow i can send you more details, if you don’t succeed.

Hey @wanek,

Thank you for the prompt response, I wasn’t at my desk either. I am using a Particle Photon, that’s why I automatically started searching for http libraries that would be equivalent to ESP8266HTTPClient.h. I am sure the code you sent earlier would work great for an ESP8266! This is why I am #including HTTPclient.h I think it essentially does the same thing in Particle Photons that #include ESP8266HTTPClient.h does in ESP8266. Let me know what you think!! Particle build doesn’t have the two libraries that you included.

Best,
Mohamed

hm, you’re right, i forgot that you use particle, not esp. than indeed you have to figure it out the correct settings regarding header, port, etc.

as i never used these boards, i can’t help with this.

1 Like