Counting Problems

Hi,
I have an application running on a Photon (works on Spark too) and it’s purpose is to count the number of times a red light on a power meter flashes. Basically it measures the consumption by counting the flashes which translate to 1Wh. I have a light sensor connected to D0 as a digital input and every time I detect the input changing state from low to high, I increment two counters - PulseCount and TotalPulseCount. I use something like PulseCount += 1 to increment both variables and they are both declared as uint32_t.

The application attempts to send an http request with the readings at the turn of every minute. The only difference between the two counters is that PulseCount resets to zero with each successful upload while the other one should keep on incrementing until it reaches 10000 and then resets to zero. However, for some strange reason, it is resetting to zero half way through, some times after just 200 counts. Before I post all the code and ask you to look through it for obvious bugs which I might miss, I wanted to ask you if you are aware of any problems where the Photon loses count at seemingly random intervals.

Thanks!

Nothing I’m aware of, but how’s about system restarts due to cloud connection fail/stall, powerloss, hard faults, …?
Any buffers overflowing into your counter?

1 Like

I suspect as much. Is there some easy way to keep a log of any resets?

@osprey, is you use the particle dashboard, you will see the Photon going offline.

1 Like

There are different options.

  • you could write the times when you go through setup() into your EEPROM
  • you can publish something to your HTTP server each time you go through setup()
  • you could subscribe to this event
event: spark/status
data: {"data":"online","ttl":"60","published_at":"2015-10-06T15:54:56.796Z","coreid":"<device ID>"}

and of course @peekay123’s suggestion :wink:

@osprey, is you use the particle dashboard2, you will see the Photon going offline.

I'm not too keen on spending time looking for something to happen since it happens randomly and could take hours between events. Unless you mean there is some kind of log I can look at.

@osprey, the dashboard IS a log of events :smile:

1 Like

Yes, but the dashboard scrolls (and is cute about whether it is visible in a browser window) - so if you’re not there to see it, you can be SOL (at least that’s been my experience with the dashboard and transient problems like this.) It’s a good diagnostic for reproducable events, but not for intermittent ones.

I have found using curl to dump the event stream to be more effective (although that can also reset, because the internet/cloud computing doesn’t like long lived TCP connections in general :smile:) If you click on the icon circled in the following image, the system should provide a curl command line that you can enter at your command line and capture logs without the limitations of a browser window.

Note that in many cases, you will not see a device offlien event, but it must be inferred from the “device online event”.

LOL! You're so right! I never tried the dashboard before, and I am only now (now that you mentioned it) slowly getting accustomed to it's benefits.

By command line, do you mean the DOS command prompt in Windows? When I tried it it said that curl is not a recognized command. Do I need to install something or set some paths? Please bear with me since I am new to this stuff.

Yes, curl is a command that you’ll have to install.

I think you can download it from somewhere linked from the curl downloads page.

Then you would run it from the DOS command prompt. I’m not a windows user, so I do not know what your options are for ensuring that the scroll history is retained; maybe someone else can chime in here.

1 Like

OK. From looking at the dashboard, it appears that if there is a temporary loss of wifi signal, the Photon behaves as if it was reset as soon as a connection is reestablished. I know this is something obvious for you guys. Is there a way to prevent this, that is, have the Photon/Core keep looping, counting and doing its thing and then resume sending the HTTP requests as soon as the wifi signal is back?

What about the retained var? If it is a soft reset the count should persist through that right?
https://docs.particle.io/reference/firmware/photon/#storing-data-in-backup-ram

1 Like

Agreed retained variables are perfect for this, and even one better is to use system threading too, that way you can still count while not connected and once connected it can send the totals.

Here is some code I wrote just the other day to do exactly what your doing but reading a reed switch. And I’m actually in progress to make it report total consumption and the days consumption. I also added a function to set the current meter value to the unit, and changed the code slightly to report in litres instead of pulses

The first step should maybe be to employ SYSTEM_MODE(SEMI_AUTOMATIC) to rid yourself of the majority of problems when the cloud connection fails.
After that all the above :wink:

