Counting Problems

That is exactly what i was looking for! Maybe we should add it to our docs near the Time.format() section
even maybe the link directly to the section

https://sourceware.org/newlib/libc.html#strftime

1 Like

I second that!

I’m afraid I talked too soon. After seeing the counter arriving up to 4000 (it used to reset after about 200 counts max) I thought the problem was fixed, but I am back to the initial problem. If wifi is switched off, the counter resets.

Here is the latest code:

#include "HttpClient/HttpClient.h"
#include "application.h"

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);
STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

//Settings
String DeviceID = "XXXXXX";
String TargetHostName = "yyy.yyyy.com";


int val = 0;
int inPin  = D0;
int outPin = D7;
int PreviousMinute = -1;
int ThisMinute = -1;
bool SensorState = false;
bool PreviousSensorState = false;
retained uint32_t PulseCount = 0;
retained uint32_t TotalPulseCount = 0;
String PacketData = "";
String DeviceTime = "";
String PreviousResponseBody = "";
int ResponseStatus = 0;
bool success;
unsigned long PreviousTime = millis();


uint8_t retry_count = 0;
unsigned long old_time = millis();
unsigned long PulsePeriod = 0;

double CurrentPower = 0;
double incPower = 0;
double AveragePower = 0;
int TimeStamp;


HttpClient http;
http_header_t headers[] = {
    { "Accept" , "*/*"},
    { NULL, NULL }
};
http_request_t request;
http_response_t response;

void setup() {
    pinMode(outPin, OUTPUT);
    pinMode(inPin,  INPUT);
    Time.zone(2);
    WiFi.on();
}

void loop() {
    if(millis() - old_time >= 2000){        
        if(retry_count < 10){
            if(!WiFi.ready()){
                WiFi.connect();
                retry_count++;

            }
            else if (!Particle.connected()){
                Particle.connect();
                retry_count++;
            }
        }
        else{
            WiFi.off();
            retry_count = 0;
            WiFi.on();
        }
        old_time = millis();
    }    
    
    val = digitalRead(inPin);
    SensorState = !val;
    digitalWrite(outPin, SensorState); //show sensor state on little blue led
    
    //Count Pulses
    if(SensorState != PreviousSensorState) {
        //Detect Leading Edge
        if(SensorState==true) {
            PulseCount += 1;
            TotalPulseCount += 1;
            if(TotalPulseCount==10000) {
               TotalPulseCount=0; 
            }
            PulsePeriod = millis() - PreviousTime;
            CurrentPower = (3600000 / (double)PulsePeriod);
            incPower += CurrentPower;
            PreviousTime = millis();
        }
        PreviousSensorState = SensorState;
    }

    
    //Transmit Pulsecount at the turn of the minute//
    ThisMinute = Time.minute();
    if(ThisMinute != PreviousMinute) {
        TimeStamp = Time.now();
        DeviceTime = URLEncode(Time.format(TimeStamp, "%y%m%d%H%M%S"));
        AveragePower = (incPower / PulseCount);

        PacketData = DeviceID + ";" + String(PulseCount) + ";" + DeviceTime + ";" + String(TotalPulseCount) + ";" + String(AveragePower);
        
        //***Using HTTP Client***
        request.hostname = TargetHostName;
        request.port = 80;
        request.path = "/spark_receiver.ashx?PD=" + PacketData;
        http.get(request, response, headers);
        ResponseStatus = response.status;


        if((response.body != PreviousResponseBody) && (response.body.substring(0,2) == "OK") && (ResponseStatus == 200)) {
            //only reset if connection was successful
            PulseCount = 0;
            incPower = 0;
            PreviousResponseBody = response.body;
            success = Particle.publish("TotalPulseCount", String(TotalPulseCount) , 60, PRIVATE);
            success = Particle.publish("CurrentPower", String(CurrentPower) , 60, PRIVATE);
            success = Particle.publish("AveragePower", String(AveragePower) , 60, PRIVATE);
        }
        else {
            success = Particle.publish("Upload Failed");
        }
        PreviousMinute = ThisMinute;
    }
}

String URLEncode(const char* msg)
{
    const char *hex = "0123456789abcdef";
    String encodedMsg = "";

    while (*msg!='\0'){
        if( ('a' <= *msg && *msg <= 'z')
                || ('A' <= *msg && *msg <= 'Z')
                || ('0' <= *msg && *msg <= '9') ) {
            encodedMsg += *msg;
        } else {
            encodedMsg += '%';
            encodedMsg += hex[*msg >> 4];
            encodedMsg += hex[*msg & 15];
        }
        msg++;
    }
    return encodedMsg;
}

While it would be nice to have it all in the Particle docs, where should it end?

Maybe it should suffice to have a note (which already is there) in the docs that these format place-holders go in line with the standard C/C++ ones (as do the printf(), scanf(), ... ones) which can be found all over the web.

http://www.cplusplus.com/reference/ctime/strftime/
http://www.cplusplus.com/reference/cstdio/printf/
http://www.cplusplus.com/reference/cstdio/scanf/

