function loop that i can't get out of

hey guys. I am currently creating a weather display that will light up different neopixels based on the weather. for example if its sunny they light up yellow, overcast is all white. it takes data from weather underground json and parses it.
The problem lies in when i have rain and snow. With the rain and snow, they are not static LEDs and need a loop to simulate raindrops or snow falling. I have it working fine. When its sunny it goes to yellow. then it starts raining switches on the rain but its stuck within that loops and i can't wrap my mind around how to get out of it.

below is the rain and snow function. based on weather (ha get it?) or not its snowing or raining light or heavy it blinks the leds in random faster or slower. So the problem lies in the while statement that I have. So without the while statement it lights 1 LED and doesn't do anything else. so i have to have it in. Currently weather type and speed are passed in via a if then in another function or if it snows then its "snow" "fast" etc. the srCheck gets updated by the function that parses the json
If you want I can post the whole code but it is quite a lot and not well written or formatted it all so everyone will probably cringe here.
The only time it is able to escape the rainandsnow function is when it crashes which it does regularly as from what I have read it detects an infinite loop and soft kills itself. any suggestions at all? I know this is probably much harder to troubleshoot than the standard questions but i have spent the past 3 days trying to think of ways to pass data into it that gets updated but im not good enough to think of a solution. I thought of the srCheck last night and that got me a little closer but now im running into the crashing due to infinite loop task and never updating.

if statement

