Execute Code ONLY once on State change

I am trying to send a sms message 1 time (on state change?) when water is considered high or low(determined by 2 floating balls that act as switches)

I am unable to determine a way to prevent a hundred messages being sent while either condition is true, i only need 1 message sent at a time. Thanks for reading and helping.

#include "arduino4G.h"
int lowfloat = 8;
int highfloat = 9;
int led = 3;
int buttonState1 = 1; //reads float status
int buttonState2 = 1; //reads float status
int ledstate = LOW;
unsigned long previousMillis = 0;
const long interval = 1000;
//////////////////////////////////////////////////
char phone_number[] = "";
char sms_body[] = "";
uint8_t error;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Initializing.");
  Serial.println("Initializing..");
  Serial.println("Initializing...");
  pinMode(highfloat, INPUT_PULLUP); // Internal Resistor 10K
  pinMode(lowfloat, INPUT_PULLUP);// Internal Resistor 10K
  pinMode (led, OUTPUT);

}

void loop() {
  buttonState1 = digitalRead(lowfloat);
  buttonState2 = digitalRead(highfloat);



  if  (buttonState1 == HIGH & buttonState2 == HIGH)
  { Serial.println ("High Level");
  sendsms();  //send 1 message saying water high
  digitalWrite(led, LOW);
  }
  else {
    sendlowsms();  //send 1 message saying water low
    }
}

void sendsms() 
{

  error = _4G.sendSMS(phone_number, "Water High"); //4g

}

void  sendlowsms(){
 error = _4G.sendSMS(phone_number, "Water Low"); //4g

}
  
}

if  (buttonState1 == HIGH & buttonState2 == HIGH)The above won't work as you expect. Use "&&" (logical AND) instead of "&" (bitwise AND).

You can use a status variable to indicate message sent, for example something like the following:

if (message_sent == false ) {
sendsms();
message_sent = true;
}

jremington:
if  (buttonState1 == HIGH & buttonState2 == HIGH)The above won't work as you expect. Use "&&" (logical AND) instead of "&" (bitwise AND).

You can use a status variable to indicate message sent, for example something like the following:

if (message_sent == false ) {

sendsms();
message_sent = true;
}

Thanks for the suggestion.
Should that if statement be nested inside of the other if statements that look at water level?
Im just a little confused on its placement.
Thanks

jremington:

if  (buttonState1 == HIGH & buttonState2 == HIGH)

The above won't work as you expect. Use "&&" (logical AND) instead of "&" (bitwise AND).

That expression will work as expected, though it is more customary (and more correct) to use "&&", as you said.

That expression will work as expected

In general, such expressions should be avoided because of poorly chosen operator precedence rules. This is safe, but still a bad idea:

if  ((buttonState1 == HIGH) & (buttonState2 == HIGH))

Should that if statement be nested inside of the other if statements that look at water level?

It can be. Example (be sure to declare the "sent" variables appropriately):

     if  ( (buttonState1 == HIGH) && (buttonState2 == HIGH)) {
        Serial.println ("High Level");
        if (high_message_sent == false) {
           sendsms();  //send 1 message saying water high
           high_message_sent=true;
        }
        digitalWrite(led, LOW);
     }
    else {
       if (low_message_sent == false) {
          sendlowsms();  //send 1 message saying water low
          low_message_sent = true;
       }
    }

jremington:
No, it won't in general. The & operator precedence supersedes == precedence.

No it doesn't. & has higher precedence than &&, but it's lower precedence than ==.

But you're correct that it won't work as expected in general, because & operates on bits whereas && operates on logic (zero/non-zero). 5 & 2 yields 0 while 5 && 2 yields 1 (for example). If you can ensure all of the operands are 0 or 1, then you can use &/&& and |/|| interchangeably*; otherwise you can't.

  • Using & and | instead of && and || may be useful in constant-time calculations, such as for cryptography, where you don't want to expose any secrets through a side-channel like calculation times that depend on the input.

Hi guys,

Please mark as SOLVED.

Thanks for the input. Using the StateChangeDetection sample code I was able to fullfil my goal and print to the serial monitor only once per change.
Here is an excerpt of my code.

void loop() {
  buttonState1 = digitalRead(lowfloat);
  buttonState2 = digitalRead(highfloat);


  if  (buttonState1  != lastbuttonState1 && buttonState2 != lastbuttonState2)
  {

    if (buttonState1 && buttonState2 == HIGH) {
      Serial.println("on"); ///Placeholder for send sms
    }
    else {
      Serial.println("OFF"); /////placeholder for send sms

    }


    delay(50);
    lastbuttonState1 = buttonState1;
    lastbuttonState2 = buttonState2;
  }