Can you tell why this isn't publishing an event?

The following code doesn’t produce an event when viewing the Event tab on the console… and I think it should, shouldn’t it?

  • Im assuming I just screwed up the steps needed to publish? or the format?
    -The Lidar is getting good readings (I checked with a probe). Lidar is powered from USB.
    -The code compiled (I cut it down to put it on here so I may have a typo in this posting)
  • The LED write/reads where just put in there to turn on/off the onboard LED to help me tell where the code was… I didn’t see it come on or go off - so not even sure code got to that point.
  • Thank you in advance for any help.

In a nutshell, this is just supposed to take readings from the Lidar. Order the data and select a reading. Compare that to a threshold and report that it is above or below.

#define OCCP__FQCY     6000        
#define FREE__FQCY     6000         
#define THRESHOLD      1875                                           
#define NUM_READINGS     15        
#define READING_INDEX    12         
  
// Pin Connections:
int lidarReadingPin = A0;  
int boardLed        = D7;  

// Variable Declarations:
int         reading_vals[NUM_READINGS];
int  sorted_reading_vals[NUM_READINGS];
int  reading;                          
bool  currentStatus;               
bool previousStatus;  

//-------------------------------------------------------------------
void setup() {
    digitalWrite(boardLed, HIGH);
}
//-----------------------------------------------------------------------

void loop() {

          // 2. A set of 15 analog (signal out voltage) readings are taken
          for( int i=0; i<NUM_READINGS; i++ ) {
                // Read analog value
              reading_vals[i] = analogRead(lidarReadingPin);
          }

          // 3. The set of readings are sorted ascending
          //sorted_reading_vals = sort(reading_vals, (reading_vals + NUM_READINGS));
          
          for(int i=0; i<(NUM_READINGS -1); i++) {
            bool flag = true;
                for(int j=0;  j<(NUM_READINGS-(i+1)); j++) {
                    if(reading_vals[j] > reading_vals[j+1]) {
                        int t = reading_vals[j];
                        reading_vals[j] = reading_vals[j+1];
                        reading_vals[j+1] = t;
                        flag = false;
                     }
                }
            if (flag) break;
            }

          // 4. The value at MEDIAN_INDEX is selected as the reading
          reading = sorted_reading_vals[READING_INDEX];

          // 5. The reading is compared to THRESHOLD to determine currentStatus
          previousStatus = currentStatus;     // save previous status of space

          if( reading >= THRESHOLD ) {
             currentStatus = true;
           } else {
             currentStatus = false;
           }  

          // 6. If a change of previousStatus has occured - pusblish currentStatus to cloud
          if( previousStatus != currentStatus ) {
              
              //if ( Particle.connected() ) {
                    if( currentStatus == true ) {
                        Particle.publish( "status", "occupied", 60, PUBLIC, NO_ACK ); 
                    } else {
                        Particle.publish( "status", "free",     60, PUBLIC, NO_ACK );
                    }
               } else { 
                      Particle.connect();
               //}
           } 


          //7. Delay based on currentStatus value then loopback to 1.
              
              // Space is occupied
          if( currentStatus == true ) {         
              delay(OCCP__FQCY);  

              // Space is free
          } else {
              delay(FREE__FQCY);
          } 
          
    digitalWrite(boardLed, LOW);
}

You said that is a stripped down version which may contain typos. I guess the lack of pinMode(boardLed, OUTPUT); in setup() is one of them, right?

Also the else case for the commented if (Particle.connected()) check shouldn’t be there.

I’d recommend to make your publishes PRIVATE and drop the NO_ACK for your tests.
e.g.

  Particle.publish( "status", "occupied", PRIVATE );

previousStatus should rather be updated when a discrepancy (!=) is detected instead of unconditionally. This makes sure you won’t leave a potential change untreated.

Just one note

         if( reading >= THRESHOLD ) {
             currentStatus = true;
           } else {
             currentStatus = false;
           }  

this can be simplified into this

  currentStatus = (reading >= THRESHOLD);

But finally, I’m not sure your bubble sort does what you expect.
As soon you found one element j being greater than j+1 you stop iterating the rest of the i loop.
AFAICT this only puts the greates reading at the end of the array and then stops.
Try printing the entire “sorted” array after that sort attempt.

3 Likes

Thank you again for taking the time to help out.

  1. Not a typo, I’m just a n00b and missed it.
    pinMode(boardLed, OUTPUT);
    pinMode(lidarReadingPin, INPUT);
    have been added to void setup() { }

  2. Particle.connected() - I didn’t want this in there, I want to set this up SEMI-AUTOMATIC eventually but I read in Particle.publish this: If the cloud connection is turned on and trying to connect to the cloud unsuccessfully, Particle.publish may block for 20 seconds to 5 minutes. Checking Particle.connected() can prevent this. So I just wanted to avoid that. You are saying I don’t need to Particle.connect if it is not connected - is that because it checks Particle.connected at the start of each loop cycle for me?
    As you advised, I have removed Particle.connect. Also, for now, I have also commented out the Particle.connected check just to try and get a publish pushed through before adding complexity back in.

  3. I have modified Particle.publish to read as you advised

  4. previousStatus I tried to reason through your suggested change but I don’t understand it. In my head these three things happen in a loop and give me the behavior I’m looking for (namely publish a status message only when the status has changed).
    a. transfer currentStatus to previousStatus
    b. acquire the new status and update value in currentStatus
    c. if previousStatus != currentStatus => a change occurred - so publish base on the value of the new currentStatus
    d. If they are equal, then no change happened, so no action

  5. currentStatus = (reading >= THRESHOLD);
    #delicious

  6. Bubble Sort: I redid the sort and got basically the same thing - perhaps I am repeating an error. Regardless you are right - a print will solve the mystery… Can one simply - printf? :face_with_monocle: Where does it go? Will it post an event to the online particle console? To the attached USB CLI terminal? (This is an electron unit)

