How Would I simplify this animation code

Im basically using the 4 pin l2c lcd screen and getting reading from dht11 and ldr and printing those readings onto the lcd screen, although i wanted to use an animation to display them (just for the looks). although I've butchered some code together and was wondering if there was a simplified way to animate it. here is the code

#include <LiquidCrystal_I2C.h>
#include <DHT.h>

#define DHTPIN 8
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 20, 4);

const int buttonPin = 3;
const byte ldrPin = A0;

unsigned long previousMillis = 0;
const long interval = 3000;
unsigned long clearMillis = 0;

void setup() {
  lcd.init();
  lcd.backlight();
  dht.begin();
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  pinMode(ldrPin, INPUT_PULLUP);
}

void loop() {
  unsigned long currentMillis = millis();
  
  // check if it's time to update the LED
  if (currentMillis - previousMillis >= interval - 2000) {
    // save the last time you updated the LED
    previousMillis = currentMillis;

    float h = dht.readHumidity();
    float t = dht.readTemperature();
    float f = dht.readTemperature(true);

    if (isnan(h) || isnan(t) || isnan(f)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }

    float hif = dht.computeHeatIndex(f, h);
    float hic = dht.computeHeatIndex(t, h, false);

    Serial.print(F("Humidity: "));
    Serial.print(h);
    Serial.print(F("%  Temperature: "));
    Serial.print(t);
    Serial.print(F("°C "));
    Serial.print(f);
    Serial.print(F("°F  Heat index: "));
    Serial.print(hic);
    Serial.print(F("°C "));
    Serial.print(hif);
    Serial.println(F("°F"));

    lcd.setCursor(0,0);
    lcd.print(" ");
    lcd.setCursor(0,1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(1,0);
    lcd.print(" ");
    lcd.setCursor(0,0);
    lcd.print("H");
    lcd.setCursor(1,1);
    lcd.print(" ");
    lcd.setCursor(0,1);
    lcd.print("T");
    delay(25);
    lcd.setCursor(2,0);
    lcd.print(" ");
    lcd.setCursor(1,0);
    lcd.print("u");
    lcd.setCursor(2,1);
    lcd.print(" ");
    lcd.setCursor(1,1);
    lcd.print("e");
    delay(25);
    lcd.setCursor(3,0);
    lcd.print(" ");
    lcd.setCursor(2,0);
    lcd.print("m");
    lcd.setCursor(3,1);
    lcd.print(" ");
    lcd.setCursor(2,1);
    lcd.print("m");
    delay(25);
    lcd.setCursor(4,0);
    lcd.print(" ");
    lcd.setCursor(3,0);
    lcd.print("i");
    lcd.setCursor(4,1);
    lcd.print(" ");
    lcd.setCursor(3,1);
    lcd.print("p");
    delay(25);
    lcd.setCursor(5,0);
    lcd.print(" ");
    lcd.setCursor(4,0);
    lcd.print(":");
    lcd.setCursor(5,1);
    lcd.print(" ");
    lcd.setCursor(4,1);
    lcd.print(":");
    delay(25);
    lcd.setCursor(6,0);
    lcd.print(" ");
    lcd.setCursor(5,0);
    lcd.print(" ");
    lcd.setCursor(6,1);
    lcd.print(" ");
    lcd.setCursor(5,1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(8,0);
    lcd.print(" ");
    lcd.setCursor(8,1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(9,0);
    lcd.print(" ");
    lcd.setCursor(9,1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(7,0);
    lcd.print(" ");
    lcd.setCursor(6,0);
    lcd.print(h);
    lcd.setCursor(7,1);
    lcd.print(" ");
    lcd.setCursor(6,1);
    lcd.print(t);
    delay(25);
    lcd.setCursor(10,0);
    lcd.print(" ");
    lcd.setCursor(10,1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(11,0);
    lcd.print(" ");
    lcd.setCursor(10,0);
    lcd.print("%");
    lcd.setCursor(11,1);
    lcd.print(" ");
    lcd.setCursor(10,1);
    lcd.print("C");
    delay(25);
    lcd.setCursor(11,1);
    lcd.print((char)223);
    lcd.setCursor(12,0);
    lcd.print(" ");
    lcd.setCursor(12,1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(13,0);
    lcd.print(" ");
    lcd.setCursor(13,1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(14,0);
    lcd.print(" ");
    lcd.setCursor(14,1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(15,0);
    lcd.print(" ");
    lcd.setCursor(15,1);
    lcd.print(" ");

    while (true) {
       // clear the LCD if it's time
    if (millis() - currentMillis >= interval) {
      currentMillis = millis();
      lcd.setCursor(0,0);
      lcd.print(" ");
      lcd.setCursor(0,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(1,0);
      lcd.print(" ");
      lcd.setCursor(1,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(2,0);
      lcd.print("L");
      lcd.setCursor(2,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(3,0);
      lcd.print("i");
      lcd.setCursor(3,1);
      lcd.print(" ");
      delay(25);     
      lcd.setCursor(4,0);
      lcd.print("g");
      lcd.setCursor(4,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(5,0);
      lcd.print("h");
      lcd.setCursor(5,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(6,0);
      lcd.print("t");
      lcd.setCursor(6,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(7,0);
      lcd.print(" ");
      lcd.setCursor(7,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(8,0);
      lcd.print("L");
      lcd.setCursor(8,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(9,0);
      lcd.print("e");
      lcd.setCursor(9,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(10,0);
      lcd.print("v");
      lcd.setCursor(10,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(11,0);
      lcd.print("e");
      lcd.setCursor(11,1);
      lcd.print(" ");
      delay(25);
      lcd.setCursor(12,0);
      lcd.print("l");
      lcd.setCursor(12,1);
      lcd.print(" ");

      break;
      } 
    }

      /* LDR SENSOR */
  unsigned int AnalogValue;

  AnalogValue = analogRead(A0);

  Serial.println(AnalogValue);

  lcd.setCursor(3, 1);

    while (true) {
      if (millis() - currentMillis >= interval -2999) {
        currentMillis = millis();
        lcd.setCursor(3,1);
      if (AnalogValue < 10) {
      lcd.print("-");
      lcd.setCursor(4,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(5,1);
      delay(25); 
      lcd.print(" ");
      lcd.setCursor(6,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(7,1);
      delay(25);
      lcd.print("D");
      lcd.setCursor(8,1);
      delay(25);
      lcd.print("a");
      lcd.setCursor(9,1);
      delay(25);
      lcd.print("r");
      lcd.setCursor(10,1);
      delay(25);
      lcd.print("k");
      lcd.setCursor(11,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(12,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(13,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(14,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(15,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(16,1);
      delay(25);
      lcd.print("-");
    } else if (AnalogValue < 200) {
      lcd.setCursor(3,1);
      lcd.print(" ");
      lcd.setCursor(4,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(5,1);
      delay(25); 
      lcd.print(" ");
      lcd.setCursor(6,1);
      delay(25);
      lcd.print("D");
      lcd.setCursor(7,1);
      delay(25);
      lcd.print("i");
      lcd.setCursor(8,1);
      delay(25);
      lcd.print("m");
      lcd.setCursor(9,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(10,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(11,1);
      delay(25);
      lcd.print(" ");
    } else if (AnalogValue < 500) {
      lcd.setCursor(3,1);
      lcd.print(" ");
      lcd.setCursor(4,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(5,1);
      delay(25); 
      lcd.print(" ");
      lcd.setCursor(6,1);
      delay(25);
      lcd.print("L");
      lcd.setCursor(7,1);
      delay(25);
      lcd.print("i");
      lcd.setCursor(8,1);
      delay(25);
      lcd.print("g");
      lcd.setCursor(9,1);
      delay(25);
      lcd.print("h");
      lcd.setCursor(10,1);
      delay(25);
      lcd.print("t");
      lcd.setCursor(11,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(12,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(13,1);
      delay(25);
      lcd.print(" ");
   } else if (AnalogValue < 800) {
      lcd.setCursor(3,1);
      lcd.print(" ");
      lcd.setCursor(4,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(5,1);
      delay(25); 
      lcd.print(" ");
      lcd.setCursor(6,1);
      delay(25);
      lcd.print("B");
      lcd.setCursor(7,1);
      delay(25);
      lcd.print("r");
      lcd.setCursor(8,1);
      delay(25);
      lcd.print("i");
      lcd.setCursor(9,1);
      delay(25);
      lcd.print("g");
      lcd.setCursor(10,1);
      delay(25);
      lcd.print("h");
      lcd.setCursor(11,1);
      delay(25);
      lcd.print("t");
      lcd.setCursor(12,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(13,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(14,1);
      delay(25);
      lcd.print(" ");
   }  else {
      lcd.setCursor(0,1);
      lcd.print(" ");
      lcd.setCursor(1,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(2,1);
      delay(25); 
      lcd.print(" ");
      lcd.setCursor(3,1);
      delay(25);
      lcd.print("V");
      lcd.setCursor(4,1);
      delay(25);
      lcd.print("e");
      lcd.setCursor(5,1);
      delay(25);
      lcd.print("r");
      lcd.setCursor(6,1);
      delay(25);
      lcd.print("y");
      lcd.setCursor(7,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(8,1);
      delay(25);
      lcd.print("B");
      lcd.setCursor(9,1);
      delay(25);
      lcd.print("r");
      lcd.setCursor(10,1);
      delay(25);
      lcd.print("i");
      lcd.setCursor(11,1);
      delay(25);
      lcd.print("g");
      lcd.setCursor(12,1);
      delay(25);
      lcd.print("h");
      lcd.setCursor(13,1);
      delay(25);
      lcd.print("t");
      lcd.setCursor(14,1);
      delay(25);
      lcd.print(" ");
      lcd.setCursor(15,1);
      delay(25);
      lcd.print("-");
      lcd.setCursor(16,1);
      delay(25);
      lcd.print(" ");


        }
        break;
      }
    }

    while (true) {
      if (millis() - currentMillis >= interval) {
        currentMillis = millis();
          break;
      }
    }

  }
}```

Put your text in a string.
Read about arrays and for loops.
Use the fact that a cstring is an array of char.
This sketch can be pushed in around 20 lines...
GeeksForGeeks has good tutorials on c++.

instead of this:

char message[] = " - Very Bright - ";
int len = strlen(message);
for (byte i =0; i < len; i++) {
  lcd.setCursor( i ,1);
  delay(25);
  lcd.print(message[i]);
}

The next stage - write this code as a function with message and starting print position as arguments, what will help you to replace all such code blocks with one

sorry im very new, i kinda understand the code but what you said makes no sense to me.

1 Like

So it is a time to learn

More homework...
Put functions (with arguments) on your 'to learn list'.

is this better (still a lot of work to do)

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <stdio.h>

#define DHTPIN 8
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);

const int buttonPin = 3;
const byte ldrPin = A0;

char printLL[12] = "Light Level";  // creates a character for display "Light Level" on the lcd screen
char LDR_Readings[16];             // create a character array to hold the message that differs depending on the output of the LDR

unsigned long previousMillis = 0;
const long interval = 3000;
unsigned long clearMillis = 0;

int delayTime = 25;


    float f = dht.readTemperature(true);
    float h = dht.readHumidity();
    float t = dht.readTemperature();
  char Temp[16] = "Temp: ";
  char H[16] = "Humi: ";
  char t_str[8];
  char h_str[8];
  sprintf(t_str, "%6.2f", t);  // Format temperature value as a string with 2 decimal places
  sprintf(h_str, "%6.2f", h);  // Format humidity value as a string with 2 decimal places
  strcat(Temp, t_str);  // Concatenate the temperature string to the "Temp: " message
  strcat(H, h_str);

void setup() {
  lcd.init();
  lcd.backlight();
  dht.begin();
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  pinMode(ldrPin, INPUT_PULLUP);
}

void displayLDR(LiquidCrystal_I2C lcd, char* LDR_Readings, int delayTime) {
  int len = strlen(LDR_Readings);
  for (byte i = 0; i < len; i++) {
    lcd.setCursor(i + 2, 1);
    delay(25);
    lcd.print(LDR_Readings[i]);
  }
}

void LightLevel(LiquidCrystal_I2C lcd, char* printLL, int delayTime) {
  int len = strlen(printLL);
  for (byte i = 0; i < len; i++) {
    lcd.setCursor(i + 2, 0);
    delay(25);
    lcd.print(printLL[i]);
  }
}


void TempHumi(LiquidCrystal_I2C lcd, char* Temp, char* H,  int delayTime) {
  int len = strlen(Temp);

  for (byte i = 0; i < len; i++) {
        delay(25);
    lcd.setCursor(i,0);
    lcd.print(Temp[i]);
    lcd.setCursor(i,1);
    lcd.print(H[i]);
  }
}



/*
The reason we need to put everything in the function parameters is so that we can pass in the required 
values when calling the function. This is a common programming technique called "passing arguments".

The LiquidCrystal_I2C lcd parameter is used to pass in the LCD object that you want to display the
message on. This allows the function to work with any LCD object, as long as it is of the 
LiquidCrystal_I2C type.

The char* message parameter is used to pass in the message that you want to display on the LCD.
The char* type is a pointer to an array of characters, which is commonly used to represent 
strings in C/C++.

The int delayTime parameter is used to pass in the delay time between each character display.
This allows the delay time to be easily adjusted without having to modify the function code.

By defining the function with these parameters, it becomes a reusable block of code that can 
be called from other parts of your program with different LCD objects, messages, and delay times.
*/


// displayMessage(lcd, message, delayTime); !!!!!!!

/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
displayMessage(lcd, message, delayTime) is a function call that invokes the displayMessage function
we defined earlier.

The first parameter lcd is the LCD object that we want to use for displaying the message. 
It must be of type LiquidCrystal_I2C as that is the type defined in the function parameter.

The second parameter message is the message that we want to display on the LCD. It is a 
character array (or string) that we defined earlier in the code.

The third parameter delayTime is the amount of delay we want to have between each 
character being displayed on the LCD. It is an integer value that we defined earlier in the code.

When this function is called with these arguments, it will execute the code inside the function, 
which will display the message character by character on the specified LCD with the specified delay time.
*/

void loop() {

  /* LDR SENSOR */
  unsigned int AnalogValue;

  AnalogValue = analogRead(A0);

  strcpy(printLL, "Light Level");
  Serial.println(AnalogValue);

  lcd.setCursor(3, 1);

  // determining the message output for the ldr sensor readings.
  if (AnalogValue < 10) {
    strcpy(LDR_Readings, " - Dark - ");  // copy the message into the array
  } else if (AnalogValue < 200) {
    strcpy(LDR_Readings, "  - Dim - ");
  } else if (AnalogValue < 500) {
    strcpy(LDR_Readings, " - Light - ");
  } else if (AnalogValue < 800) {
    strcpy(LDR_Readings, " - Bright - ");
  } else {
    strcpy(LDR_Readings, " - Bright + - ");
  }

  /*
These lines are the modified if statements that set the appropriate message based on the AnalogValue reading.

If the AnalogValue is less than 10, the message array is assigned the string " - Dark - ".
 If the AnalogValue is between 10 and 200, the message array is assigned the string " - Dim - ", and so on.

Note that the strcpy function is used to copy the appropriate message into the message array.
 This function copies the contents of the second argument (the string) into the first argument (the message array).
*/

  unsigned long currentMillis = millis();

  // check if it's time to update the LED
  if (currentMillis - previousMillis >= interval - 2000) {
    // save the last time you updated the LED
    previousMillis = currentMillis;


    if (isnan(h) || isnan(t) || isnan(f)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }

    float hif = dht.computeHeatIndex(f, h);
    float hic = dht.computeHeatIndex(t, h, false);

    char Temp[16] = "Temp: ";



    Serial.print(F("Humidity: "));
    Serial.print(h);
    Serial.print(F("%  Temperature: "));
    Serial.print(t);
    Serial.print(F("°C "));
    Serial.print(f);
    Serial.print(F("°F  Heat index: "));
    Serial.print(hic);
    Serial.print(F("°C "));
    Serial.print(hif);
    Serial.println(F("°F"));

    /*lcd.setCursor(0, 0);
    lcd.print(" ");
    lcd.setCursor(0, 1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(1, 0);
    lcd.print(" ");
    lcd.setCursor(0, 0);
    lcd.print("H");
    lcd.setCursor(1, 1);
    lcd.print(" ");
    lcd.setCursor(0, 1);
    lcd.print("T");
    delay(25);
    lcd.setCursor(2, 0);
    lcd.print(" ");
    lcd.setCursor(1, 0);
    lcd.print("u");
    lcd.setCursor(2, 1);
    lcd.print(" ");
    lcd.setCursor(1, 1);
    lcd.print("e");
    delay(25);
    lcd.setCursor(3, 0);
    lcd.print(" ");
    lcd.setCursor(2, 0);
    lcd.print("m");
    lcd.setCursor(3, 1);
    lcd.print(" ");
    lcd.setCursor(2, 1);
    lcd.print("m");
    delay(25);
    lcd.setCursor(4, 0);
    lcd.print(" ");
    lcd.setCursor(3, 0);
    lcd.print("i");
    lcd.setCursor(4, 1);
    lcd.print(" ");
    lcd.setCursor(3, 1);
    lcd.print("p");
    delay(25);
    lcd.setCursor(5, 0);
    lcd.print(" ");
    lcd.setCursor(4, 0);
    lcd.print(":");
    lcd.setCursor(5, 1);
    lcd.print(" ");
    lcd.setCursor(4, 1);
    lcd.print(":");
    delay(25);
    lcd.setCursor(6, 0);
    lcd.print(" ");
    lcd.setCursor(5, 0);
    lcd.print(" ");
    lcd.setCursor(6, 1);
    lcd.print(" ");
    lcd.setCursor(5, 1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(8, 0);
    lcd.print(" ");
    lcd.setCursor(8, 1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(9, 0);
    lcd.print(" ");
    lcd.setCursor(9, 1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(7, 0);
    lcd.print(" ");
    lcd.setCursor(6, 0);
    lcd.print(h);
    lcd.setCursor(7, 1);
    lcd.print(" ");
    lcd.setCursor(6, 1);
    lcd.print(t);
    delay(25);
    lcd.setCursor(10, 0);
    lcd.print(" ");
    lcd.setCursor(10, 1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(11, 0);
    lcd.print(" ");
    lcd.setCursor(10, 0);
    lcd.print("%");
    lcd.setCursor(11, 1);
    lcd.print(" ");
    lcd.setCursor(10, 1);
    lcd.print("C");
    delay(25);
    lcd.setCursor(11, 1);
    lcd.print((char)223);
    lcd.setCursor(12, 0);
    lcd.print(" ");
    lcd.setCursor(12, 1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(13, 0);
    lcd.print(" ");
    lcd.setCursor(13, 1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(14, 0);
    lcd.print(" ");
    lcd.setCursor(14, 1);
    lcd.print(" ");
    delay(25);
    lcd.setCursor(15, 0);
    lcd.print(" ");
    lcd.setCursor(15, 1);
    lcd.print(" ");
*/
  TempHumi(lcd, Temp, H, delayTime);

    while (true) {
      // clear the LCD if it's time
      if (millis() - currentMillis >= interval) {
        currentMillis = millis();
        for (byte o = 0; o < 2; o++) {
          lcd.setCursor(o, 0);
          lcd.print(" ");
          delay(25);
        }
        LightLevel(lcd, printLL, delayTime);

        break;
      }
    }


    // see below to find more about what LightLevel(); does.

    /*
char message[] = " - Dark - ";
int len = strlen(message);
for (byte i = 0; i < len; i++) {
lcd.setCursor(i+2, 1);
delay(25);
lcd.print(message[i]);
}

The first line declares a character array named "message" and initializes it with the string "- Dark -". 
The string is enclosed in double quotes, which is how strings are represented in C++.

The second line declares an integer variable named "len" and assigns it the length of the "message" string using the strlen() function. 
This function calculates the length of a string by counting the number of characters in it, excluding the null character at the end ('\0').

The code then enters a for loop that will iterate over each character in the "message" string. 
The loop uses a byte variable "i" as the loop counter, starting from 0 and ending when "i" is no longer less than "len".

Inside the loop, the code sets the cursor position of the LCD display to i+2 on the second row (1), 
using the lcd.setCursor() function. The "+2" is added to position the text in the middle of the display, 
and the second parameter is the row number (0 for the first row and 1 for the second row).

The code then introduces a delay of 25 milliseconds using the delay() function. 
This is to create a pause between each character being printed to the LCD display.

The last line of the loop prints the current character of the "message" string to the LCD display using the lcd.print() function. 
The "i" variable is used as the index to access the current character in the "message" string, and that character is then sent to the LCD display.

The loop repeats until all the characters in the "message" string have been printed to the LCD display.

The i++ expression is a shorthand way of writing i = i + 1. It's called the increment operator,
 and it increments the value of the variable i by 1 each time the loop iterates. In this specific code, 
 i is used as the index to access each character of the message string inside the loop.
    */



    while (true)  // will rerun this function until the if statement is completed, then break; will end it {
      if (millis() - currentMillis >= interval - 2999) {
        currentMillis = millis();
        lcd.setCursor(0, 1);
        lcd.print(" ");
        lcd.print(" ");
        lcd.setCursor(3, 1);
        if (AnalogValue < 10) {
          displayLDR(lcd, LDR_Readings, delayTime);
        } else if (AnalogValue < 200) {
          displayLDR(lcd, LDR_Readings, delayTime);
        } else if (AnalogValue < 500) {
          displayLDR(lcd, LDR_Readings, delayTime);
        } else if (AnalogValue < 800) {
          displayLDR(lcd, LDR_Readings, delayTime);
        } else {
          displayLDR(lcd, LDR_Readings, delayTime);
        }

        break;
      }
  }

  /*
using the function displayLDR(...); it allows us to easily print a function into the if statements 
(see above for info on displayLDR() )
*/

  while (true) {
    if (millis() - currentMillis >= interval) {
      currentMillis = millis();

      break;
    }
  }
}

Wow, a lot has been done. :+1: :smiley:
Does this compile? You have code outside setup an loop...
I think lcd can be a global variable.
You call dht readTemp before dht.begin
You need to send the length of your array as a function argument. You cannot determine the array length inside your function (displayLDR()).
You have delaytime as an argument, but you do not use it.
You should make smaller steps, compile more and put all compiler warnings on... solve all errors and warnings before your next step. Compiler warnings can be difficult to handle. If you make small changes, you will know where to look for the problem.
I recommend strncopy and strncat that have an extra parameter to prevent buffer overflow.

yes im aware of the code outside the loop it was just there to write it then i move it where it needs to be (easier for me to do it that way). im also using wokwi simulator so i dont think you can turn on all compile warning also could you explain these - You need to send the length of your array as a function argument. You cannot determine the array length inside your function (displayLDR()).
I recommend strncopy and strncat that have an extra parameter to prevent buffer overflow.

I am sorry, the strlen function should work. C strings are the only arrays that know their length (or better: can derive their length by counting characters until they meet a '\n').

It seems to me that you didn't understand the way of using the C functions....
Look at this weird code:

Can you explain the purpose of five if ....else if conditions, if all of them run the perfectly same code?

ahh realisted my error (im new to arduino c++ only about a week experience)

above i have the code

  if (AnalogValue < 10) {
    strcpy(LDR_Readings, " - Dark - ");  // copy the message into the array
  } else if (AnalogValue < 200) {
    strcpy(LDR_Readings, "  - Dim - ");
  } else if (AnalogValue < 500) {
    strcpy(LDR_Readings, " - Light - ");
  } else if (AnalogValue < 800) {
    strcpy(LDR_Readings, " - Bright - ");
  } else {
    strcpy(LDR_Readings, " - Bright + - ");
  }

which would change the LDR_readings string so i only have to use

displayLDR(lcd, LDR_Readings, delayTime); by its self if im correct?

I think yes, at least for this issue :slight_smile:
But despite the superficial conditions you have a endless loop while(true) around this piece of code... What for?

idk i was using chat gpt to help me understand millis() more and it got me to that point. apparently millis is better than delay. is it? and am i using it correctly. here is an adjusted code.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <stdio.h>

#define DHTPIN 8
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);

const int buttonPin = 3;
const byte ldrPin = A0;

char printLL[12] = "Light Level";  // creates a character for display "Light Level" on the lcd screen
char LDR_Readings[16];             // create a character array to hold the message that differs depending on the output of the LDR

unsigned long previousMillis = 0;
const long interval = 3000;
unsigned long clearMillis = 0;

int delayTime = 25;

const int soilPin = A0;
const int soilPower = 13;


int readSoil() {
  digitalWrite(soilPower, HIGH);  //turn D7 "On"
  delay(10);                      //wait 10 milliseconds
  int val = analogRead(soilPin);  //Read the SIG value form sensor
  digitalWrite(soilPower, LOW);   //turn D7 "Off"
  return val;                     //send current moisture value
}

void setup() {
  lcd.init();
  lcd.backlight();
  dht.begin();
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  pinMode(ldrPin, INPUT_PULLUP);
}

void displayLDR(LiquidCrystal_I2C lcd, char* LDR_Readings, int delayTime) {
  int len = strlen(LDR_Readings);
  for (byte i = 0; i < len; i++) {
    lcd.setCursor(i + 2, 1);
    delay(delayTime);
    lcd.print(LDR_Readings[i]);
  }
}

void LightLevel(LiquidCrystal_I2C lcd, char* printLL, int delayTime) {
  int len = strlen(printLL);
  for (byte i = 0; i < len; i++) {
    lcd.setCursor(i + 2, 0);
    delay(delayTime);
    lcd.print(printLL[i]);
  }
}


void TempHumi(LiquidCrystal_I2C lcd, char* Temp, char* H, int delayTime) {
  int len = strlen(Temp);
  for (byte i = 0; i < len; i++) {
    delay(delayTime);
    lcd.setCursor(i, 0);
    lcd.print(Temp[i]);
    lcd.setCursor(i, 1);
    lcd.print(H[i]);
  }
}

void SoilMoistureLevel(LiquidCrystal_I2C lcd, char* readSoil, int delayTime) {
  int len = strlen(readSoil);
  for (byte i = 0; i < len; i++) {
    lcd.setCursor(i + 2, 1);
    delay(delayTime);
    lcd.print(readSoil[i]);
  }
}



/*
The reason we need to put everything in the function parameters is so that we can pass in the required 
values when calling the function. This is a common programming technique called "passing arguments".

The LiquidCrystal_I2C lcd parameter is used to pass in the LCD object that you want to display the
message on. This allows the function to work with any LCD object, as long as it is of the 
LiquidCrystal_I2C type.

The char* message parameter is used to pass in the message that you want to display on the LCD.
The char* type is a pointer to an array of characters, which is commonly used to represent 
strings in C/C++.

The int delayTime parameter is used to pass in the delay time between each character display.
This allows the delay time to be easily adjusted without having to modify the function code.

By defining the function with these parameters, it becomes a reusable block of code that can 
be called from other parts of your program with different LCD objects, messages, and delay times.
*/


// displayMessage(lcd, message, delayTime); !!!!!!!

/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
displayMessage(lcd, message, delayTime) is a function call that invokes the displayMessage function
we defined earlier.

The first parameter lcd is the LCD object that we want to use for displaying the message. 
It must be of type LiquidCrystal_I2C as that is the type defined in the function parameter.

The second parameter message is the message that we want to display on the LCD. It is a 
character array (or string) that we defined earlier in the code.

The third parameter delayTime is the amount of delay we want to have between each 
character being displayed on the LCD. It is an integer value that we defined earlier in the code.

When this function is called with these arguments, it will execute the code inside the function, 
which will display the message character by character on the specified LCD with the specified delay time.
*/

void loop() {

  map(readSoil, 0, 700, 0, 20);
  /*
value is the input value to be mapped, in this case, the analog output value of the soil moisture sensor.

fromLow and fromHigh are the range of values that the input value can take. In this case, fromLow would be 
300 and fromHigh would be 700, as these are the approximate values for the dry and wet ranges of the sensor.

toLow and toHigh are the desired range of values to map the input value to. In this case, toLow could be 0 
and toHigh could be 10, as these are the desired output values for the mapped range.
*/

  Serial.println(readSoil());  // reads from the int readSoil() Variable

  /* LDR SENSOR */
  unsigned int AnalogValue;

  AnalogValue = analogRead(A0);

  strcpy(printLL, "Light Level");
  Serial.println(AnalogValue);

  lcd.setCursor(3, 1);

  // determining the message output for the ldr sensor readings.
  if (AnalogValue < 10) {
    strcpy(LDR_Readings, " - Dark - ");  // copy the message into the array
  } else if (AnalogValue < 200) {
    strcpy(LDR_Readings, "  - Dim - ");
  } else if (AnalogValue < 500) {
    strcpy(LDR_Readings, " - Light - ");
  } else if (AnalogValue < 800) {
    strcpy(LDR_Readings, " - Bright - ");
  } else {
    strcpy(LDR_Readings, " - Bright + - ");
  }

  /*
These lines are the modified if statements that set the appropriate message based on the AnalogValue reading.

If the AnalogValue is less than 10, the message array is assigned the string " - Dark - ".
If the AnalogValue is between 10 and 200, the message array is assigned the string " - Dim - ", and so on.

Note that the strcpy function is used to copy the appropriate message into the message array.
 This function copies the contents of the second argument (the string) into the first argument (the message array).
*/

  unsigned long currentMillis = millis();

  // check if it's time to update the LED
  if (currentMillis - previousMillis >= interval - 2000) {
    // save the last time you updated the LED
    previousMillis = currentMillis;

    float f = dht.readTemperature(true);
    float h = dht.readHumidity();
    float t = dht.readTemperature();
    char Temp[16] = "Temp: ";
    char H[16] = "Humi: ";
    char t_str[16];
    char h_str[16];
    dtostrf(t, 4, 2, t_str);
    dtostrf(h, 4, 2, h_str);
    strcat(Temp, t_str);
    strcat(H, h_str);

    if (isnan(h) || isnan(t) || isnan(f)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }

    float hif = dht.computeHeatIndex(f, h);
    float hic = dht.computeHeatIndex(t, h, false);


    Serial.print(F("Humidity: "));
    Serial.print(h);
    Serial.print(F("%  Temperature: "));
    Serial.print(t);
    Serial.print(F("°C "));
    Serial.print(f);
    Serial.print(F("°F  Heat index: "));
    Serial.print(hic);
    Serial.print(F("°C "));
    Serial.print(hif);
    Serial.println(F("°F"));

    TempHumi(lcd, Temp, H, delayTime);
    lcd.setCursor(11,0);
    delay(delayTime);
    lcd.print("C");
    delay(delayTime);
    lcd.print(char(223)) ;
    lcd.setCursor(11,1);
    lcd.print("%");


    while (true) {
      // clear the LCD if it's time
      if (millis() - currentMillis >= interval) {
        currentMillis = millis();
        for (byte o = 0; o < 2; o++) {
          lcd.setCursor(o, 0);
          lcd.print(" ");
          delay(25);
        }
        LightLevel(lcd, printLL, delayTime);

        break;
      }
    }


    // see below to find more about what LightLevel(); does.

    /*
char message[] = " - Dark - ";
int len = strlen(message);
for (byte i = 0; i < len; i++) {
lcd.setCursor(i+2, 1);
delay(25);
lcd.print(message[i]);
}

The first line declares a character array named "message" and initializes it with the string "- Dark -". 
The string is enclosed in double quotes, which is how strings are represented in C++.

The second line declares an integer variable named "len" and assigns it the length of the "message" string using the strlen() function. 
This function calculates the length of a string by counting the number of characters in it, excluding the null character at the end ('\0').

The code then enters a for loop that will iterate over each character in the "message" string. 
The loop uses a byte variable "i" as the loop counter, starting from 0 and ending when "i" is no longer less than "len".

Inside the loop, the code sets the cursor position of the LCD display to i+2 on the second row (1), 
using the lcd.setCursor() function. The "+2" is added to position the text in the middle of the display, 
and the second parameter is the row number (0 for the first row and 1 for the second row).

The code then introduces a delay of 25 milliseconds using the delay() function. 
This is to create a pause between each character being printed to the LCD display.

The last line of the loop prints the current character of the "message" string to the LCD display using the lcd.print() function. 
The "i" variable is used as the index to access the current character in the "message" string, and that character is then sent to the LCD display.

The loop repeats until all the characters in the "message" string have been printed to the LCD display.

The i++ expression is a shorthand way of writing i = i + 1. It's called the increment operator,
 and it increments the value of the variable i by 1 each time the loop iterates. In this specific code, 
 i is used as the index to access each character of the message string inside the loop.
    */



    while (true)  // will rerun this function until the if statement is completed, then break; will end it {
      if (millis() - currentMillis >= interval - 2999) {
        currentMillis = millis();
        lcd.setCursor(0, 1);
        lcd.print(" ");
        lcd.print(" ");
        lcd.setCursor(3, 1);
        displayLDR(lcd, LDR_Readings, delayTime);

        break;
      }
  }

  /*
using the function displayLDR(...); it allows us to easily print a function into the if statements 
(see above for info on displayLDR() )
*/

  while (true) {
    if (millis() - currentMillis >= interval) {
      currentMillis = millis();

      break;
    }
  }
}

Sorry, I don't understand your code.
Could you explain, what should be shown on the screen and in what order. Why do you need four consecutive cycles with millis?

Here is a link to a simulator in running it on

I’m trying to create an animation purely for looks

FYI I also have a physical copy just easier online as well as you will see some code for a soil moisture sensor which I’m testing right now but no sensor for it on wokwi.

Also I’m unaware why I’m using 4 Millis cycles as I said I’ve been doing this for about a week I don’t know much about the Millis and everything. Maybe teaching me is a better way of understanding what is wrong.

1 Like

First line after loop:
Readsoil is a function, not a variable.
Why interval -2000?
Did this compile?
Please cut out the chatgtp stuff you do not understand...
While(true) break; is ugly... even if it does what you want it to do.

I didn’t just copy and paste the stuff from chatgpt. I couldn’t find much about it online so I asked chat gpt to explain it to me and that’s what I got. Interval 2000 is for the Millis thingy. And if you want me to remove everything relating to the millis delays then what should I put instead? Delay();?

To be honest, I am not willing to process your code line by line as a compiler would...
So you need to start from some point where the code compiles. And then gradually add your stuff. And compile again...
Starting point could be a completely fresh start:

void setup(){
    ;
}

void loop() {
    ;
}

Come here if you do not get it to compile (including last version that did compile and compiler message).
Or come here if the code compiles, but does not do what you want. In that case: show your code, say what you want it to do and say what it does instead.

It does compile. I built it up from nothing, started with the dht22 then moved onto the light sensor and now working on the soil moisture, I didn’t just copy and paste some code together.