SOS red blink and one solid red after Flashing New Program

Hi everyone…

I have a bit of experience with arduino, and have had luck getting through the API, but I’m stumped with uploading new firmware. It is a particular program that is giving me troubles… only two stock libraries.

I am thinking it may be a memory issue, but this is smaller than the arduino code I developed and that was under 30kB FLASH and about 1.5kBSRAM. It happens DEBUG_ON or not…

Code:

#include "Adafruit_DHT/Adafruit_DHT.h"
#include "LiquidCrystal/LiquidCrystal.h"

// -----------------------------------
// WiFi Controller
// -----------------------------------

#define DEBUG_ON
#define DISPLAY_UPDATE_TIME 3000UL
#define DIMMER_PIN D1
#define NUMBER_OF_MESSAGE_TYPES 17
#define DHTTYPE DHT11		// DHT 11 
//#define DHTTYPE DHT22		// DHT 22 (AM2302)
//#define DHTTYPE DHT21		// DHT 21 
#define DHT_SENSOR_PIN D6
#define NUMBER_OF_ACTION_BUTTONS 5
//
#ifdef  DEBUG_ON
#define DEBUG_PRINT(x)   Serial.print(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#define SERIAL_START(x)  Serial.begin(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#define SERIAL_START(x)
#endif
//
typedef enum{
  LCD_WIND, LCD_TIME, LCD_ALARM_STATUS, LCD_GARAGE, LCD_GUEST_GARAGE, LCD_IP_ADDRESS, LCD_TEMPERATURE, LCD_AC_SETPOINT, LCD_OUTSIDE_TEMP, LCD_WEATHER, LCD_FORECAST, LCD_MESSAGE, LCD_HI_LOW, LCD_EMAIL} 
lcdState;
//
lcdState state = LCD_TIME;  // display start on Time
//
LiquidCrystal lcd(D0, D1, D2, D3, D4, D5);
//
DHT dht(DHT_SENSOR_PIN, DHTTYPE);
//
//
boolean messageFlag = false;
unsigned long myTimerStart;
unsigned long myTimerDuration;
int mySignal = 0;
boolean lightOn;
boolean relayState;
boolean garageOpen = false;
boolean guestGarageOpen = false;
char customMessage [30];
char weatherCondition[30] = {
  "  Not Yet Reported"};
char weatherForecast[30] = {
  "  Not Yet Reported"};  
int outdoorTemp = -99;
int outdoorHumid = -99;
int todayHigh = -99;
int todayLow = -99;
int airconSetpoint = 78;
int alarmArmed = -1;
int windSpeed = 99;
char windDirection[6] = {
  "ZZZ"};
char myCharBuffer[30];
byte brightLevel = 0;
byte oldBrightLevel;
int emailCount = -1;
const char *messageType[NUMBER_OF_MESSAGE_TYPES] = {
  "?ledStatus=", "?alarmState=", "?garageState=", "?guestGarageState=", "?weatherCondition=", "?outsideTemp=", "?outsideHumid=", "?airconSetpoint=", "?weatherForecast=", "?messageData=", "?todayHigh=", "?todayLow=", "?windSpeed=", "?windDirection=", "?relayState=", "?brightLevel=", "?emailCount="};
//
const char *dayOfWeek[] = { 
  "       Sunday","       Monday", "      Tuesday", "     Wednesday", "      Thursday", "       Friday", "      Saturday"};

//
byte buttonPin[NUMBER_OF_ACTION_BUTTONS] = {
  A0, A1, A2, A3, A4};
byte lastButtonState[NUMBER_OF_ACTION_BUTTONS];
//
// name the pins
int led1 = D0;
int led2 = D1;
int led3 = D7;
unsigned long startMillis;
int blinkOn = 0;