Uhm, sorry, but in that case you don't want to set pinMode(). You are analogRead()ing that pin and for that a special mode (AN_INPUT) is set inside the analogRead() function.

Not quite. What I wanted to say was: "With the line if( Particle.connected() ) { commented out, the followin } else { line is dangling without related if()".
So if you "disable" the if() line you also need to do away with the entire else block.
But you should actually rather check for if (Particle.connected()) but the reconnection should happen in a more orderly manner in some dedicated block - not just en pasant :wink:

You can't just printf() but you can Serial.printf() and that would go to the USB Serial interface where you can catch the output and print it with particle serial monitor --follow (or any other serial terminal program).

This is mainly a matter of style. But since any discrepancy between currentState and previousState would indicate that the change wasn't dealt with already it just seems better style to resolve that ASAP.
Imagine you are debugging your code after you dropped out of the if (previousStatus != currentStatus) block and checked whether or not the job was already done by comparing both values in the debugger.

Consequently this just seems cleaner

  currentStatus = (reading >= THRESHOLD);
  if (currentStatus != previousStatus) {
    // do whatever
    previousStatus = currentStatus; // mark job done
  }

With your approach it takes a lot longer (aeons for a microcontroller :wink: ) before the job gets marked done.
You also update previousStatus only on when the state has changed and not on each iteration of loop() for no reason or benefit.

2 Likes
  1. pinMode(lidarReadingPin, INPUT); Confirmed - it has been removed from void setup().
    sidenote: having it in setup did not prevent/interfere with operation so far as I could tell

  2. Particle.connect gotcha. As a alluded to - I planned on shifting to SEMI_AUTOMATIC with a keepAlive . Not best sure how to handle the Particle.connected check - I just want to both minimize data over an essentially permanent session and also avoid the potential problem with Particle.publish when it fails to publish… so that it doesn’t get held up - I’d rather it not wait for any ACK and just keep going and get the next one - in the true sense of UDP. I do want this all cleaned up and efficient - just not sure how to best put all those pieces together yet.

  3. printf - #flippinsweet - imperative to have the “print” tool in the coding toolbox. (I took a college course in C a few months ago and one in python 3… they constitute all the languages I currently have been exposed to (because I really can only write C in C++ .) I have done some work in x86_64 assembly too opr (dest, srce) style (AT&T?)

  4. stati - Well said… I’m convinced… I’ll adopt those changes.

  5. I’m very grateful for your help. Cheers! :beers:

2 Likes

Blockquote
I have gotten in the habit of trying the Particle.connect and or particle.process to usually get things going on to show my variables and functions in cloud. The keep.Alive(150) has been the sweet spot for me too.

1 Like
  1. Particle.keepAlive
    I’m surprised to hear you used 150 (sec) . The reference for the
    function recommends every 23 minutes.
    // SYNTAX Particle.keepAlive(23 * 60); // send a ping every 23 minutes

The 23 minutes is only possible when your provider has a special contract to keep the path valid for that long. Most providers don’t by default but Particle has negotiated special terms of service for their SIMs to allow for that.

So only Particle SIMs support 23 minutes and for these you don’t need to set Particle.keepAlive(23 * 60) at all since that’s the default.

2 Likes

Know of a list or map that would show the expected efficacy of the 23 min keepAlive? Know someone at Particle who might?

Decreasing keepAlive from 23 min to 2.5 min (150 sec) would push daily data usage up about 1220 bytes over (~factor of 10) the 23 min time period…
keepAlive overhead:
~8.8 Kb/day (264 Kb/month) with the 23min interval
~88 Kb/day ( 2.64 Mb/month) with the 2.5 min interval :hushed:

What’s the background of the question?
If you are using a Particle SIM you just stick with the 23 minutes. If you use a 3rd party SIM you have to stick with their keep alive periode, no matter what.
It’s not an arbitrary choice by Particle to increase the keep alive of 3rd party SIMs it’s a technical necessity.

1 Like

Ah, thank you for the rehashing/clarification. I am currently using the SIM provided by particle… so then I should be able to achieve the 23 min in the Continental US (at least).
Now that I know of this time distinction - I will ONLY be using Particle SIMs.
Down the road if I get a doodad to go to scale - I’ll need the data overhead reduction provided by use of Particle’s SIM.

1 Like

:+1:t2: