Help with Switch Case on Tracker SoM

Hey Particle Team, I am trying to create a switch case that can be called from Particle.function to change device useCase. I have a bunch of errors, would love some feedback on this!

#include "Particle.h"

#include "tracker_config.h"
#include "tracker.h"

#include "Air_Quality_Sensor.h"
#include "Adafruit_BME280.h"
#define AQS_PIN A2


SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

PRODUCT_ID(TRACKER_PRODUCT_ID);
PRODUCT_VERSION(TRACKER_PRODUCT_VERSION);

SerialLogHandler logHandler(115200, LOG_LEVEL_TRACE, {
    { "app.gps.nmea", LOG_LEVEL_INFO },
    { "app.gps.ubx",  LOG_LEVEL_INFO },
    { "ncp.at", LOG_LEVEL_INFO },
    { "net.ppp.client", LOG_LEVEL_INFO },
});

// Library: Grove_Temperature_And_Humidity_Sensor
AirQualitySensor aqSensor(AQS_PIN);
Adafruit_BME280 bme;


// Sample the temperature sensor every 2 seconds. This is done so the outlier values can be filtered out easily.
const unsigned long CHECK_PERIOD_MS = 2000;
unsigned long lastCheck = 0;
int useCaseState = 0; // useCase 1 = Cold Chain(temp/humid), useCase 2 (AQM) = , useCase 3 = (pressure)



void locationGenerationCallback(JSONWriter &writer, LocationPoint &point, const void *context); // Forward declaration


void setup()
{
    Tracker::instance().init();

    aqSensor.init();
    bme.begin();

    Particle.function("Input",thisUseCase);

    // Callback to add key press information to the location publish
    Tracker::instance().location.regLocGenCallback(locationGenerationCallback);

    Particle.connect();
}

void loop()
{
    Tracker::instance().loop();

    if (millis() - lastCheck >= CHECK_PERIOD_MS) {
        lastCheck = millis();
    }
}


thisUseCase (String input){
    if input = "Cold Chain"
        useCaseState = 1;
    
    if input = "heavyTrucking"
        useCaseState = 2;
    
    if input = "railCar"
        useCaseState = 3;
    
}



// put in some function and let it redirect 

void locationGenerationCallback(JSONWriter &writer, LocationPoint &point, const void *context)
{
    callback (input){
        parseFunction();
    }

}
parseFunction (input){
    switch (useCaseState){
        case 1: coldChain()
        break;

        case 2: railCar()
        break;

        case 3: heavyTrucking()
        break;
    }
}


coldChain (){
    // Read Measurments from BME 280
    int temp = (int)bme.readTemperature();
    int humidity = (int)bme.readHumidity();

    // Add Names under device page
    writer.name("Temperature").value(temp, 1);
    writer.name("Humidity").value(humidity, 1);
}

railCar (){
    // Read Measurments from BME 280
    int pressure = (int)(bme.readPressure() / 100.0F);
    int humidity = (int)bme.readHumidity();

    // Add Names under device page
    writer.name("Pressure").value(pressure, 1);
    writer.name("Humidity").value(humidity, 1);
=
}

heavyTrucking(){
    // Read Measurments from Air Quality v1.2
    // Persona 2
    int quality = aqSensor.slope();
    String qual = "None";

    if (quality == AirQualitySensor::FORCE_SIGNAL)
    {
        qual = "Danger";
    }
    else if (quality == AirQualitySensor::HIGH_POLLUTION)
    {
        qual = "High Pollution";
    }
    else if (quality == AirQualitySensor::LOW_POLLUTION)
    {
        qual = "Low Pollution";
    }
    else if (quality == AirQualitySensor::FRESH_AIR)
    {
        qual = "Fresh Air";
    }

    // Write AQ under Device Page
    writer.name("Quality").value(qual, 15); 

}




Posting the errors would be helpful :wink:

However, even without them we can guess what some of the issues are the compiler will complain about:

  • you are missing a void before parseFunction() (and your other functions too)
  • you are missing the datatype of input in the parameter list of parseFunction()
  • you define parseFunction() to take one parameter, but when calling it you are passing none
  • you are missing the definition of callback() entirely
  • in C/C++ if statements require you to pack the condition in parentheses
  • in C/C++ equality checks are not performed via the assignment operator (=) but the equality operator (==)
  • you got a stray = at the end of railCar()

