How do i lessen my sketch space

hello im new to arduino, sometimes this reach 105% which makes my esp32 not working... how can i lessen this more..

Sketch uses 1248836 bytes (95%) of program storage space. Maximum is 1310720 bytes.
Global variables use 50292 bytes (15%) of dynamic memory, leaving 277388 bytes for local variables. Maximum is 327680 bytes.
esptool.py v4.8.1
Serial port COM7
Connecting....
Chip is ESP32-D0WD-V3 (revision v3.1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: a0:dd:6c:02:bd:74
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.


#define GREEN_LED_PIN 26  // Change to GPIO 26
#define RED_LED_PIN 27    // Change to GPIO 27

#define DHTPIN 4     // new added - GPIO4 (can be any digital pin)
#define DHTTYPE DHT22   //new added - DHT 22 (AM2302)
#include <ArduinoJson.h>

#include <Arduino.h>
#include <WiFi.h>
#include <time.h> 
#include <Firebase_ESP_Client.h>

//Provide the token generation process info.
#include "addons/TokenHelper.h"
//Provide the RTDB payload printing info and other helper functions.
#include "addons/RTDBHelper.h"

#include <DHT.h> 

const char* wifiList[][3] PROGMEM = {
  {"HUAWEI-D8kG", "ana@36546"},
  {"TECNNO CAMON 20 Pro", "vidallo12345"},
  {"Carlo", "carlfrancis0205"},
  {"Kaida", "Kaida123"},
  {"Hotspot", "12468642369485"},
  {"VILLA", "arielvillajr."},
  {"TECNNO CAMON 20 Pro", "vidallo12345"},
  {"CCT2-512", "ccthospes2019"},
  {"HG8145V5_D400A", "jcww2myE"},

};
const int numNetworks = sizeof(wifiList) / sizeof(wifiList[0]);



//Define Firebase Data object
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
FB_Firestore firestore;


unsigned long sendDataPrevMillis = 0;
int count = 0;
bool signupOK = false;

const int sensorPin1 = 34;  
const int sensorPin2 = 35;
const int sensorPin3 = 33;
const int sensorPin4 = 32;




// Calibration values based on your tests
const int dryValue1 = 2480, wetValue1 = 580;
const int dryValue2 = 2475, wetValue2 = 600;
const int dryValue3 = 2480, wetValue3 = 660;
const int dryValue4 = 2430, wetValue4 = 500;


// Initialize the DHT sensor
DHT dht(DHTPIN, DHTTYPE);

void connectToWiFi() {
    WiFi.mode(WIFI_STA);
    for (int i = 0; i < numNetworks; i++) {
        Serial.print("Trying to connect to: ");
        Serial.println(wifiList[i][0]);

        WiFi.begin(wifiList[i][0], wifiList[i][1]);
        int attempts = 20;  // Timeout after ~10 seconds
        while (WiFi.status() != WL_CONNECTED && attempts > 0) {
            delay(500);
            Serial.print(".");
            attempts--;
        }

        if (WiFi.status() == WL_CONNECTED) {
            Serial.println("\n✅ Connected to WiFi!");
            Serial.print("IP Address: ");
            Serial.println(WiFi.localIP());
            digitalWrite(RED_LED_PIN, LOW);
            digitalWrite(GREEN_LED_PIN, HIGH);
            return;
        } else {
            Serial.print("\n❌ Failed to connect to ");
            Serial.println(wifiList[i][0]);
            Serial.print("Error Code: ");
            Serial.println(WiFi.status());
        }
    }
    Serial.println("⚠️ Could not connect to any WiFi. Retrying in 10 seconds...");
    delay(10000);
    ESP.restart();  // Restart only if all networks fail
}



float averageMoisture(int readings[], int count) {
  float sum = 0;
  for (int i = 0; i < count; i++) {
    sum += readings[i];
  }
  return sum / count;  // Return the average
}

void readAndDisplaySensorValues() {
  //Serial.println(WiFi.localIP()); 
  
  // Read soil moisture sensor values
  int moisture1 = analogRead(sensorPin1);
    int moisture2 = analogRead(sensorPin2);
    int moisture3 = analogRead(sensorPin3);
    int moisture4 = analogRead(sensorPin4);
    int moisturePercent1 = map(moisture1, dryValue1, wetValue1, 0, 100);
    int moisturePercent2 = map(moisture2, dryValue2, wetValue2, 0, 100);
    int moisturePercent3 = map(moisture3, dryValue3, wetValue3, 0, 100);
    int moisturePercent4 = map(moisture4, dryValue4, wetValue4, 0, 100);

   // Ensure values stay between 0% and 100%
    moisturePercent1 = constrain(moisturePercent1, 0, 100);
    moisturePercent2 = constrain(moisturePercent2, 0, 100);
    moisturePercent3 = constrain(moisturePercent3, 0, 100);
    moisturePercent4 = constrain(moisturePercent4, 0, 100);

  float temperature = dht.readTemperature();  // Read temperature
  float humidity = dht.readHumidity();  // Read humidity
  // Calculate average moisture
  int moistureReadings[] = {
    moisturePercent1, 
    moisturePercent2, 
  moisturePercent3, 
  moisturePercent4};
  float averageMoistureLevel = averageMoisture(moistureReadings, 4);



  // // Display the values on the Serial Monitor

  if (Firebase.RTDB.setInt(&fbdo, "Moisture/MoistureReadings_1", moisturePercent1)){

      
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    } 

    if (Firebase.RTDB.setInt(&fbdo, "Moisture/MoistureReadings_2", moisturePercent2)){

      
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    } 

    if (Firebase.RTDB.setInt(&fbdo, "Moisture/MoistureReadings_3", moisturePercent3)){

      
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    } 

    if (Firebase.RTDB.setInt(&fbdo, "Moisture/MoistureReadings_4", moisturePercent4)){

    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    } 

    if (Firebase.RTDB.setFloat(&fbdo, "Moisture/Average", averageMoistureLevel)){
      
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    } 


    if (Firebase.RTDB.setFloat(&fbdo, "Temperature/temperature", temperature)){

      
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    } 

    if (Firebase.RTDB.setFloat(&fbdo, "Humidity/humidity", humidity)){
      
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    } 


  Serial.println("Soil Moisture Levels:");
  Serial.print("Sensor 1: "); Serial.print(moisturePercent1); Serial.println("%");
  Serial.print("Sensor 2: "); Serial.print(moisturePercent2); Serial.println("%");
  Serial.print("Sensor 3: "); Serial.print(moisturePercent3); Serial.println("%");
  Serial.print("Sensor 4: "); Serial.print(moisturePercent4); Serial.println("%");
  Serial.print("Average Soil Moisture: "); Serial.print(averageMoistureLevel); Serial.println("%");
  Serial.print("Temperature: "); Serial.print(temperature); Serial.println("°C");
  Serial.print("Humidity: "); Serial.print(humidity); Serial.println("%");
} //new added


// Firestore starts here!!!!!!!
// This for setting the time no need na sa RTC component instead we using network time protocol
void setupTime() {
    if (WiFi.status() != WL_CONNECTED) {
        Serial.println("WiFi not connected! Cannot sync time.");
        return;
    }
    const long gmtOffset_sec = 8 * 3600; // GMT+8 (Philippines, Singapore, etc.)
    const int daylightOffset_sec = 0;    // No DST in many countries

    configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org");

    configTime(8 * 3600, 0, "pool.ntp.org", "time.google.com", "asia.pool.ntp.org");


    Serial.println("Syncing time...");

    delay(5000);  // Wait for NTP sync

    time_t now = time(nullptr);
    int attempts = 10;
    while (now < 1000000000 && attempts > 0) { // Check if time is reasonable
        Serial.println("Waiting for NTP sync...");
        delay(1000);
        now = time(nullptr);
        attempts--;
    }
    
    if (now < 1000000000) {
        Serial.println("❌ Failed to get time from NTP!");
    } else {
        Serial.println("✅ Time synchronized!");
    }
}

  //Getting the Date and Time here 
  String getDateString() {
    time_t now = time(nullptr);
    struct tm timeInfo;
    localtime_r(&now, &timeInfo);
    char buffer[11];  // YYYY-MM-DD format
    strftime(buffer, sizeof(buffer), "%Y-%m-%d", &timeInfo);
    return String(buffer);
}

  String getTimeString() {
    time_t now = time(nullptr);
    struct tm timeInfo;
    localtime_r(&now, &timeInfo);
    char buffer[9];  // HH-MM-SS format
    strftime(buffer, sizeof(buffer), "%H-%M-%S", &timeInfo);
    return String(buffer);
}

String getSelectedPlot() {
    String selectedPlot;
    if (Firebase.RTDB.getString(&fbdo, "SelectedPlot/plotName")) {
        selectedPlot = fbdo.stringData();
        Serial.println("Selected Plot: " + selectedPlot); 
    } else {
        Serial.println("Failed to get selected plot: " + fbdo.errorReason());
        selectedPlot = "Plot1";  // Default to Plot1 if failed
    }
    return selectedPlot;
}
  // Connecting and creating logs storing to Firestore
  void saveDailyLogToFirestore(float temperature, float humidity, float avgMoisture, 
                             int moisture1, int moisture2, 
                             int moisture3, 
                             int moisture4) {
    FirebaseJson json;
    
    // Get current date and time
    String dateString = getDateString();
    String timeString = getTimeString();  

    // Get time in ISO 8601 format
    time_t now = time(nullptr);
    struct tm timeInfo;
    gmtime_r(&now, &timeInfo);  // Convert to UTC time

    char isoTime[25];  // "YYYY-MM-DDTHH:MM:SSZ"
    strftime(isoTime, sizeof(isoTime), "%Y-%m-%dT%H:%M:%SZ", &timeInfo);
    //print debugg statemnt
    Serial.print("Current timestamp: ");
    Serial.println(isoTime);

    // Get selected plot
    String selectedPlot = getSelectedPlot();

    json.set("fields/plot/stringValue", selectedPlot);
    json.set("fields/timestamp/timestampValue", isoTime);
    json.set("fields/temperature/doubleValue", temperature);
    json.set("fields/humidity/doubleValue", humidity);
    json.set("fields/average_moisture/doubleValue", avgMoisture);
    json.set("fields/moisture_1/integerValue", moisture1);
    json.set("fields/moisture_2/integerValue", moisture2);
    json.set("fields/moisture_3/integerValue", moisture3);
    json.set("fields/moisture_4/integerValue", moisture4);


    String jsonString;
    json.toString(jsonString, true);

    // Firestore path: "Plots/{selectedPlot}/sensorData/{dateString}/{timeString}"
    String collectionPath = "Plots/" + selectedPlot + "/sensorData";
    String documentPath = dateString + "_" + timeString; // Ensures valid document ID

    // Creating document and collection logs to the firestore
    if (firestore.createDocument(&fbdo, "test-monitor-reui", "", collectionPath.c_str(), documentPath.c_str(), jsonString.c_str(), "")) {
        Serial.println("Daily log saved: " + collectionPath + "/" + documentPath);
    } else {
        Serial.println("Failed to save log: " + fbdo.errorReason());
    }
}

void listenForPlotChanges() {
  Firebase.RTDB.getString(&fbdo, "SelectedPlot");
  String selectedPlot = fbdo.stringData();

  Serial.print("Selected Plot: ");
  Serial.println(selectedPlot);

  if (selectedPlot == "Plot 1") {
    // Read sensors for Plot 1
    readAndDisplaySensorValues();

  } else if (selectedPlot == "Plot 2") {
    // Read sensors for Plot 2
    readAndDisplaySensorValues();
  }
}

void setup(){
  Serial.begin(115200);
  pinMode(GREEN_LED_PIN, OUTPUT);
  pinMode(RED_LED_PIN, OUTPUT);
    
  digitalWrite(RED_LED_PIN, HIGH);  // Assume system is not ready
  digitalWrite(GREEN_LED_PIN, LOW); // Turn off green LED initially
  
  connectToWiFi();
  setupTime();  // Initialize time

  /* Assign the api key (required) */
  config.api_key = API_KEY;

  /* Assign the RTDB URL (required) */
  config.database_url = DATABASE_URL;
  dht.begin(); //begin dht sens 

  /* Sign up */
  if (Firebase.signUp(&config, &auth, "", "")){
    Serial.println("ok");
    signupOK = true;
  }
  else{
    Serial.printf("%s\n", config.signer.signupError.message.c_str());
  }

  /* Assign the callback function for the long running token generation task */
  config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h
  
  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);
}