// This routine runs only once upon reset
void setup()
{
   SERIAL_START(9600);
   //Register our Spark function here
   Spark.function("led", ledControl);
   Spark.function("blinkLed", blinkLed);
   Spark.function("getMyData", getMyData);

   // Configure the pins to be outputs
   pinMode(led1, OUTPUT);
   pinMode(led2, OUTPUT);
   pinMode(led3, OUTPUT);
   dht.begin();
   // Initialize both the LEDs to be OFF
   digitalWrite(led1, LOW);
   digitalWrite(led2, LOW);
}


// This routine loops forever
void loop()
{
  if(blinkOn)
  {
      if (millis() - startMillis > 100UL)
      {
          digitalWrite(led3,!digitalRead(led3));
          startMillis = millis();
      }
  }
  else
  {
      digitalWrite(led3,LOW);
  }
  lcdUpdate();
  getTime();
  messageTimer();
  for (byte i = 0; i < NUMBER_OF_ACTION_BUTTONS; i++)
  {
    byte buttonState = digitalRead(buttonPin[i]);
    if (buttonState == LOW && lastButtonState[i] == HIGH)
    {
      buttonPress(i);
    }
    lastButtonState[i] = buttonState;
  }
}
//
void buttonPress(int buttonNumber)
{
    delay(1);
}
//
void getTime()
{
  static unsigned long lastTimeSync;
  if (millis() - lastTimeSync > 3600UL) 
  {
    Spark.syncTime();
    lastTimeSync = millis();
  }
}
//
void lcdUpdate()
{
  static unsigned long lastDisplayChangeTime;
  if (millis() - lastDisplayChangeTime >= DISPLAY_UPDATE_TIME)
  {
    switch (state) 
    {
    case LCD_TIME:
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      DEBUG_PRINT(F("Time: "));
      DEBUG_PRINT(Time.hourFormat12());
      DEBUG_PRINT(F(":"));
      DEBUG_PRINT(Time.minute());
      DEBUG_PRINTLN(Time.isAM() ? "a" : "p");
      DEBUG_PRINTLN(dayOfWeek[Time.weekday() - 1]);
      //lcd.print(dayOfWeek[weekday() - 1]);
      displayStatus();
      if (emailCount != -1)
        state = LCD_EMAIL;
      else
        state = LCD_ALARM_STATUS;
      break;
      //
    case LCD_EMAIL:
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("    Email Count"));
      DEBUG_PRINT(F("emails: "));
      lcd.setCursor(0,2);
      lcd.print(F("         "));
      lcd.print(emailCount);
      DEBUG_PRINTLN(emailCount);
      displayStatus();
      state = LCD_ALARM_STATUS;
      break;
      //
    case LCD_ALARM_STATUS:
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("    Alarm Status"));
      DEBUG_PRINT(F("Alm: "));
      lcd.setCursor(0,2);
      if (alarmArmed == 0)
      {
        lcd.print(F("     Not  Armed"));
      }
      else if (alarmArmed == 1)
      {
        lcd.print(F("        Armed"));
      }
      else
      {
        lcd.print(F("  Not Yet Reported"));
      }
      DEBUG_PRINTLN(alarmArmed ? F("Yes") : F("NO"));
      displayStatus();
      state = LCD_GARAGE;
      break;
      //
    case LCD_GARAGE:
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("    Main  Garage"));
      DEBUG_PRINT(F("Garage: "));
      lcd.setCursor(0,2);
      if (garageOpen == 0)
      {
        lcd.print(F("       Closed"));
      }
      else if (garageOpen == 1)
      {
        lcd.print(F("        Open"));
      }
      else
      {
        lcd.print(F("  Not Yet Reported"));
      }
      DEBUG_PRINTLN(garageOpen ? F("OPEN") : F("CLOSE"));
      displayStatus();
      state = LCD_GUEST_GARAGE;
      break;
      //
    case LCD_GUEST_GARAGE:
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("    Guest Garage"));
      DEBUG_PRINT(F("Guest: "));
      lcd.setCursor(0,2);
      if (guestGarageOpen == 0)
      {
        lcd.print(F("       Closed"));
      }
      else if (guestGarageOpen == 1)
      {
        lcd.print(F("        Open"));
      }
      else
      {
        lcd.print(F("  Not Yet Reported"));
      }
      DEBUG_PRINTLN(guestGarageOpen ? F("OPEN") : F("CLOSE"));
      displayStatus();
      state = LCD_TEMPERATURE;
      break;
      //
    case LCD_TEMPERATURE:
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F(" Temperture: "));
      DEBUG_PRINT(F("Inside Temp:"));
      lcd.print(dht.getTempFarenheit(), 0);
      lcd.print(char(223));
      lcd.print(F("F"));
      lcd.setCursor(0,2);
      lcd.print(F("   Humidity: "));
      lcd.print(dht.getHumidity(), 0);
      DEBUG_PRINT(F("Humidity:"));
      DEBUG_PRINTLN(dht.getHumidity());
      lcd.print(F("%"));
      displayStatus();
      state = LCD_AC_SETPOINT;
      break;
    case LCD_AC_SETPOINT:
      //
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("    A/C Setpoint"));
      lcd.setCursor(0,2);
      lcd.print(F("        "));
      lcd.print(airconSetpoint);
      lcd.print(char(223));
      lcd.print(F("F"));
      DEBUG_PRINT(F("A/C setpoint:"));
      DEBUG_PRINTLN(airconSetpoint);
      displayStatus();
      state = LCD_OUTSIDE_TEMP;
      break;
      //
    case LCD_OUTSIDE_TEMP:
      //
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F(" Outdoor Temp:"));
      DEBUG_PRINT(F("Ext. Temp:"));
      lcd.print(outdoorTemp);
      lcd.print(char(223));
      lcd.print(F("F"));
      DEBUG_PRINTLN(outdoorTemp);
      lcd.setCursor(0,2);
      lcd.print(F("     Humidity:"));
      DEBUG_PRINT(F("Humidity:"));
      lcd.print (outdoorHumid);
      lcd.print(F("%"));
      DEBUG_PRINTLN(outdoorHumid);
      displayStatus();
      state = LCD_WEATHER;
      break;
      //
    case LCD_WEATHER:
      //
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("  Today's  Weather"));
      DEBUG_PRINT(F("Weather: "));
      lcd.setCursor(0,2);
      lcd.print(weatherCondition);
      DEBUG_PRINTLN(weatherCondition);
      displayStatus();
      state = LCD_HI_LOW;
      break;
      //
    case LCD_HI_LOW:
      //
      fastClearLCD();
      DEBUG_PRINTLN(F("Weather Hi/Lows"));
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("Today's High: "));
      lcd.print(todayHigh);
      lcd.print(char(223));
      lcd.print(F("F"));
      lcd.setCursor(0,2);
      lcd.print(F("         Low: "));
      lcd.print (todayLow);
      lcd.print(char(223));
      lcd.print(F("F"));
      displayStatus();
      if (windSpeed > 2)
      {
        state = LCD_WIND;
      }
      else
      {
        state = LCD_FORECAST;
        DEBUG_PRINTLN(F("wind too light to report..."));
      }
      break;
      // 
    case LCD_WIND:
      //
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("   Winds  Gusting"));
      DEBUG_PRINT(F("Winds: "));
      DEBUG_PRINTLN(windSpeed);
      lcd.print(F(" "));
      lcd.setCursor(1,2);
      if (windSpeed < 10) lcd.print(F(" "));
      lcd.print(windSpeed);
      lcd.print(F("mph from the "));
      lcd.print(windDirection);
      displayStatus();
      state = LCD_FORECAST;
      break; 
    case LCD_FORECAST:
      //
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("      Tomorrow"));
      DEBUG_PRINT(F("Forecast: "));
      lcd.setCursor(0,2);
      lcd.print(weatherForecast);
      DEBUG_PRINTLN(weatherForecast);
      displayStatus();
      if (messageFlag)
        state = LCD_MESSAGE;
      else 
        state = LCD_IP_ADDRESS;
      break;
      //  
    case LCD_MESSAGE:
      //
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      //
      if (mySignal == 2 && brightLevel > 0)
      {
        for (int i = 0; i < 20; i++)
        {
          digitalWrite(DIMMER_PIN, HIGH);
          delay(50);
          digitalWrite(DIMMER_PIN,LOW);
          delay(50);
        }
        analogWrite(DIMMER_PIN,brightLevel);
      }
      else if (mySignal == 1 && lightOn == 1)
      {
        beepTone();
      }
      if (mySignal != 0) 
      {
        lastDisplayChangeTime - millis();  // give the message back the time lost in the flash/blinking
      }
      //
      lcd.setCursor(0,1);
      lcd.print(F("  *** Message ***"));
      DEBUG_PRINT(F("Message: "));
      lcd.setCursor(0,2);
      lcd.print(customMessage);
      DEBUG_PRINTLN(customMessage);
      displayStatus();
      state = LCD_IP_ADDRESS;
      break;
      //
    case LCD_IP_ADDRESS:
      //
      fastClearLCD();
      lcd.setCursor(0,0);
      timeDate();
      lcd.setCursor(0,1);
      lcd.print(F("     IP Address"));
      DEBUG_PRINT(F("IP Address: "));
      lcd.setCursor(0,2);
      lcd.print("    ");
      for (byte thisByte = 0; thisByte < 4; thisByte++) // print the value of each byte of the IP address:
      {
        //lcd.print(Ethernet.localIP()[thisByte], DEC);
        if (thisByte < 3) lcd.print(".");
#ifdef DEBUG_ON
        //Serial.print(Ethernet.localIP()[thisByte], DEC);
#endif
        if (thisByte < 3) DEBUG_PRINT(".");
        else DEBUG_PRINTLN(F(" "));
      }
      lcd.print(F(" "));
      displayStatus();
      state = LCD_TIME;
      break;
      //      
    }
    lastDisplayChangeTime = millis();
    //DEBUG_PRINT(F("free ram:"));
    //DEBUG_PRINTLN(freeRam());
  } 
}
//
// These Functions get called whenever there is a matching API request
//
int ledControl(String command)
{
   int state = 0;
   //find out the pin number and convert the ascii to integer
   int pinNumber = (command.charAt(1) - '0') - 1;
   //Sanity check to see if the pin numbers are within limits
   if (pinNumber < 0 || pinNumber > 1) return -1;

   // find out the state of the led
   if(command.substring(3,7) == "HIGH") state = 1;
   else if(command.substring(3,6) == "LOW") state = 0;
   else return -1;

   // write to the appropriate pin
   digitalWrite(pinNumber, state);
   return 1;
}