So far the errors I could spot.

And here some suggestions

  • in heavyTrucking() you could also use a switch instead of if() .. else if() .. else ..
  • try to avoid String wherever possible and rather go with char arrays
    e.g
  char qual[16];
  switch (quality) {
    case AirQualitySensor::HIGH_POLLUTION:
      strncpy(qual, "High Pollution", sizeof(qual));
      break;
    ...
    default:
      strncpy(qual, "None", sizeof(qual));
  }
  writer.name("Quality").value(qual, sizeof(qual));
2 Likes

Thanks @ScruffR.

#include "Particle.h"
#include "tracker_config.h"
#include "tracker.h"
#include "Air_Quality_Sensor.h"
#include "Adafruit_BME280.h"
#define AQS_PIN A2

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);
PRODUCT_ID(TRACKER_PRODUCT_ID); 
PRODUCT_VERSION(TRACKER_PRODUCT_VERSION); 

SerialLogHandler logHandler(115200, LOG_LEVEL_TRACE, {
    { "app.gps.nmea", LOG_LEVEL_INFO },
    { "app.gps.ubx",  LOG_LEVEL_INFO },
    { "ncp.at", LOG_LEVEL_INFO },
    { "net.ppp.client", LOG_LEVEL_INFO },
}); 

AirQualitySensor aqSensor(AQS_PIN); 
Adafruit_BME280 bme; 

const unsigned long CHECK_PERIOD_MS = 2000;
unsigned long lastCheck = 0;
int useCaseState(int input); // useCase 1 = Cold Chain(temp/humid), useCase 2 (AQM) = , useCase 3 = (pressure) 
int input = 0; // not sure this should be added?


void locationGenerationCallback(JSONWriter &writer, LocationPoint &point, const void *context); 


void setup()
{
    Tracker::instance().init(); 

    aqSensor.init();

    bme.begin();

    Particle.function("Switch Case", useCaseState);

    Tracker::instance().location.regLocGenCallback(locationGenerationCallback);

    Particle.connect(); 
}


void loop()
{
    Tracker::instance().loop(); 

    if (millis() - lastCheck >= CHECK_PERIOD_MS) {

        // Should i do anything here?
        lastCheck = millis(); 

    }
}

void locationGenerationCallback(JSONWriter &writer, LocationPoint &point, const void *context)
{
    callback (input){ // not sure i need this here? 
        parseFunction();
    }
    
}
// Should void be added here? is the switch case right, when 1 is called in function useCaseState the device will adpot coldChian method
void parseFunction (input){
    switch (useCaseState){ 
        case 1: coldChain() 
        break;

        case 2: railCar() 
        break;

        case 3: heavyTrucking()
        break;
    }
}




void coldChain (){
    int temp = (int)bme.readTemperature();
    int humidity = (int)bme.readHumidity();

    writer.name("Temperature").value(temp, 1); 
    writer.name("Humidity").value(humidity, 1);
}

void railCar (){
    int pressure = (int)(bme.readPressure() / 100.0F);
    int humidity = (int)bme.readHumidity();

    writer.name("Pressure").value(pressure, 1);
    writer.name("Humidity").value(humidity, 1);
}

void heavyTrucking(){

    int quality = aqSensor.slope();
    char qual[16];

  switch (quality) {
    case AirQualitySensor::FORCE_SIGNAL:
      strncpy(qual, "Danger", sizeof(qual));
      break;

    case AirQualitySensor::HIGH_POLLUTION:
      strncpy(qual, "High Pollution", sizeof(qual));
      break;

    case AirQualitySensor::LOW_POLLUTION:
      strncpy(qual, "Low Pollution", sizeof(qual));
      break;

    case AirQualitySensor::FRESH_AIR:
      strncpy(qual, "Fresh Air", sizeof(qual));
      break;
    
    default:
      strncpy(qual, "None", sizeof(qual));
  }
  writer.name("Quality").value(qual, sizeof(qual));
}