I added SYSTEM_MODE(SEMI_AUTOMATIC) and now my Photon is breathing white and appearing offline on dashboard. Also, I can't flash anything. Is there a way to get it out of semi automatic mode (without a factory reset), at least until I can flash a new firmware?

look to put your Photon into Safe Mode

2 Likes

Thanks!

After using retained variables, I am still experiencing premature resetting of counter values. Here’s my current code. How do I incorporate SYSTEM_MODE(SEMI_AUTOMATIC) in it without making the device go offline? I know my code is “noobish” so if you have any other suggestions about how to make it better, I am all ears. I definitely need to streamline the way I got the value of the DeviceTime variable and I am not sure I am using the best method to send an HTTP request.

    #include "HttpClient/HttpClient.h"
    #include "application.h"
    
    STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));
    //SYSTEM_MODE(SEMI_AUTOMATIC);
    
    //Settings//
    String DeviceID = "XXXXXX";
    String TargetHostName = "yyy.yyy.com";
    ////////////
    
    
    int val = 0;
    int inPin  = D0;
    int outPin = D7;
    int PreviousSecond = -1;
    int ThisSecond = -1;
    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;
    
    
    HttpClient http;
    http_header_t headers[] = {
        { "Accept" , "*/*"},
        { NULL, NULL } // NOTE: Always terminate headers will NULL
    };
    http_request_t request;
    http_response_t response;
    
    void setup() {
        pinMode(outPin, OUTPUT);
        pinMode(inPin,  INPUT);
        Time.zone(2);
        PreviousSecond = Time.second();
        Particle.variable("PulseCount", &TotalPulseCount, INT);
        
        bool success;
        success = Particle.publish("Device Started");
    }
    
    void loop() {
        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; 
                }
            }
            ///////////////////////
            PreviousSensorState = SensorState;
        }
        ////////////////
        
        //Transmit Pulsecount at the turn of the minute//
        ThisMinute = Time.minute();
        if(ThisMinute != PreviousMinute) {
            //will optimize this once I figure out how string formatting works//
            DeviceTime = String(Time.year()).substring(2);
            if(String(Time.month()).length()==1)
                {DeviceTime += "0" + String(Time.month());}
            else
                {DeviceTime += String(Time.month());}
            if(String(Time.day()).length()==1)
                {DeviceTime += "0" + String(Time.day());}
            else
                {DeviceTime += String(Time.day());}
    
            if(String(Time.hour()).length()==1)
                {DeviceTime += "0" + String(Time.hour());}
            else
                {DeviceTime += String(Time.hour());}
                
            if(String(Time.minute()).length()==1)
                {DeviceTime += "0" + String(Time.minute());}
            else
                {DeviceTime += String(Time.minute());}
                
            if(String(Time.second()).length()==1)
                {DeviceTime += "0" + String(Time.second());}
            else
                {DeviceTime += String(Time.second());}
            ////////////////////////////////////////////////////////////////////
            
            PacketData = DeviceID + ";" + String(PulseCount) + ";" + DeviceTime + ";" + String(TotalPulseCount);
            
            //***Using HTTP Client***//
            request.hostname = TargetHostName;
            request.port = 80;
            request.path = "/spark_receiver.ashx?PD=" + PacketData;
            http.get(request, response, headers);
            ResponseStatus = response.status;
            ///////////////////////////
            
            bool success;
            
            if((response.body != PreviousResponseBody) && (response.body.substring(0,2) == "OK") && (ResponseStatus == 200)) {
                //only reset if connection was successful
                PulseCount = 0;
                PreviousResponseBody = response.body;
                success = Particle.publish("TotalPulseCount", String(TotalPulseCount) , 60, PRIVATE);
            }
            else {
                success = Particle.publish("Upload Failed");
            }
            
            PreviousMinute = ThisMinute;
        }
        /////////////////////////////////////////////////
    }

a few comments for you to consider while you hunt down your issues...