int blinkLed(String status)
{
    if (status == "1")
    {
      blinkOn = 1;
      //digitalWrite(led2,HIGH);
      return 1;
    }
    else if (status == "0")
    {
      blinkOn = 0;
      //digitalWrite(led2,LOW);
      return 0;
    }
    else
    {
      return -1;
    }
}
//
int getMyData(String myData)
{
    delay(1);
    return -1;
}
//
void fastClearLCD()
{
  for (int i = 1; i < 3; i++)
  {
    lcd.setCursor(0,i);
    for (int j = 0; j < 20; j++)
    {
      lcd.print(F(" "));
    }
  }
}
//
void timeDate()
{
  if (Time.hourFormat12() < 10) lcd.print(F(" "));
  lcd.print(Time.hourFormat12());
  lcd.print(Time.minute() < 10 ? F(":0") : F(":"));
  lcd.print(Time.minute());
  lcd.print(Time.isAM() ? "am" : "pm");
  lcd.setCursor(9,0);
  if (Time.month() < 10) lcd.print(F(" "));
  lcd.print(Time.month());
  lcd.print(Time.day() < 10 ? F("/0") : F("/"));
  lcd.print(Time.day());
  lcd.print(F("/"));
  lcd.print(Time.year());
}
//
void displayStatus()
{
  lcd.setCursor(0,3);
  lcd.print(emailCount < 0? 0 : emailCount);
  if (emailCount == 1)
  {
    lcd.print(F(" eMail   "));
  }
  else
  {
    lcd.print(F(" eMails   "));
  }
  lcd.setCursor(11,3);
  if (alarmArmed != 1)
  {
    lcd.print(F("Not Armed"));
  }
  else
  {
    lcd.print(F("    Armed"));
  }
}
//
void beepTone()
{
    
}
void messageTimer()
{
  if (millis() - myTimerStart >= myTimerDuration * 60000UL)
  {
    messageFlag = false;
    mySignal = 0;
  }
}