I have updated the code and managed to work on most of the errors. I have attached a picture of the errors i am getting.

Ultimately i am trying achieve the following:

  • Call cold chain, heavy trucking or rail car on function in console
  • the device adopts the persona based on input
  • data will be added to tracker through writer.name and show on device map

Would appreciate any feedback and help :raised_hands:


The docs do state that Particle.function() requires a callbeck funciton that takes a String

But you are passing a callback function that takes an int as parameter. That doesn’t work.

image
This I already addressed in my previous post

So was this

You may want to re-read what I wrote above and try to understand what I meant.
If I didn’t express myself clearly enough, quote the statement and explain what was not clear :wink:

Finally you introduced a new mistake with this

You are using the function useCaseState() like a variable which will not work the way you expect it to do - although it probably will only produce a warning rather than an error.

And this

ignores what the docs say about Particle.function()

1 Like

Made it work!! Thanks @ScruffR for help and feedback.

#include "Particle.h"
#include "tracker_config.h"
#include "tracker.h"
#include "Air_Quality_Sensor.h"
#include "Adafruit_BME280.h"
#define AQS_PIN A2

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);
PRODUCT_ID(TRACKER_PRODUCT_ID); 
PRODUCT_VERSION(TRACKER_PRODUCT_VERSION); 

SerialLogHandler logHandler(115200, LOG_LEVEL_TRACE, {
    { "app.gps.nmea", LOG_LEVEL_INFO },
    { "app.gps.ubx",  LOG_LEVEL_INFO },
    { "ncp.at", LOG_LEVEL_INFO },
    { "net.ppp.client", LOG_LEVEL_INFO },
}); 

AirQualitySensor aqSensor(AQS_PIN); 
Adafruit_BME280 bme; 

const unsigned long CHECK_PERIOD_MS = 2000;
unsigned long lastCheck = 0;

#define ColdChain 1
#define Truck 2
#define Rail 3
int useCaseVal = 0; // 1 = cold chain, 2= truck, 3= rail
int useCaseState(String input); // forward definition for .cpp



void locationGenerationCallback(JSONWriter &writer, LocationPoint &point, const void *context); 


void setup()
{
    Tracker::instance().init(); 

    aqSensor.init();

    bme.begin();

    Particle.function("useCase", useCaseState);

    Tracker::instance().location.regLocGenCallback(locationGenerationCallback);

    Particle.connect(); 
}


void loop()
{
    Tracker::instance().loop(); 

    if (millis() - lastCheck >= CHECK_PERIOD_MS) {

        // Should i do anything here?
        lastCheck = millis(); 

    }
}

int useCaseState(String command)
{
  if(command == "cold chain")
  {
      useCaseVal = ColdChain;
  }
  if(command == "truck")
  {
      useCaseVal = Truck;
  }
  if(command == "rail car")
  {
      useCaseVal = Rail;
  }
}

void locationGenerationCallback(JSONWriter &writer, LocationPoint &point, const void *context)
{

int temp = (int)bme.readTemperature();
int humidity = (int)bme.readHumidity();   
int pressure = (int)(bme.readPressure() / 100.0F);
int quality = aqSensor.slope();
String qual = "None";



switch (useCaseVal) {
        case ColdChain:
            writer.name("Temperature").value(temp, 1); 
            writer.name("Humidity").value(humidity, 1);
        break;
        case Truck:
            if (quality == AirQualitySensor::FORCE_SIGNAL)
            {
                qual = "Danger";
            }
            else if (quality == AirQualitySensor::HIGH_POLLUTION)
            {
                qual = "High Pollution";
            }
            else if (quality == AirQualitySensor::LOW_POLLUTION)
            {
                qual = "Low Pollution";
            }
            else if (quality == AirQualitySensor::FRESH_AIR)
            {
                qual = "Fresh Air";
            }

            // Write AQ under Device Page
            writer.name("Quality").value(qual, 16); 
        break;
        case Rail:
            writer.name("Pressure").value(pressure, 1);
            writer.name("Humidity").value(humidity, 1);
        break;
    }   
}