Troubleshooting keypad matrix hard to press

hello everyone, I have a problem with the program for my final project. in my program, when I run it, there is a problem with the use of the 4x4 keypad. when I try to press the button on the keypad it is very difficult, it is necessary to press the keypad many times so that the keypad output comes out. whether all my friends can help me to improve my program.

for my project program is below

#include <PubSubClient.h>
#include <Preferences.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Keypad.h>
#include <TinyGPSPlus.h>

// ================= OLED =================
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ================ DS18B20 ===============
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// =============== Relay Lock =============
#define RELAY_PIN 2

// =============== Keypad 4x4 =============
const byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {14, 27, 26, 25};
byte colPins[COLS] = {19, 18, 17, 16};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

// =============== WiFi & MQTT =============
const char* ssid        = "Laswan";
const char* password    = "30140728";
const char* mqtt_server = "broker.emqx.io";
const int   mqtt_port   = 1883;
WiFiClient      wifiClient;
PubSubClient    client(wifiClient);
const char* topicSuhu = "vaksin/suhu";
const char* topicStok = "vaksin/stok";
const char* topicDoor = "vaksin/doorlock";
const char* topicGPS  = "vaksin/gps";

// ================= GPS ===================
TinyGPSPlus gps;
#define GPS_RX 32
#define GPS_TX 33
HardwareSerial gpsSerial(2);

// ============= Preferences ==============
Preferences prefs;
#define MAX_PIN_LENGTH 10
char pinCode[MAX_PIN_LENGTH] = "1234";
long vaksinMasuk = 0, vaksinKeluar = 0;

// ========== State & Variables ==========
enum State { 
  MAIN_MENU, PIN_INPUT, WAIT_CLOSE,
  CHOICE_VAKSIN, SETTING_MENU, CHANGE_PIN,
  INPUT_MASUK, INPUT_KELUAR
};
State currentState = MAIN_MENU;

unsigned long lastPublish    = 0;
const long   publishInterval = 5000;

String inputStr    = "";
String latitudeStr = "0.000000";
String longitudeStr= "0.000000";

// ================ SETUP =================
void setup() {
  Serial.begin(115200);

  // I2C untuk OLED
  Wire.begin();

  // GPS serial
  gpsSerial.begin(9600, SERIAL_8N1, GPS_RX, GPS_TX);

  // Mode INPUT_PULLUP pada ROW pins untuk internal pull-up
  for (byte i = 0; i < ROWS; i++) {
    pinMode(rowPins[i], INPUT_PULLUP);
  }
  // kolom dibiarkan oleh library

  // Atur debounce rendah dan polling cepat
  keypad.setDebounceTime(1);   // 1 ms debounce
  keypad.setHoldTime(200);     // 200 ms hold time

  // Relay sebagai OUTPUT
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);

  // Inisialisasi WiFi & MQTT
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);

  // Inisialisasi sensor suhu
  sensors.begin();

  // Inisialisasi OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED gagal");
    while (true) delay(10);
  }
  display.clearDisplay();

  // Load PIN & stok dari NVS
  loadPreferences();

  // Tampilkan pesan inisialisasi
  tampilPesan("Inisialisasi...\nTunggu...");
  delay(1000);
}

// ================= LOOP ==================
void loop() {
  // Update sensor & GPS
  sensors.requestTemperatures();
  float suhu = sensors.getTempCByIndex(0);
  updateGPS();

  // Baca satu key PRESSED secara event-based
  char key = getKeyPressed();

  // Publish MQTT periodik
  if (millis() - lastPublish >= publishInterval) {
    if (!client.connected()) reconnect();
    client.loop();
    publishData(suhu);
    lastPublish = millis();
  }

  // State machine
  switch (currentState) {
    case MAIN_MENU:
      tampilMainMenu(suhu);
      if (key == 'A') { waitKeyRelease(); bukaKotak(); }
      if (key == 'B') { waitKeyRelease(); menuSetting(); currentState = SETTING_MENU; }
      break;

    case PIN_INPUT:
      if (key) {
        if (key == '#') {
          if (inputStr == String(pinCode)) {
            tampilPesan("PIN Benar\nMembuka Kotak...");
            delay(300);
            digitalWrite(RELAY_PIN, HIGH);
            publishDoorlock(true);
            tampilPesan("Kotak Terbuka!\nTekan D utk Tutup");
            currentState = WAIT_CLOSE;
          } else {
            tampilPesan("PIN Salah!\nKembali...");
            delay(300);
            currentState = MAIN_MENU;
          }
          inputStr = "";
          waitKeyRelease();
        } else {
          inputStr += key;
          tampilPesan("Masukkan PIN:\n" + inputStr);
        }
      }
      break;

    case WAIT_CLOSE:
      if (key == 'D') {
        waitKeyRelease();
        digitalWrite(RELAY_PIN, LOW);
        publishDoorlock(false);
        tampilPesan("Kotak Terkunci!");
        delay(300);
        menuPilihanVaksin();
      }
      break;

    case CHOICE_VAKSIN:
      if (key == '1' || key == '2' || key == 'D') {
        waitKeyRelease();
        if (key == '1') tambahVaksin(true);
        else if (key == '2') tambahVaksin(false);
        else currentState = MAIN_MENU;
      }
      break;

    case INPUT_MASUK:
    case INPUT_KELUAR:
      if (key) {
        if (key == '#') {
          if (currentState == INPUT_MASUK) vaksinMasuk += inputStr.toInt();
          else vaksinKeluar += inputStr.toInt();
          savePreferences();
          inputStr = "";
          tampilPesan("Data Tersimpan!\nKembali...");
          delay(300);
          currentState = MAIN_MENU;
        }
        else if (isDigit(key)) {
          inputStr += key;
          tampilPesan((currentState==INPUT_MASUK?"Vaksin Masuk:\n":"Vaksin Keluar:\n") + inputStr);
        }
      }
      break;

    case SETTING_MENU:
      if (key == '1' || key == '2' || key == '3' || key == 'D') {
        waitKeyRelease();
        if (key == '1') gantiPIN();
        else if (key == '2') tambahVaksin(true);
        else if (key == '3') tambahVaksin(false);
        else currentState = MAIN_MENU;
      }
      break;

    case CHANGE_PIN:
      if (key) {
        if (key == '#') {
          if (inputStr.length() >= 4) {
            strncpy(pinCode, inputStr.c_str(), MAX_PIN_LENGTH-1);
            pinCode[MAX_PIN_LENGTH-1] = '\0';
            savePreferences();
            tampilPesan("PIN Diubah!");
            delay(300);
          } else {
            tampilPesan("Minimal 4 digit");
            delay(300);
          }
          inputStr = "";
          currentState = MAIN_MENU;
        } else {
          inputStr += key;
          tampilPesan("PIN Baru:\n" + inputStr);
        }
      }
      break;
  }
}