void loop() {
  listenForPlotChanges();  // Check Firebase for the selected plot
  delay(1000); 
  
  // Storing For Realtime
    if (Firebase.ready() && signupOK && (millis() - sendDataPrevMillis > 2000 || sendDataPrevMillis == 0)) {
        sendDataPrevMillis = millis();
        readAndDisplaySensorValues();
    }

    // Get current time for 
    time_t now = time(nullptr);
    struct tm timeInfo;
    localtime_r(&now, &timeInfo);

    int currentHour = timeInfo.tm_hour;
    int currentMinute = timeInfo.tm_min;
    static int lastLoggedMinute = -1;
    static int lastLoggedHour = -1;


    // **Scheduled logging at specific hours**
    if ((currentHour == 8 || currentHour == 11 || currentHour == 12 ||currentHour == 13 ||
    currentHour == 14 ||currentHour == 15 || currentHour == 17 || currentHour == 3 || currentHour == 4 ) &&
        lastLoggedHour != currentHour) {
    lastLoggedHour = currentHour;
    logSensorDataToFirestore();
    Serial.println("📌 Firestore log saved (Scheduled Time).");
}
}



// Function to log sensor data to Firestore
// Just calling this function inside the loop function
void logSensorDataToFirestore() {
    float temperature = dht.readTemperature();
    float humidity = dht.readHumidity();
   int moisture1 = analogRead(sensorPin1);
    int moisture2 = analogRead(sensorPin2);
    int moisture3 = analogRead(sensorPin3);
    int moisture4 = analogRead(sensorPin4);
    int moisturePercent1 = map(moisture1, dryValue1, wetValue1, 0, 100);
    int moisturePercent2 = map(moisture2, dryValue2, wetValue2, 0, 100);
    int moisturePercent3 = map(moisture3, dryValue3, wetValue3, 0, 100);
    int moisturePercent4 = map(moisture4, dryValue4, wetValue4, 0, 100);

   // Ensure values stay between 0% and 100%
    moisturePercent1 = constrain(moisturePercent1, 0, 100);
    moisturePercent2 = constrain(moisturePercent2, 0, 100);
    moisturePercent3 = constrain(moisturePercent3, 0, 100);
    moisturePercent4 = constrain(moisturePercent4, 0, 100);
    float avgMoisture = (moisturePercent1 + moisturePercent2 + moisturePercent3 + moisturePercent4) / 4.0;
    saveDailyLogToFirestore(temperature, humidity, avgMoisture, 
                        moisturePercent1, moisturePercent2, 
                        moisturePercent3, moisturePercent4, getSelectedPlot());

}

If that API key in your code is the real API key, I suggest that you (when posting on the forum) replace it with something like ***.

I can't help you but have a question. Why does wifiList[][3] have 3 columns but you only specify 2 in the initialisation?

This is a pretty smsll sketch. So some of your libraries are likely very big...
Also: if you have 4 the same things it would be better if they were put into an array...

This function should have a generic name. That will allow easier reuse...

The ESP32 boards default to having a flash "partitioning" scheme that reserves some of the flash for a file system (SPIFS) and some for over-the-air SW updates. If you're not using those, or can get by with a smaller file system, you can just pick a different partition scheme in the "tools" menu, and it will give you more program space...