@BulldogLowell
What is the behavior you are experiencing?

If you are getting a flashing RED SOS with 8 RED FLASHES then It’s probably a memory heap issue. From my experience you need at least 3KB SRAM.

OK, I misread your comment. You state you only are using 1.5KB SRAM so there should be plenty. Can you explain what problems you are having?

@mtnscott

thanks for the reply… I get the magic changing colours as the ‘upload’ proceeds, and then, just at it transitions from blinking blue to blinking cyan… I get an SOS with one solid blink of red following that. then rotates blinking blue, SOS, blinking cyan.

I removed the entire lcdUpdate() function and it uploads and works (minus that bit, obviously). Does Spark support the arduino F macro or does the compiler just ignore that, or do I need to edit that out?

@BulldogLowell

I think you are incorrectly using the (char) feature when trying to print a degree symbol
You have lcd.print(char(223)); when I think you want to have lcd.print((char) 223);

What I don’t understand is that you should be getting a compile time error with char not being defined as an array

@mtnscott

tried that:

lcd.print((char)223);

still, not loading, same error form… I took all of the F-macro out too.

for the internet Dev tool, how does one find the compiled size of a program?

About the code size:
When you build your project, you’ll get a success message with “(i)” (i in a circle). Press on that and you’ll see the compiler output.