// ============== FUNCTIONS ==============

// 1) WiFi & MQTT
void setup_wifi() {
  Serial.print("Connect WiFi " ); Serial.print(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) { delay(300); Serial.print("."); }
  Serial.println(" connected");
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("MQTT connect...");
    if (client.connect("ESP32Client")) Serial.println("ok");
    else { Serial.print("fail, rc="); Serial.print(client.state()); Serial.println(" retry"); delay(2000);} 
  }
}

// 2) Publish data
void publishData(float suhu) {
  client.publish(topicSuhu, String(suhu,2).c_str());
  client.publish(topicStok, String(vaksinMasuk - vaksinKeluar).c_str());
  client.publish(topicGPS, (latitudeStr + "," + longitudeStr).c_str());
}

void publishDoorlock(bool open) {
  client.publish(topicDoor, open ? "TERBUKA" : "TERKUNCI");
}

// 3) Preferences (NVS)
void loadPreferences() {
  prefs.begin("vaksin", true);
  String p = prefs.getString("pin", "1234");
  p.toCharArray(pinCode, MAX_PIN_LENGTH);
  vaksinMasuk = prefs.getLong("in", 0);
  vaksinKeluar= prefs.getLong("out", 0);
  prefs.end();
}

void savePreferences() {
  prefs.begin("vaksin", false);
  prefs.putString("pin", String(pinCode));
  prefs.putLong("in", vaksinMasuk);
  prefs.putLong("out", vaksinKeluar);
  prefs.end();
}

// 4) GPS update
void updateGPS() {
  while (gpsSerial.available()) gps.encode(gpsSerial.read());
  if (gps.location.isValid()) {
    latitudeStr  = String(gps.location.lat(), 6);
    longitudeStr = String(gps.location.lng(), 6);
  }
}

// 5) Keypad helper
char getKeyPressed() {
  keypad.getKeys();
  for (int i = 0; i < LIST_MAX; i++) {
    if (keypad.key[i].stateChanged && keypad.key[i].kstate == PRESSED) {
      return keypad.key[i].kchar;
    }
  }
  return NO_KEY;
}

void waitKeyRelease() {
  while (getKeyPressed() != NO_KEY) {
    keypad.getKeys();
  }
}

// 6) OLED display
void tampilPesan(const String& msg) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(msg);
  display.display();
}

void tampilMainMenu(float suhu) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("====================");
  display.println(" Cold Chain Storage");
  display.println("--------------------");
  display.print("Suhu : "); display.print(suhu,2); display.println(" C");
  display.print("Stok : "); display.println(vaksinMasuk - vaksinKeluar);
  display.print("Lat  : "); display.println(latitudeStr);
  display.print("Long : "); display.println(longitudeStr);
  display.println("A:Open  B:Setting");
  display.display();
}

// 7) Menu actions
void bukaKotak() {
  inputStr = "";
  tampilPesan("Masukkan PIN:");
  currentState = PIN_INPUT;
}

void menuSetting() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("1:Ganti PIN");
  display.println("2:Vaksin Masuk");
  display.println("3:Vaksin Keluar");
  display.println("D:Kembali");
  display.display();
}

void gantiPIN() {
  inputStr = "";
  tampilPesan("PIN Baru:\n#=Selesai");
  currentState = CHANGE_PIN;
}

void tambahVaksin(bool masuk) {
  inputStr = "";
  tampilPesan(masuk ? "Vaksin Masuk:\n#=Selesai" : "Vaksin Keluar:\n#=Selesai");
  currentState = masuk ? INPUT_MASUK : INPUT_KELUAR;
}

void menuPilihanVaksin() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("1:Vaksin Masuk");
  display.println("2:Vaksin Keluar");
  display.println("D:Kembali");
  display.display();
  currentState = CHOICE_VAKSIN;
}

Welcome

sensors.requestTemperatures() is a blocking function, unless you use sensors.setWaitForConversion(false) to make it non-blocking. This is most likely the cause of your problem.

See DallasTemperature library documentation and examples : Arduino-Temperature-Control-Library/examples/WaitForConversion2/WaitForConversion2.ino at master · milesburton/Arduino-Temperature-Control-Library · GitHub

Also I recommend you do less temperature readings, like every 5 or 10 seconds.

Use the simpler, stable keypad.getKey() function instead. It returns a single key character when pressed — no state change tracking, just active key polling.

char key = getKeyPressed();

With:

char key = keypad.getKey();

And remove your custom getKeyPressed() function entirely.

Also update waitKeyRelease():

void waitKeyRelease() {
  while (keypad.getKey() != NO_KEY) {
    delay(10);
  }
}