Panic SOS: Assert_Failed Help

Hi all, I’m not the greatest coder and would appreciate some help as to why I’m getting this SOS assert failure on my Photon running version 0.7. The assert failure basically kills my ability to do anything with the device until I run “particle doctor”. The assert failure occurs once I run the Particle.publish to read my webhook.

My code reads a JSON API and depending on the values on the webhook it changes the RGB value of 2 RGB LEDS. The webhook URL Is here: http://192.241.149.199:3000/device/ and my code is below.

Thank you!

// This #include statement was automatically added by the Particle IDE.
#include <ArduinoJson.h>

const char* HOUSE_A = "34003b000547363339343638";
const char* HOUSE_B = "3a0033000b47363339343638";
const char* HOUSE_C = "320061000d51353532343635";

int PriceRedPin = A4;    // RED pin of the LED to PWM pin **A4**
int PriceGreenPin = D0;  // GREEN pin of the LED to PWM pin **D0**
int PriceBluePin = D1;   // BLUE pin of the LED to PWM pin **D1**

int ConsumptionRedPin = A5;    // RED pin of the LED to PWM pin **A4**
int ConsumptionGreenPin = TX;  // GREEN pin of the LED to PWM pin **D0**
int ConsumptionBluePin = RX;   // BLUE pin of the LED to PWM pin **D1**

int PriceRedValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255
int PriceGreenValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255
int PriceBlueValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255

int ConsumptionRedValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255
int ConsumptionGreenValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255
int ConsumptionBlueValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255</td>

void setup() {

    WiFi.disconnect();
    WiFi.on();
    WiFi.setCredentials("Frugar", "906EBB2D43AD");

    Particle.subscribe("hook-response/getdata", getdata, MY_DEVICES);

      // Set up our pins for output
    pinMode( PriceRedPin, OUTPUT);
    pinMode( PriceGreenPin, OUTPUT);
    pinMode( PriceBluePin, OUTPUT);
    pinMode( ConsumptionRedPin, OUTPUT);
    pinMode( ConsumptionGreenPin, OUTPUT);
    pinMode( ConsumptionBluePin, OUTPUT);

    // turn them all off...
    analogWrite( PriceRedPin, PriceRedValue);
    analogWrite( PriceGreenPin, PriceGreenValue);
    analogWrite( PriceBluePin, PriceBlueValue);
    analogWrite( ConsumptionRedPin, ConsumptionRedValue);
    analogWrite( ConsumptionGreenPin, ConsumptionGreenValue);
    analogWrite( ConsumptionBluePin, ConsumptionBlueValue);
}

void getdata(const char *name, const char *data) {       // we're subscribed to a webhook event in the particle console. You'll need to set this up in your console
    String s = String(data);
    unsigned int n = s.length();

    char json[n];
    strcpy(json, s); //cleaning up some json

    DynamicJsonBuffer jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject(json);

    if (!root.success()) {
        //Serial.println("parseObject() failed");
        return;
    }

    const char* colorA = root["colora"];
    const char* colorB = root["colorb"];
    const char* colorC = root["colorc"];
    const char* priceColor = root["pricecolor"];

    PriceLedControl(priceColor);

    String coreID = System.deviceID();


    if (coreID == HOUSE_A)
    {
      ConsumptionLedControl(colorA);
    }
    else if (coreID == HOUSE_B)
    {
      ConsumptionLedControl(colorB);
    }
    else if (coreID == HOUSE_C)
    {
      ConsumptionLedControl(colorC);
    }
    else
    {
      ConsumptionLedControl("255,255,255");
    }

}

int PriceLedControl( String command )
{
    String colors[3];
    colors[0]="";
    colors[1]="";
    colors[2]="";

    int index = 0;
    for( int i = 0; i < command.length(); i++ )
    {
      if( index < 3 ){
        char c = command.charAt(i);
        colors[index] += c;

        if( c == ',') index++;
      }
    }

    // get the red component...
    PriceRedValue = colors[0].toInt();
    // now green
    PriceGreenValue = colors[1].toInt();
    // now blue
    PriceBlueValue = colors[2].toInt();

   // write the mixed color
   analogWrite( PriceRedPin, PriceRedValue);
   analogWrite( PriceGreenPin, PriceGreenValue);
   analogWrite( PriceBluePin, PriceBlueValue);

   return 1;
}