Press on the circle i after the “Ready.” If it does not show up then add a to your file and verify again. Then after you have pressed the circle i you will see -

@BulldogLowell
At this point I suggest you start putting some debugging statements in your code. I typically use Serial.println("At test point"); in various places as I trace thru the code. I would try putting that line in various places within your lcdUpdate() and watching the output on your serial monitor before you get into your panic state.

Sorry, I’m not going a good time multi-tasking :slight_smile: I just looked at your code and you already have a lot of debugging print statements. How far does your code get before it panics?

1 Like

@ScruffR thanks!

@mtnscott

it looks like memory isn’t an issue…

I’ll get into the Serial.print()s… actually, I was thinking that the program didn’t finish loading… let u know.

Just as a side-note:
I can’t see any pinMode() setting for your action buttons. I guess you’d want something like pinMode(buttonPin[0], INPUT_PULLUP) in setup().

2 Likes

@ScruffR

Yeah, I added it in, thanks… I’m not getting to that part yet…

Nothing from Serial at all before the SOS panic lights with this program. I’m going to start choppin’ up that lcdUpdate function.

If you’d want to make sure, that you’ll definetly see all your debug output in your serial monitor, you might want to redefine your SERIAL_START this way

#define SERIAL_START(x)  Serial.begin(x);           \
                         while(!Serial.available()) \
                           SPARK_WLAN_Loop();

That way the setup() will be waiting for you to activate your serial monitor and “press any key”, before it starts spitting out debug messages.


Edit: Sorry, just tried this in Web IDE, and it complains for some reason - I’ll come back :blush: I had / instead of \ - now it should work

1 Like

BTW: How are you flashing your Core OTA, if it immediately enters panic mode, once you power it up?

That would be another perk in using the reworked SERIAL_START macro - you’d always have enough time to flash a new FW.