You may wish to consider (to get the program performing better) eliminating the use of String class which can really wreak havoc on memory... consider using C strings (char arrays).

you create bool success in your setup() function it gets destroyed as soon as setup() ends, then you recreate it again in loop() where it will again get destroyed on exit of loop(). Do you want a persistent variable there?. Read up on "scope."

Have you tried threading?

as a side note, look to make your code more readable by eliminating all those forward-leaning hashmarks (you know that the compiler interprets those... so use them in pairs or with the asterisk, e.g. /my comment/) and all that white space... and pick a method to use curly braces that is consistent .

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

STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));
//SYSTEM_MODE(SEMI_AUTOMATIC);

String DeviceID = "XXXXXX";
String TargetHostName = "yyy.yyy.com";

int val = 0;
int inPin  = D0;
int outPin = D7;
int PreviousSecond = -1;
int ThisSecond = -1;
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;

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

void setup() 
{
  pinMode(outPin, OUTPUT);
  pinMode(inPin,  INPUT);
  Time.zone(2);
  PreviousSecond = Time.second();
  Particle.variable("PulseCount", &TotalPulseCount, INT);
  bool success;
  success = Particle.publish("Device Started");
}

void loop() 
{
  val = digitalRead(inPin);
  SensorState = !val;
  digitalWrite(outPin, SensorState);
  if (SensorState != PreviousSensorState) 
  {
    //Detect Leading Edge//
    if (SensorState == true) 
    {
      PulseCount += 1;
      TotalPulseCount += 1;
      if (TotalPulseCount == 10000) 
      {
        TotalPulseCount = 0;
      }
    }
    PreviousSensorState = SensorState;
  }
  ThisMinute = Time.minute();
  if (ThisMinute != PreviousMinute) 
  {
    DeviceTime = String(Time.year()).substring(2);
    if (String(Time.month()).length() == 1)
    {
      DeviceTime += "0" + String(Time.month());
    }
    else
    {
      DeviceTime += String(Time.month());
    }
    if (String(Time.day()).length() == 1)
    {
      DeviceTime += "0" + String(Time.day());
    }
    else
    {
      DeviceTime += String(Time.day());
    }
    if (String(Time.hour()).length() == 1)
    {
      DeviceTime += "0" + String(Time.hour());
    }
    else
    {
      DeviceTime += String(Time.hour());
    }

    if (String(Time.minute()).length() == 1)
    {
      DeviceTime += "0" + String(Time.minute());
    }
    else
    {
      DeviceTime += String(Time.minute());
    }

    if (String(Time.second()).length() == 1)
    {
      DeviceTime += "0" + String(Time.second());
    }
    else
    {
      DeviceTime += String(Time.second());
    }
    PacketData = DeviceID + ";" + String(PulseCount) + ";" + DeviceTime + ";" + String(TotalPulseCount);
    request.hostname = TargetHostName;
    request.port = 80;
    request.path = "/spark_receiver.ashx?PD=" + PacketData;
    http.get(request, response, headers);
    ResponseStatus = response.status;
    bool success;
    if ((response.body != PreviousResponseBody) && (response.body.substring(0, 2) == "OK") && (ResponseStatus == 200)) 
    {
      PulseCount = 0;
      PreviousResponseBody = response.body;
      success = Particle.publish("TotalPulseCount", String(TotalPulseCount) , 60, PRIVATE);
    }
    else {
      success = Particle.publish("Upload Failed");
    }
    PreviousMinute = ThisMinute;
  }
}

Once you do that, forum members can 'see' a lot more :wink:

3 Likes

The docs have a rather helpful search feature.
When using it with SYSTEM_MODE or SEMI_AUTOMATIC you’ll find a description of the System Modes
https://docs.particle.io/reference/firmware/photon/#system-modes

And there you’ll find a reference to Particle.connect() which you need to call in order to connect to the cloud.
You can do this on demand (e.g. via a button, TCP/HTTP packet, …) or in setup().
If you only want WiFi connection without the cloud you could use WiFi.connect() instead.

1 Like