int ConsumptionLedControl( String command )
{
    String colors[3];
    colors[0]="";
    colors[1]="";
    colors[2]="";

    int index = 0;
    for( int i = 0; i < command.length(); i++ )
    {
      if( index < 3 ){
        char c = command.charAt(i);
        colors[index] += c;

        if( c == ',') index++;
      }
    }

    // get the red component...
    ConsumptionRedValue = colors[0].toInt();
    // now green
    ConsumptionGreenValue = colors[1].toInt();
    // now blue
    ConsumptionBlueValue = colors[2].toInt();

   // write the mixed color
   analogWrite( ConsumptionRedPin, ConsumptionRedValue);
   analogWrite( ConsumptionGreenPin, ConsumptionGreenValue);
   analogWrite( ConsumptionBluePin, ConsumptionBlueValue);

   return 1;
}

void loop(){

  while (WiFi.ready()){
    //if(abs(Time.minute() - lastTime) >= 5){ // if it's been mmore than five minutes
        Particle.publish("getdata", PRIVATE); 
        delay(30000);
  }
    //}

}

Where is your Particle.connect() call?
What’s the purpose of that inner while() in loop()?

2 Likes

I assumed that Particle.connect() is automatically called in automatic mode as long as I set up the Wifi credentials properly?

I guess I don’t need that inner ‘while(Wifi.ready())’. Just wanted to make sure I only send requests once a Wifi connection is established.

However, even if my Wifi credentials are set up properly, the assertion failure still occurs. I believe it has something to do with my “getdata” JSON parsing function.

Once your code deliberately disconnects from the cloud (as you do with WiFi.disconnect()) the system has to obey this decition till you tell it that you want to be connected again.

In that case you'd need to check for Particle.connected(). You may have a valid WiFi connection but that is no guarantee for also being connected to the cloud.
And if you wanted to make sure you are connected a simple if() would be better suited than a while()

You could add some Serial.print() statements in your code to get an idea where the crash happens.

I put in some Serial.print() statements and it looks like it’s crashing in my getdata() function either before or after this assignment String coreID = System.deviceID();.

I changed the declaration of String coreID as a global but that didn’t help.

The reason I am getting the Photon ID is because I have three different Photons that read the same webhook and based on which ID it is, it will decide which color to show on the RGB led.

I wonder, since there are three Photons publishing the same getdata() event, that the subscribe is getting confused between the which event to react to?

With Serial.print() you need to be aware that the output happens slightly after the actual statement as hardware interfaces are running async.

However, people who know me round here are probably sick of hearing it, but I’ll keep on repeating it wherever possible: Don’t use String when you can use pure C strings (aka character arrays).

Just a coding hint:
Whenever you are writing some custom parsing logic, it’s useful to add a comment at the beginning of the parsing block that states the format of the string you’re trying to parse.
That will make it easier for yourself when you come back to the same code in future and also if you want others to understand what’s going on.

Looking at your parsing effort there I could imagine a much simpler way of doing it, but to be sure a data sample would be helpful :wink:

int ConsumptionLedControl( String command )
{ // command format "rrr,ggg,bbb": e.g. 0,50,255
  switch(sscanf(command, "%d,%d,%d", &ConsumptionRedValue, &ConsumptionGreenValue, &ConsumptionBlueValue)) 
  { // only set the values that could be parsed correctly
    case 3:
     analogWrite( ConsumptionBluePin, ConsumptionBlueValue);
    case 2:
      analogWrite( ConsumptionGreenPin, ConsumptionGreenValue);
    case 1:
      analogWrite( ConsumptionRedPin, ConsumptionRedValue);
    default:
      break;
  }
  // return the combined integer value of the parsed color
  return ConsumptionRedValue << 16 | ConsumptionGreenValue << 8 | ConsumptionBlueValue << 0;
}

Also this block of code could be tuned a bit

