How to show value only when value has changed (in void loop)?

I am working with ble on my esp32 and am trying to make it so when someone turns a led on, the esp32 notifies the client with either 'ON' or 'OFF'. Currently with my code the update is sent every time it loops but I only want to notify whenever the value of pin 15 changes.

I think I need to explore the same concept of someone who would want to send a serial.print whenever something changes.

Here is my relevant code.

if (deviceConnected) {
    if(digitalRead(15)==LOW){
      pCharacteristic->setValue("ON");
      
    }
    else{
      pCharacteristic->setValue("OFF");
     
    }
    pCharacteristic->notify();

I found this bit of code but am unsure if it's helpful or how to combine it into mine

int old_something;

void loop ()
{
 int something = get_my_data ();
 if (something != old_something)
   Serial.print (something);  // display if it changed
 old_something = something;
 }

Delta_G:
It sounds helpful for what you want to do. Basically you create a variable of the same type as the one you're dealing with and let it hold the old value. Each time your function runs, get your new data and you can compare to the old one. Then save the new one as the old one for next time.

In your case if the digitalRead line is the one you want to watch, then you need to create two variables, one to hold the old state and one to hold the new state and use that instead of the digitalRead call in the if statement.

I tried to implement what you mentioned and didn't seem to get it working. Must have done something wrong here is my code

//All the way at the top
boolean oldState = LOW;

// In the Loop
  boolean newState = digitalRead(15);
  
  if (deviceConnected) {
    if(newState==LOW){
      pCharacteristic->setValue("ON");
      
    }
    else{
      pCharacteristic->setValue("OFF");
     
    }
    pCharacteristic->notify();
  };

  oldState = newState;
   
  delay(50);
}

Delta_G:
Oh wait, I left something out. Look at what I wrote and look at the example you posted at the end of your first post. See the difference? See the line I left out?

Do you understand why we need that line? That's the line that says to only do this stuff when the state has changed.

Yup that fixed it! This code now works on my end. This is only a small part of a much bigger code

 boolean newState = digitalRead(15);

  if (deviceConnected) {
    if (newState != oldState) {
      if (newState == LOW) {
        pCharacteristic->setValue("ON");

      }
      else {
        pCharacteristic->setValue("OFF");

      }
      pCharacteristic->notify();
    };

    oldState = newState;

    delay(50);
  }
}

Maybe it would be good if you explored a topic called Interrupts. There are multiple examples online.

The benefits of doing those towards using a loop is less calculation, more speed, less power consumption.

Would this suit your project ???

Maybe it would be good if you explored a topic called Interrupts. There are multiple examples online.

The benefits of doing those towards using a loop is less calculation, more speed, less power consumption.

Can you please explain what place do interrupts have in solving this problem ?

UKHeliBob:
Can you please explain what place do interrupts have in solving this problem ?

Of course.

The thing you're trying to do is basically check the change of your outside system. This has been an issue since the early days of programming.

I see you're programming for stm32 so it might be best to send the relevant link here:

Now my programming might be a bit off here since I didn't test it but I believe you will get the idea:

#define PIN_TO_WATCH 15
volatile bool is_pin_changed=false;
volatile bool state_of_pin = 0;

void IRAM_ATTR ISR() interrupt_routine{
is_pin_changed = true;
state_of_pin = !state_of_pin;
}

void setup()
{
attachInterrupt(PIN_TO_WATCH , interrupt_routine, CHANGE);
state_of_pin = digitalRead(PIN_TO_WATCH);
}

void loop ()
{
if (is_pin_changed)
{
Serial.print (state_of_pin);
is_pin_changed = false;
}
}

Now, there are a couple of things to note here:

  1. the variables are volatile so we don't let our compiler optimize this part of the code
  2. if the pins are changing states at a really high rate then we might desync our state_of_pin variable.

Because of #2 we should also disable the interrupts in this part of the code and enable them again.

There is infinite ways to solve one problem, this is just one of the solutions.

I just found that this question was spot on example for introducing such a "difficult" topic of interrupts.

VielenDank:
I just found that this question was spot on example for introducing such a "difficult" topic of interrupts.

It's been my observation on this forum that using millis() timing to do several things at the same time is a more difficult concept for most than interrupts.

YMMV

dougp:
It's been my observation on this forum that using millis() timing to do several things at the same time is a more difficult concept for most than interrupts.

YMMV

MMDV

It has been my observation that users decide that using interrupts is the answer to problems that don't exist and the proposed solution using interrupts is a case in point.

The ISR in the program changes the value of a variable and the main program in loop() checks the value of that variable and acts on it. It might just as well check the state of the input directly

UKHeliBob:
MMDV

It has been my observation that users decide that using interrupts is the answer to problems that don't exist and the proposed solution using interrupts is a case in point.

The ISR in the program changes the value of a variable and the main program in loop() checks the value of that variable and acts on it. It might just as well check the state of the input directly

I see arduinos as a perfect platform for learning about code and computers. Somebody already solved it one way, I just added another one.
Having more options to choose from and to be able to learn from is always better.

I guess you feel that my answer somehow adds noise to the unexperienced reader?

UKHeliBob:
It has been my observation that users decide that using interrupts is the answer to problems that don't exist and the proposed solution using interrupts is a case in point.

We are in agreement. Rereading my statement it seems a bit murky. @Delta_G expressed it better:

Delta_G:
I know it sounds good to you now, but start writing that code out and you’ll see where it gets you stuck. Then let me add something to it like an encoder and suddenly you’re having to rewrite the whole thing because you took the solution that was “interesting” and not the one that was best.