2 Likes

If you are using SYSTEM_THREAD(ENABLED); do you think you also need to use SYSTEM_MODE(SEMI_AUTOMATIC);?

you could try waitUntil(WiFi.ready); instead of constantly toggling wifi on and off.

https://docs.particle.io/reference/firmware/photon/#system-thread

also another side note, your use of httpClient (its blocking nature) is likely to cause you missed pulses in your state-change-detection method of reading inPin. Since you have blocking code, you may want to think about putting the counting into an interrupt function.

I am troubled with your persistent vars using retained not holding, but noticed this thread earlier, and I have not played with that "EEPROM-like" feature yet.

2 Likes

The problem is that my program is mixture of suggestions by different users and I do not fully understand what each line does. For example, I don't know about the relationship between the two lines you mentioned.

I got this code:

if(millis() - old_time >= 2000){        
    if(retry_count < 10){
        if(!WiFi.ready()){
            WiFi.connect();
            retry_count++;

        }
        else if (!Particle.connected()){
            Particle.connect();
            retry_count++;
        }
    }
    else{
        WiFi.off();
        retry_count = 0;
        WiFi.on();
    }
    old_time = millis();
}

from this thread: Starting Spark Core without wifi [SOLVED] - #3 by kennethlimcp

Again I am not sure how it works. My aim is to have the device keep counting even when there is no wifi connection.

Is there a httpclient that works asynchronously and that would keep the counting working even while it is attempting to send an http request?

I will look up interrupts and see if it solves my problem. In the meantime, thanks for pointing me in the right direction.

Just a brief and rough description:

  • SYSTEM_MODE(SEMI_AUTOMATIC) sets your system mode so that your program runs off without any WiFi and cloud connection, but you can choose to connect to WiFi only or WiFi and cloud at any time and from then on you don’t need to bother too much about maintaining the cloud connection (default AUTOMATIC always wants/requires cloud connection, MANUAL requires you to bother more when using the cloud)

  • SYSTEM_THREAD(ENABLED) is a beta feature that pushes the system functionality into a seperate (free running) thread while your own code runs in its own thread. So if your code blocks for some reason the system will still maintain the cloud connection, but not respond to Particle.function() calls or Particle.subscribe() triggers. And, since it’s a beta stage feature, might have some side effects or its behaviour might change to a certain degree till it gets to stable stage.

While for some use cases the two seem to have similar effects they do different things and do complement eachother.

1 Like

Going back to the original question - I do not think it is either desirable or expected that a photon/core should restart because of external wifi/internet availability.

I’m not saying this isn’t the case, just that I believe that is undesirable; and if it is happening it would be good to understand the root cause(s) and address them.

Persistent variables can be useful when you need to ride through resets due to power problems, but my view is that they are the wrong way to address the unit resetting when it should not be doing so.

2 Likes

Could it be a heat problem? Is there some way to measure the device temperature and temporarily switch off wifi (assuming that is the cause of the heating)? Since I am uploading only once a minute, would it make sense to switch off wifi after uploading and turning it back on before uploading again? How long does the photon take to connect?

Sometimes its as quick as 5 seconds, sometimes it takes 15 seconds to connect to wifi and the cloud.

Photons are designed to run 24x7. There should be no weird heating problems.

I’d suggest focusing on addressing/understanding root causes, not trying to paper over symptoms.

1 Like

It does raise the specter (it is getting close to halloween) of a power issue, though.

How are you powering your rig @osprey?

1 Like

I'm using a a USB charger similar to this one.

@osprey, what is the current rating on the adapter. It should say on the sticker 5V, xxxmA somewhere.

1 Like

It says 5V 750mA. I have now replaced it with one that reads 5V 2A. Will let you know if it resets in the next 24 hours.

Another thing you might need to look out for - apart from current rating - is the DC filter quality.
For charging purely rectified unfiltered DC will do but might not do for running a Photon and even less for analog sensors.

3 Likes

I replaced the USB adapter which came with my Samsung Camcorder (rated at 750ma) with the 2A adapter that came with the Raspberry Pi 2 and there was no reset in the past 24 hours, whereas previously it would do that after not more than 5 hours. So I think it is safe to assume that the root problem was the power adapter. I understand that, as @ScruffR suggested, the power rating alone is not an indicator of whether an adapter is suitable or not. I’m just surprised Samsung would not provide a quality adapter with their products.

Thank you all for your assistance and for introducing me to new concepts (for me) such as retained variables, the dashboard, time formatting, curl, Semi automatic modes, safe mode, interrupts and threading.

The quality of the product should be measured against the intended use, and for just charging a camcorder you don't need highly filtered DC.
But Samsung (or any other manufacturer) should not be "blamed" for providing you with a charger that can't do all the things you want to use it for, but they didn't intend it for.

2 Likes

Touché

1 Like

Happy to see that you figured out what may be causing/contributing to your problem.

I guess that’s all part of the ‘fun’ of electronics… Tracking down difficult-to-isolate problems which can manifest themselves in software or hardware!!!

:smirk:

2 Likes