int PriceRedPin = A4;    // RED pin of the LED to PWM pin **A4**
int PriceGreenPin = D0;  // GREEN pin of the LED to PWM pin **D0**
int PriceBluePin = D1;   // BLUE pin of the LED to PWM pin **D1**

int ConsumptionRedPin = A5;    // RED pin of the LED to PWM pin **A4**
int ConsumptionGreenPin = TX;  // GREEN pin of the LED to PWM pin **D0**
int ConsumptionBluePin = RX;   // BLUE pin of the LED to PWM pin **D1**

int PriceRedValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255
int PriceGreenValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255
int PriceBlueValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255

int ConsumptionRedValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255
int ConsumptionGreenValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255
int ConsumptionBlueValue = 0; // Full brightness for an Cathode RGB LED is 0, and off 255

Instead of individual variables, I’d rather go with arrays. This opens some extra options to streamline your code like this

#include <ArduinoJson.h>

enum COLORS 
{ RED       = 0
, GREEN     = 1
, BLUE      = 2
, COL_COUNT = 3
};

enum CATEGORIES 
{ PRICE     = 0
, CONSUMPT  = 1
, CAT_COUNT = 2
};

const int pin[CAT_COUNT][COL_COUNT] = 
{ { A4, D0, D1 }     // PRICE    PWM pins RED, GREEN, BLUE
, { A5, TX, RX }     // CONSUMPT PWM pins RED, GREEN, BLUE
};

int value[CAT_COUNT][COL_COUNT];


const char HOUSE[][25] = 
{ "34003b000547363339343638"
, "3a0033000b47363339343638"
, "320061000d51353532343635"
};
const int HOUSE_COUNT = sizeof(HOUSE) / sizeof(HOUSE[0]);

void setup() {
    WiFi.disconnect();
    WiFi.on();
    WiFi.setCredentials("Frugar", "906EBB2D43AD");

    Particle.subscribe("hook-response/getdata", getdata, MY_DEVICES);
    Particle.connect();
    
    for(int cat = 0; cat < CAT_COUNT; cat++) {
      for(int col = 0; col < COL_COUNT; col++) 
      {
        pinMode(pin[cat][col], OUTPUT);
        analogWrite(pin[cat][col], value[cat][col]);
      }
    }
}

void loop(){
  static uint32_t ms = 0;
  if (millis() - ms < 30000) return;

  ms = millis();
  if (Particle.connected())
    Particle.publish("getdata", PRIVATE); 
}

void getdata(const char *name, const char *data) {       // we're subscribed to a webhook event in the particle console. You'll need to set this up in your console
    char json[strlen(data)+1];
    strcpy(json, data); //cleaning up some json

    DynamicJsonBuffer jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject(json);

    if (!root.success()) return;

    const char* color[COL_COUNT] = { root["colora"], root["colorb"], root["colorc"] };
    const char* priceColor       = root["pricecolor"];

    PriceLedControl(priceColor);

    char id[25];
    strcpy(id, (const char*)System.deviceID());    
    int h;
    for (h = 0; h < HOUSE_COUNT; h++) 
      if (!strcmp(id, HOUSE[h])) break;
    
    switch(h) {
      case 0:
      case 1:
      case 2:
        ConsumptionLedControl(color[h]);
        break;
      default:
        ConsumptionLedControl("255,255,255");
        break;
    }
}

int parse(CATEGORIES cat, const char* command) 
{ // command format "rrr,ggg,bbb": e.g. 0,50,255
  int c = sscanf(command, "%d,%d,%d", &value[cat][RED], &value[cat][GREEN], &value[cat][BLUE]);
  
  for (int i = 0; i < c; i++) {
    value[cat][i] = constrain(value[cat][i], 0, 255);
    analogWrite(pin[cat][i], value[cat][i]);
  }
    
  return value[cat][RED] << 16 | value[cat][GREEN] << 8 | value[cat][BLUE] << 0;
}

int PriceLedControl( String command )
{ // command format "rrr,ggg,bbb": e.g. 0,50,255
  return parse(PRICE, command);
}

int ConsumptionLedControl( String command )
{ // command format "rrr,ggg,bbb": e.g. 0,50,255
  return parse(CONSUMPT, command);
}
2 Likes