@ScruffR

Perhaps I mis-comunicated. I am flashing my Core over the air using the internet Dev.

The webpage tells me it is loaded, I see the on-board LED go through a multi-colour display, then settle in on Green flashing, then start to illuminate cyan, then SOS red…

am I answering your question?

OK, must sleep now… can try to conquer tomorrow…

thanks @ScruffR

@BulldogLowell, yes that was exactly what I meant.

But the Web IDE can’t actually tell you if the OTA flash actually did succeed.
It only tells you, if it could trigger a OTA cycle and got the expected acknowledge for it, but not if the flashing actually went all the way through.

To make sure it actually does work, you might want to flash a dummy sketch like Blink-a-LED to confirm the Core actually gets updated correctly and after that you can flash your own sketch again.

Sometimes a corrupt firmware just refuses to get replaced :wink: And you debug and debug, but just don’t get anywhere since all your attempts vanish during OTA flash.

@ScruffR

I am able to flash this following sketch… it is what I used to get familiar with the Spark.function() and within moments, I was able to add the little blink to the demo, and use a curl to make it toggle.

// -----------------------------------
// Controlling LEDs over the Internet
// -----------------------------------

// name the pins
int led1 = D0;
int led2 = D1;
int led3 = D7;
unsigned long startMillis;
int blinkOn = 0;

// This routine runs only once upon reset
void setup()
{
  //Register our Spark function here
  Spark.function("led", ledControl);
  Spark.function("blinkLed", blinkLed);

  // Configure the pins to be outputs
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);

  // Initialize both the LEDs to be OFF
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
}


// This routine loops forever
void loop()
{
  if(blinkOn)
  {
    if (millis() - startMillis > 100UL)
    {
      digitalWrite(led3,!digitalRead(led3));
      startMillis = millis();
    }
  }
  else
  {
    digitalWrite(led3,LOW);
  }
  //
}
//
// This Function gets called whenever there is a matching API request
// the command string format is l<led number>,<state>
// for example: l1,HIGH or l1,LOW
//              l2,HIGH or l2,LOW

int ledControl(String command)
{
  int state = 0;
  //find out the pin number and convert the ascii to integer
  int pinNumber = (command.charAt(1) - '0') - 1;
  //Sanity check to see if the pin numbers are within limits
  if (pinNumber < 0 || pinNumber > 1) return -1;

  // find out the state of the led
  if(command.substring(3,7) == "HIGH") state = 1;
  else if(command.substring(3,6) == "LOW") state = 0;
  else return -1;

  // write to the appropriate pin
  digitalWrite(pinNumber, state);
  return 1;
}


int blinkLed(String status)
{
  if (status == "1")
  {
    blinkOn = 1;
    //digitalWrite(led2,HIGH);
    return 1;
  }
  else if (status == "0")
  {
    blinkOn = 0;
    //digitalWrite(led2,LOW);
    return 0;
  }
  else
  {
    return -1;
  }
}

would this cause an issue? creating lastDisplayChangeTime without assigning it a number then using it in an if statement? its the same thing in the getTime() function too

I'm not sure what lastDisplayChangeTime - millis(); will do?

and im noticing your using the Adafruit_DHT, there is a new better one piettetech_dht that doesnt hang :slight_smile:

C will initialise lastDisplayChangeTime as zero...

well that was not supposed to be commented back in (my mistake going through chunks of code trying to find something that Sparky doesn't like). It was a carryover of my working arduino code where it was commented out... now deleted, thanks.

I tried commenting out the Adafruit DHT lib completely, but it didn't seem to matter... I'll try the other lib.

thanks.

No it won't - it's not C#.
You'll find the value in it that just happens to be in that memory location after restart.
But that shouldn't matter for the if since millis() will report a fairly small number on first run anyway and both being an unsigned long any value of lastDisplayChangeTime greater that millis() will definetly result in a true condition.

On the other hand, it's always good practice to initialize variables before first use.