Counting time an input is on and performing task based on result

I created a camera system using a Raspberry Pi using the circular buffer feature. Then I have an ESP-32 board that reads the light of a stack light in order to send the paired ESP-32 board attached to the Pi to record the last however many seconds of video captured. I have a current problem that if the stack was not solid but flashing, it would send the capture signal everytime it flashed. I am trying to make it to where it can read if the input is high for a specified time (3 seconds or so) and then send the capture signal only once. Then maybe resets after the state of the stack light input is no longer on. I have tried the code below but the time being printed in the serial monitor is very odd. It is not really counting up and then also, when I turn the input off, the time is not zero'd out.

#include <esp_now.h>
#include <WiFi.h>

const int sensorPin = 4;
int val = 0;
boolean counting;
unsigned long starttime;  //some global variables available anywhere in the program
unsigned long total_time;
unsigned long elapsed_time;

// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x9C, 0x9C, 0x1F, 0xC9, 0x58, 0x84};

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
  char a[32];
} struct_message;
// Create a struct_message called myData
struct_message myData;

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
 
void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
  pinMode(sensorPin, INPUT_PULLUP);
 
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  counting = false;
  starttime = millis();

  
  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  // Set values to send
  val = digitalRead(sensorPin);
  if (val == 0 && counting==false) {
    starttime = millis();
    counting = true;
  }
  if (val == 0 && counting==true) {
    counting = false;
    elapsed_time = millis()- starttime;
    total_time = total_time + elapsed_time;
    Serial.println(total_time);
    elapsed_time = 0;
  }
  if (val == 1 && elapsed_time > 3) {
    strcpy(myData.a, "Now");
    // Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
  if (result == ESP_OK) {
    Serial.println("Sent with success");
  }
  }
  //delay(3000);
}

One obvious problem I see is that the only time you set elapsed_time you reset it to 0 a few lines later. Therefore the following conditional will NEVER be true:

if (val == 1 && elapsed_time > 3)

Try this. I can't compile or test. The idea is that every time the sensor transitions from LOW to HIGH the timer is re-started. If the the signal remains HIGH and the timer exceeds 3 seconds then the capture signal is sent. While the signal is LOW nothing happens. If the signal were to go HIGH for less than 3 seconds and then go LOW it would never send the capture signal.

void loop() 
{
  // I am trying to make it to where it can read if the input is high for a specified time (3 seconds or so) 
  // and then send the capture signal only once. Then maybe resets after the state of the stack light input 
  // is no longer on.

  static int sensorLastVal = digitalRead(sensorPin);
  int sensorVal = digitalRead(sensorPin);
  
  // Check to see if sensor value has changed
  if (sensorVal != sensorLastVal)
  {
    sensorLastVal = sensorVal;
    if (sensorVal == HIGH)
    {
      // Sensor is triggered so start the timer
      starttime = millis();
    }
  }
  
  if (sensorVal == HIGH && millis() - starttime > 3000)
  {
    strcpy(myData.a, "Now");
    // Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    if (result == ESP_OK) {
      Serial.println("Sent with success");
    sent = true;
  }
}

Can't compile due to sent = true; part at the bottom. Did you mean to leave that in there?

This seems to work other than once the time has exceeded the three seconds, it repeatedly sends the message. Is that where your sent = true; was going to come in? Thanks for the help by the way.

This what happens when you code quickly and can't test!

void loop() 
{
  // I am trying to make it to where it can read if the input is high for a specified time (3 seconds or so) 
  // and then send the capture signal only once. Then maybe resets after the state of the stack light input 
  // is no longer on.
  static bool sent = false;
  static int sensorLastVal = digitalRead(sensorPin);
  int sensorVal = digitalRead(sensorPin);
  
  // Check to see if sensor value has changed
  if (sensorVal != sensorLastVal)
  {
    sensorLastVal = sensorVal;
    if (sensorVal == HIGH)
    {
      // Sensor is triggered so start the timer
      sent = false;
      starttime = millis();
    }
  }
  
  if (sensorVal == HIGH && !sent && millis() - starttime > 3)
  {
    strcpy(myData.a, "Now");
    // Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    if (result == ESP_OK) 
    {
      Serial.println("Sent with success");
      sent = true;
    }
  }
}

Yeah I think I figured it out before. It is similar to what you have here. Thanks again!! FYI I put the bool sent = false at the very beginning so it works either way I guess.

void loop() {
  // Set values to send
  //val = digitalRead(sensorPin);
  static int sensorLastVal = digitalRead(sensorPin);
  int sensorVal = digitalRead(sensorPin);
  
  // Check to see if sensor value has changed
  if (sensorVal != sensorLastVal)
  {
    sensorLastVal = sensorVal;
    sent = false;
    if (sensorVal == LOW)
    {
      // Sensor is triggered so start the timer
      starttime = millis();
    }
  }
  
  if (sensorVal == LOW && (sent == false) && millis() - starttime > 3000)
  {
    strcpy(myData.a, "Now");
    sent = true;
    // Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    if (result == ESP_OK) {
      Serial.println("Sent with success");
    
  }
  }
}