if (forecast.equalsIgnoreCase(rain))
  {
    Serial.println("precipitation in the forecast today");
    const char *fast = "fast";
    const char *rain = "rain";
    SnowandRain(rain, fast);

snow/rain function

void SnowandRain(const char *WeatherType, const char *Speed)
{
  
  Serial.println("lol");
  Serial.println(srCheck);
  Serial.println("lol");
    float fadeRate = .98;
    
   while (srCheck = WeatherType)
   { 
    if (Speed == "fast")
    {
       fadeRate = 0.93;
    }
    if (Speed == "slow")
    {
       fadeRate = 0.97;
    }
    //debug what is being passed 
    Serial.println(WeatherType);
    Serial.println(Speed);
    while (1 != 2){
    if (random(PIXEL_COUNT) == 1) {
        uint16_t i = random(PIXEL_COUNT);
        if (redStates[i] < 1 && greenStates[i] < 1 && blueStates[i] < 1 && whiteStates[i] < 1) 
        {
          redStates[i] = 0;
          greenStates[i] = 0;
          //changes to blue if rain, changes to white if snow
          if (WeatherType == "snow")
          {
          blueStates[i] = 0;
          whiteStates[i] = random(256);
          }
          if (WeatherType == "rain")
          {
          blueStates[i] = random(256);
          whiteStates[i] = 0;
          }
          
        }
      }
      
      for(uint16_t l = 0; l < PIXEL_COUNT; l++)
    {
        if (redStates[l] > 1 || greenStates[l] > 1 || blueStates[l] > 1 || whiteStates[l] > 1) 
      {
          pixels.setPixelColor(l, redStates[l], greenStates[l], blueStates[l], whiteStates[l]);
          
          if (redStates[l] > 1) 
      {
            redStates[l] = redStates[l] * fadeRate;
          } 
      else 
      {
            redStates[l] = 0;
          }
          if (greenStates[l] > 1) 
      {
            greenStates[l] = greenStates[l] * fadeRate;
          }
      else 
      {
            greenStates[l] = 0;
          }      
          if (blueStates[l] > 1) 
      {
            blueStates[l] = blueStates[l] * fadeRate;
          } 
      else 
      {
            blueStates[l] = 0;
          }
  
          if (whiteStates[l] > 1) 
      {
            whiteStates[l] = whiteStates[l] * fadeRate;
          }
      else 
      {
            whiteStates[l] = 0;
          }
          
        } 
      else 
      {
          pixels.setPixelColor(l, 0, 0, 0);
        }
      }
      pixels.show(); // light up the pixels
        if (Speed == "fast")
        {
          delay(6);
        }
        if (Speed == "slow")
        {
          delay(15);
        }
    } 
  } 
}

weather handler from the json

void handleCondition(String weather1) 
{

  lightPixels(pixels.Color(0, 0, 0, 0)); // reset all pixels to off


  String forecast = weather1;
  //parses json string data from the weather condition
  String rain = String("Rain");
  String overcast = String("Overcast");
  //String lightrain = String("Light Rain");
  String rainshower = String ("Rain Shower");
  String snow = String("Snow");
  String cloudy = String("Mostly Cloudy");
  String mostlycloudy = String("Mostly Cloudy");
  String partlycloudy = String("Partly Cloudy");
  String clearsky = String("Clear");
  String sunny = String("Sunny");
  String rainandsnow = String("Rain and Snow");
  String snowshower = String("Snow Shower");
 
  // These if statements compare the incoming weather variable to the stored conditions, and control the NeoPixels accordingly.

  
  // if there's rain in the forecast, tell the the first four pixels to be blue and the middle four pixels to be white (but don't draw them yet)
  if (forecast.equalsIgnoreCase(rain))
  {
    Serial.println("precipitation in the forecast today");
    const char *fast = "fast";
    const char *rain = "rain";
    SnowandRain(rain, fast);

    //pixels.show();
    }
  
  // if there's snow in the forecast, tell the the first four pixels to be whiteish blue and the middle four pixels to be white (but don't draw them yet)
  if (forecast.equalsIgnoreCase(snow) || forecast.equalsIgnoreCase(rainandsnow) || forecast.equalsIgnoreCase(snowshower))
  {
    Serial.println("precipitation in the forecast today");
    // SnowandRain("snow");
   /* pixels.setPixelColor(0, pixels.Color(0, 30, 175, 100));
    pixels.setPixelColor(1, pixels.Color(0, 30, 175, 100));

    pixels.show();         
  }
  
  // if there's sun in the forecast, tell the last four pixels to be yellow (but don't draw them yet)
  if (forecast.equalsIgnoreCase(clearsky) || forecast.equalsIgnoreCase(sunny))
  {
    Serial.println("some kind of sun in the forecast today");
    PixelSet(2,255,128,0,0); // section, green,red,blue,white
    PixelSet(3,255,128,0,0);
    pixels.show();// light up the pixels    
  }
  // if there's sun in the forecast, tell the last four pixels to be yellow (but don't draw them yet)
  if (forecast.equalsIgnoreCase(overcast))
  {
    Serial.println("no sun all overcast");
    PixelSet(1,0,0,0,255); // section, green,red,blue,white
    PixelSet(2,0,0,0,255);
    PixelSet(3,0,0,0,255);
    pixels.show();// light up the pixels    
  }
   // if its partly cloudy has 2 yellow and 1 white (but don't draw them yet)
  if (forecast.equalsIgnoreCase(partlycloudy))
  {    
    Serial.println("partly cloudy  forecast today");
    PixelSet(2,255,128,0,0);
    PixelSet(3,255,128,0,0);
    PixelSet(1,0,0,0,255);
    pixels.show(); // light up the pixels        
   }
   // if its mostly cloudy lights up 1 sun and 2 white (but don't draw them yet)
  if (forecast.equalsIgnoreCase(mostlycloudy))
  {    
    Serial.println("mostly cloudy forecast today");
    PixelSet(3,255,128,0,0);
    PixelSet(2,0,0,0,255);
    PixelSet(1,0,0,0,255);
    pixels.show(); // light up the pixels        
   }
   
}
   while (srCheck = WeatherType)

Oooops! That's an assignment statement, not a comparison.

Pete

  String forecast = weather1;
  //parses json string data from the weather condition
  String rain = String("Rain");
  String overcast = String("Overcast");
  //String lightrain = String("Light Rain");
  String rainshower = String ("Rain Shower");
  String snow = String("Snow");
  String cloudy = String("Mostly Cloudy");
  String mostlycloudy = String("Mostly Cloudy");
  String partlycloudy = String("Partly Cloudy");
  String clearsky = String("Clear");
  String sunny = String("Sunny");
  String rainandsnow = String("Rain and Snow");
  String snowshower = String("Snow Shower")

oh boy...

lol @Bulldog i know its terrible but my lack of coding experience brings me that, i did preface it saying it'd probably make people cringe :P. do you have any suggestions on how to make it cleaner/better?
@el_supremo how would I correct this? would it be "==" from what I found similar on this post

I thought that the link you posted explained the difference between = and == well.

Beware of accidentally using the single equal sign (e.g. if (x = 10) ). The single equal sign is the assignment operator, and sets x to 10 (puts the value 10 into the variable x). Instead use the double equal sign (e.g. if (x == 10) ), which is the comparison operator, and tests whether x is equal to 10 or not.

Add to that what I wrote in #1 and there's not much choice here.

Pete

When I rise to power I will change this = vs == nonsense.

I will decree that = in an if will be the comparison, so "if (x=50)".

I will decree that assignments will need the word "let" in front, so "let x=50".

Seeemples.

ah ok. well thats fair, sorry im just not confident in my coding ability so thought id make sure. I have done this now it never enters the loop even though both variables that its checking are the exact same they are both const char and they both equal "Rain"

Is there a way to call that variable from the function like for example showWeather.weather or handleConnection.weather1?

Post your code as it is now

UKHeliBob:
Post your code as it is now

here is the entire project .sorry in adv its messy. I have tried my best to clean it up. im just not a professional. The rainandsnow function is all the way at the bottom. i have removed a tiny bit of information of wifi and api keys

this is the actual link. it would not let me post it all as there is a max 9000 character limit
https://github.com/bizit524/Weather/blob/master/Weather.ino

any suggestions are appreciated for it, even if doesn't have anything to do with my current problem. Im open to advice on what I should or shouldnt do as standard practice
Thanks for your time

they are both const char and they both equal "Rain"

They might both equal "Rain" but they don't necessarily point to the same string. Consider this snippet:

 const char *r1 = "Rain";
  const char *r2 = "Today it will Rain";
  const char *r3 = &r2[14];

If you then print the strings r1 and r3, they will both print "Rain". But those two strings are in different parts of the memory. The "Rain" pointed to by r1 is not the same "Rain" as the one pointed to by r3, so the address in r1 is not the same as the address in r3. Therefore, if you compare them with "while(r1 == r3)" or "if(r1 == r3)" the comparison will always fail because r1 is not equal to r3 - i.e. you are not comparing the content of the strings, you are comparing where they are in memory.

Try this code:

void setup(void)
{
  Serial.begin(9600);
  while(!Serial);
  const char *r1 = "Rain";
  const char *r2 = "Today it will Rain";
  const char *r3 = &r2[14];

  Serial.println(r1);
  Serial.println(r3);
  if(r1 == r3) {
    Serial.println("They are equal");
  } else {
    Serial.println("They are NOT equal");
  }
}

void loop(void)
{
}

It prints:

Rain
Rain
They are NOT equal

To compare char* strings you need to use the strcmp function (or one of its variations strncmp, stricmp etc.). This code:

 if(strcmp(r1,r3) == 0) {
    Serial.println("They are equal");
  } else {
    Serial.println("They are NOT equal");
  }

will indicate that the strings are equal because strcmp compares the content of the strings, not their address.

If this doesn't clarify things, or makes it worse, you'll have to do some reading about C/C++ pointers and strings.

Pete

//setup for snowandrain function
const char srCheck;

I think this should be
const char *srCheck;

Pete

el_supremo:

//setup for snowandrain function

const char srCheck;



I think this should be
const char *srCheck;

Pete

Yes you are very right. I actually put that back really quick because I was testing stuff by putting it in the main loop() function. I originally had that but thanks for pointing that out :slight_smile:

To compare char* strings you need to use the strcmp function (or one of its variations strncmp, stricmp etc.). This code:

 if(strcmp(r1,r3) == 0) {

Serial.println("They are equal");
 } else {
   Serial.println("They are NOT equal");
 }



will indicate that the strings are equal because strcmp compares the content of the strings, not their address.

If this doesn't clarify things, or makes it worse, you'll have to do some reading about C/C++ pointers and strings.

Pete

oh man! i had no clue about that! thanks :slight_smile: I will implement this right now and try it :slight_smile:

The DecimalNumber function would look a lot better and be much smaller if you used an array:

uint8_t layout[10] = {
  B10111111,
  B10000110,
  B11011011,
  etc. // you fill in the rest
};
uint8_t DecimalNumber (int number)
{
  // If number is in the range 0 to 8 return the associated layout
  if(number >= 0 && number <= 8) return layout[number];
  // otherwise return layout[9]
  return layout[9];
}

But you are really going to have to completely rethink how the handleCondition function works. All those Strings are going to cause you grief.
The SnowandRain function needs to be fixed to use strcmp as I've described previously.

Pete

wooo now it technically works! so the string compare works gets the current weather and it is able to switch from "sunny" or w/e it is to the rain or snow. However since this is in a loop it still never exits. because the srcheck never gets reupdated. so even if the weather changes the loops will still check the old value. hopefully that makes sense. is there a way to take a quick "break" from this function to check to see if "srcheck" has changed?
Since srcheck is technically updated in the function showWeather. is there a way to beak from the while loop really quick and update the showWeather again?

i dont know maybe i have screwed this whole thing up because the check is only supposed to happen every 30 min because weather underground only allows 400 requests a day via the free api key
this is definitely not the most efficient program
How would you suggest I change the strings? do you mean I should change them to something else?

Also i didn't think about the array. however I will try to implement that! that would be a lot easier then a ton of if thens... thanks so much for the advice :slight_smile:

Maybe you shouldn't be using while anyway. Perhaps changing

  while (srCheck == "Rain")

to

  if (srCheck == "Rain")

is all that's needed?

Pete

Maybe you don't need 'while' in the SnowandRain function, you should try 'if' instead.

P.S. Dunno how my previous message #15 got sent. I was sure I had cancelled it.

Pete

Thanks el_supremo
I have pushed a new change. I have switched to the array and removed the if thens in the decimal function. I will need to test this 100% of all the numbers just to make sure i got them right.

No worries about double posting ive done that.
well. I can do an if statement however then it doesn't loop the code(as far as I know).I have tried it with a while which then it works "fine" just never exits and I have tried it with no condition statement at all and it runs through it 1x and lights 1 neopixel then stops and waits for the weather to be updated again.

So to be fair I found this neopixel animation on some website and they were just using it as an example. They originally had it in the loop() function but my program is a bit more complex so i have to call this function

I will try and implement the if condition. Another thought, i literally just thought of. Maybe Ill put a while statement in where it calls for this function snowrain() to begin with then it makes it easier (i believe) to update the weather variable and check if its still snowing or raining. Then if I am thinking correctly it will call the function over and over again making it do 1 LED each time.
something to work on tonight!

also what would you suggest I change the bunch of strings to?