//Arduino forum 02_21_2022 blh64 Faraday https://forum.arduino.cc/t/onebutton-library-doubleclick/959465/30
//My_Working_OneButton_Harley_Fog_Lights_With_Police_Fine_Tuneup_1.uno
//button 4 blinks the fog lights
//Button 5 has 3 jobs short click, long press, double click
//Button 5 will have 3 jobs, a short press will toggle on or off the high beam fog lights, as you have coded.
//Button 5 the first long press will turn off all the fog lights, and a second long press will turn on just the low beam fog lights, as you have coded.
//while all the fog lights are off , no other button presses will work
//Button 5 a first double click, will turn on the police lights, and a second double click will turn off the police lights and just light the low beam fog lights, the high beams will be off.
//The low beam fog lights are always on as default.
//Declarations
#include "OneButton.h"
//===================================================================================================================================================
//=======================================================================================================================================================
//BEGIN run_police_lights_2 code
//=======================================================================================================================================================
// HARDWARE AND TIMER SETTINGS
// YOU MAY NEED TO CHANGE THESE CONSTANTS TO YOUR HARDWARE AND NEEDS
// CONSTANT DEFINITION
constexpr byte LedPinsStages[] {6,7,8,9}; // portPin o---|220|---|LED|---GND
//LED pins
constexpr byte LedPinsStage1[] {6,7}; // portPin o---|220|---|LED|---GND
constexpr byte LedPinsStage3[] {8,9};
// portPin o---|220|---|LED|---GND
//How many flashes
constexpr int numberOfFlashs1 {6};
constexpr int numberOfFlashs3 {6};
//set the times
constexpr unsigned long delayTimeStage1 {50};
constexpr unsigned long delayTimeStage2 {100};
constexpr unsigned long delayTimeStage3 {50};
#define OutPutTest
unsigned long OutPutTestTime {500};
// VARIABLE DECLARATION AND DEFINITION
unsigned long currentTime;
struct TIMER { // has the following members
unsigned long duration; // memory for interval time
unsigned long stamp; // memory for actual time
bool onOff; // control for start/stop
};
TIMER stage1 {delayTimeStage1, 0, false};
TIMER stage2 {delayTimeStage2, 0, false};
TIMER stage3 {delayTimeStage3, 0, false};
bool timerEvent (TIMER &timer) {
return (currentTime - timer.stamp >= timer.duration && timer.onOff);
}
void startTimer(TIMER &timer) {
timer.stamp = currentTime;
timer.onOff = true;
}
void resetTimer(TIMER &timer) {
timer.stamp = currentTime;
}
void stoppTimer(TIMER &timer) {
timer.onOff = false;
}
void toogleLedPin(int pin) {
digitalWrite(pin, !digitalRead(pin));
}
//=======================================================================================================================================================
//END run_police_lights_2 code
//=======================================================================================================================================================
// Setup a new OneButton push buttons on pin 4 and 5
/*
Button 4 - toggle blinking on/off
Button 5 - toggle HIGH fog ligts on, long click - toggle all lights on/off
*/
//OneButton blink_button(4, true); //original
//OneButton on_off_button(5, true); //original
OneButton button_blink_the_fog_lights(4, true, true);
OneButton switch_turn_on_the_high_beam_fog_lights(5, true, true);
//define
#define DISABLED false
#define ENABLED true
#define LEDon HIGH
#define LEDoff LOW
unsigned long currentMillis;
unsigned long previousMillis;
unsigned long on_off_long_press_start_time;
const unsigned long blinkInterval = 100;
//this is not needed on a long press because of switch_turn_on_the_high_beam_fog_lights.setPressTicks(2500); // a long press will be detected after 2500 ms
const unsigned long longPressInterval = 2500;
//LED's
const int fog_light_low_beam = 6;
const int fog_light_low_beam_indicator = 7;
const int fog_light_high_beam = 8;
const int fog_light_high_beam_indicator = 9;
//bool
bool blinking = DISABLED;
bool inLongPress = false;
bool all_the_fog_lights_are_off = DISABLED;
//enum
//enum { LIGHTS_OFF, LIGHTS_LOW_BEAM, LIGHTS_BOTH };//original
enum { LIGHTS_OFF, LIGHTS_LOW_BEAM, LIGHTS_BOTH, POLICE_LIGHTS };
int lightState;
//Police lights
bool start_police_lights_now = DISABLED;
bool Short_Button_Press_Allowed = ENABLED;
const long onDuration_1 = 250;// OFF time for LED//orig 100
const long offDuration_1 = 200;// ON time for LED //orig 500 lower this number for a faster blink
const long onDuration_2 = 250;// OFF time for LED// orig 100
const long offDuration_2 = 200;// ON time for LED//orig 500 lower this number for a faster blink
int LEDState_1 = HIGH;// initial state of LED
int LEDState_2 = LOW;// initial state of LED
long rememberTime_1 = 0;// this is used by the code
long rememberTime_2 = 0;
//end Police
//END Declarations
void setup()
{
//=======================================================================================================================================================
//BEGIN run_police_lights_2 code
//=======================================================================================================================================================
// https://www.learncpp.com/cpp-tutorial/for-each-loops/
for (auto Output_ : LedPinsStages) pinMode(Output_, OUTPUT);
#ifdef OutPutTest
// check outputs
//for (auto Output_ : LedPinsStages) digitalWrite(Output_, HIGH), delay(OutPutTestTime);//original
//BEGIN my add edit
////this does NOT light the 4 LED's, on startup, when Output is set to LOW, uncomment it if you wish, and then "comment out" for (auto Output_ : LedPinsStages) digitalWrite(Output_, HIGH), delay(OutPutTestTime);
//for (auto Output_ : LedPinsStages) digitalWrite(Output_, LOW), delay(OutPutTestTime);
//this lights the 4 LED's, on startup, when Output is set to HIGH, comment it out is you wish and then "uncomment" /for (auto Output_ : LedPinsStages) digitalWrite(Output_, LOW), delay(OutPutTestTime);
for (auto Output_ : LedPinsStages) digitalWrite(Output_, HIGH), delay(OutPutTestTime);
//END my add edit
for (auto Output_ : LedPinsStages) digitalWrite(Output_, LOW), delay(OutPutTestTime);
#endif
startTimer(stage1);
//=======================================================================================================================================================
//END run_police_lights_2 code
//=======================================================================================================================================================
pinMode(fog_light_low_beam, OUTPUT);
pinMode(fog_light_low_beam_indicator, OUTPUT);
pinMode(fog_light_high_beam, OUTPUT);
pinMode(fog_light_high_beam_indicator, OUTPUT);
digitalWrite(fog_light_high_beam, LEDoff);
digitalWrite(fog_light_high_beam_indicator, LEDoff);
digitalWrite(fog_light_low_beam, LEDon);
digitalWrite(fog_light_low_beam_indicator, LEDon);
//turns on the low beeams default
lightState = LIGHTS_LOW_BEAM;
// Setup the Serial port. see http://arduino.cc/en/Serial/IfSerial
Serial.begin(9600);
while (!Serial)
{
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.println("\nAway we go!\n");
//link your buttos here
button_blink_the_fog_lights.attachClick(blink_click);//original this is for a "latched switch" if you want one
//begin my add or edit
button_blink_the_fog_lights.attachLongPressStart(blink_click);//this is for a momentary-on switch the "blinking" variable gets switched on and off in the blink_click function, blinking = !blinking;
button_blink_the_fog_lights.attachLongPressStop(blink_click);//this is for a momentary-on switch the "blinking" variable gets switched on and off in the blink_click function, blinking = !blinking;
//
button_blink_the_fog_lights.setDebounceTicks(50);
button_blink_the_fog_lights.setPressTicks(10);//set faster click response
//end my add or edit
//original
switch_turn_on_the_high_beam_fog_lights.attachClick(on_off_click);//original
switch_turn_on_the_high_beam_fog_lights.attachLongPressStart(on_off_long_press_start);//original
switch_turn_on_the_high_beam_fog_lights.attachDuringLongPress(on_off_long_press);//original
switch_turn_on_the_high_beam_fog_lights.attachLongPressStop(on_off_long_press_stop);//original
//begin my add or edit
switch_turn_on_the_high_beam_fog_lights.setDebounceTicks(50);
switch_turn_on_the_high_beam_fog_lights.setClickTicks(150);//this 150ms will allow the doubleclick to work, any "lower" and doubleclick will not be detected
switch_turn_on_the_high_beam_fog_lights.setPressTicks(2500); // a long press will be detected after 2500 ms
switch_turn_on_the_high_beam_fog_lights.attachDoubleClick(doubleclick); //will use this for police lights
//end my add or edit
} //setup
void loop()
{
//don't forget to set start time with millis()
currentMillis = millis();
//currentTime = millis(); used for run_police_lights_2
currentTime = millis();
// keep watching the push buttons:
button_blink_the_fog_lights.tick();
switch_turn_on_the_high_beam_fog_lights.tick();
if (blinking)
{
//call the function
blink_the_fog_lights();
}
if(start_police_lights_now)//toggled in doubleclick
{
lightState = POLICE_LIGHTS;//set lightState to POLICE_LIGHTS
blinking = DISABLED;
Short_Button_Press_Allowed = DISABLED;//don't allow short clicks
//call the function
//run_police_lights();
run_police_lights_2();
}
else//police lights are off
{
Short_Button_Press_Allowed = ENABLED;// allow short clicks
}
}//loop
//SHORT PRESS BUTTON 4 toggle on and off the high beam fog lights
void on_off_click()//button 5 short press hereh "LIGHTS_BOTH" is doing 1 job here for a "short press" high beams are OFF low beams are ON
{
// if the high beam fog lights are off, turn them on
// if the high beam fog lights are on, turn them off
if(Short_Button_Press_Allowed)
{
Serial.println("switch_turn_on_the_high_beam_fog_lights click.");
switch ( lightState )
{
case POLICE_LIGHTS:// short press do noting
break;
case LIGHTS_OFF: // all lights are off so ignore
break;
//this is called initally from void setup() lightState = LIGHTS_LOW_BEAM;
case LIGHTS_LOW_BEAM: // low beam fog lights are on so switch to just high beam fog lights
digitalWrite(fog_light_high_beam, LEDon);
digitalWrite(fog_light_high_beam_indicator, LEDon);
digitalWrite(fog_light_low_beam, LEDon);
digitalWrite(fog_light_low_beam_indicator, LEDon);
lightState = LIGHTS_BOTH;
Serial.println("high ON");
break;
case LIGHTS_BOTH: // both low and high beam fog lights are on so switch high off, "LIGHTS_BOTH" is doing 1 job here for the second "short press" high beams are OFF low beams are ON
digitalWrite(fog_light_high_beam, LEDoff);
digitalWrite(fog_light_high_beam_indicator, LEDoff);
digitalWrite(fog_light_low_beam, LEDon);
digitalWrite(fog_light_low_beam_indicator, LEDon);
lightState = LIGHTS_LOW_BEAM;
Serial.println("high OFF");
break;
}//switch case
}//if
}// end on_off_click()
//LONG PRESS BUTTON 5 on the first long press turn off all the fog lights then on the second long press turn back on just the low beam fog lights
void on_off_long_press()//button 5 long press here or doubleclick
{
// this gets called while a long press is in progress
// if enough time has elapsed, toggle the state
//using millis() here
unsigned long duration = millis() - on_off_long_press_start_time;
if ( duration >= longPressInterval && inLongPress == true )
{
// if the high beam fog lights are off, turn them on
// if the high beam fog lights are on, turn them off
Serial.println("Button 5 on_off_longPress.");
//lightState can be used in other functions
switch (lightState)
{
case LIGHTS_OFF: // all lights are off so turn on low beam fog lights
Serial.println("long press button 5 High Beam Fog Lights Off will call LIGHTS_BOTH on the next press");
digitalWrite(fog_light_high_beam, LEDoff);
digitalWrite(fog_light_high_beam_indicator, LEDoff);
digitalWrite(fog_light_low_beam, LEDon);
digitalWrite(fog_light_low_beam_indicator, LEDon);
all_the_fog_lights_are_off = DISABLED;
lightState = LIGHTS_LOW_BEAM;
Serial.println("low ON");
break;
case LIGHTS_LOW_BEAM: // low beam fog lights are on so switch everything off
case LIGHTS_BOTH: // "LIGHTS_BOTH" is doing another job here for a "long press", both low and high beam fog lights are off
Serial.println("long press button 5 ALL Fog Lights Off will call LIGHTS_OFF on the next press");
digitalWrite(fog_light_high_beam, LEDoff);
digitalWrite(fog_light_high_beam_indicator, LEDoff);
digitalWrite(fog_light_low_beam, LEDoff);
digitalWrite(fog_light_low_beam_indicator, LEDoff);
all_the_fog_lights_are_off = ENABLED;
lightState = LIGHTS_OFF;
Serial.println("all OFF");
break;
case POLICE_LIGHTS:
lightState = POLICE_LIGHTS;
break;
}//switch case
inLongPress = false;//this was set true in void on_off_long_press_start(), and set false also in void on_off_long_press_stop()
}//if
}//on_off_long_press_stop()
void on_off_long_press_start()
{
// record time of the long press
//begin my add edit
//on_off_long_press_start_time = millis();//don't need millis here because of switch_turn_on_the_high_beam_fog_lights.setPressTicks(2500); // a long press will be detected after 2500 ms
//end my add edit
inLongPress = true;
} //on_off_long_press_start
void on_off_long_press_stop()
{
inLongPress = false;
}
void blink_click()
{
//this blinking bool variable, toggles "blinking" back and forth on each run of the blink_click() function
blinking = !blinking;
// if we are done blinking, make sure we leave the lights on
if ( blinking == DISABLED )//if blinking is DISABLED do nothing
{
Serial.println("blinking");
Serial.println(blinking);
if ( lightState == LIGHTS_BOTH )
{
Serial.println("blinking");
Serial.println(blinking);
digitalWrite(fog_light_high_beam, LEDon);
digitalWrite(fog_light_high_beam_indicator, LEDon);
}//if
//if the value of "lightState" equals the value of "LIGHTS_HIGH_BEAM" "OR" the value of "lightState" equals the value of "LIGHTS_BOTH"
if ( lightState == LIGHTS_LOW_BEAM || lightState == LIGHTS_BOTH )
{
// toggle low beams
digitalWrite(fog_light_low_beam, LEDon);
digitalWrite(fog_light_low_beam_indicator, LEDon);
}//if
}//blinking DISABLED
}//blink_click()
void blink_the_fog_lights()
{
//if lighrState = LIGHTS_OFF bail out, do not blink
if ( lightState == LIGHTS_OFF )
{
// lights are off so nothing to do
return;
}//if
//using millis() here
if (currentMillis - previousMillis >= blinkInterval)
{
// enough time passed yet?
previousMillis = currentMillis; // sets the time we wait "from"
if ( lightState == LIGHTS_BOTH )
{
// toggle high beams
digitalWrite(fog_light_high_beam, !digitalRead(fog_light_high_beam)); // shortcut to toggle the LED
digitalWrite(fog_light_high_beam_indicator, !digitalRead(fog_light_high_beam_indicator)); // shortcut to toggle the LED
}//if
//if the value of "lightState" equals the value of "LIGHTS_LOW_BEAM" "OR" the value of "lightState" equals the value of "LIGHTS_BOTH"
if ( lightState == LIGHTS_LOW_BEAM || lightState == LIGHTS_BOTH )
{
// toggle low beams
digitalWrite(fog_light_low_beam, !digitalRead(fog_light_low_beam)); // shortcut to toggle the LED
digitalWrite(fog_light_low_beam_indicator, !digitalRead(fog_light_low_beam_indicator)); // shortcut to toggle the LED
}//if
}//if
}//blink_the_fog_lights()
// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleclick()
{
if (!all_the_fog_lights_are_off)//all the fog lights are NOT off, so continue to run the police lights
{
if (!start_police_lights_now)//police lights are on
{
start_police_lights_now = ENABLED;
Short_Button_Press_Allowed = DISABLED;
}
else//police lights are off
{
start_police_lights_now = DISABLED;
Short_Button_Press_Allowed = ENABLED;
if (lightState = POLICE_LIGHTS)
{
digitalWrite(fog_light_high_beam, LEDoff);
digitalWrite(fog_light_high_beam_indicator, LEDoff);
digitalWrite(fog_light_low_beam, LEDon);
digitalWrite(fog_light_low_beam_indicator, LEDon);
lightState = LIGHTS_LOW_BEAM;//go back to short press LIGHTS_LOW_BEAM
} //if
}//else
} //all_the_fog_lights_are_off
} //end doubleclick
//Police
void run_police_lights()
{
if(start_police_lights_now)
{
Serial.println("the police lights are on");
// LED blink with millis()
if( LEDState_1 == HIGH )
{
if( (millis() - rememberTime_1) >= onDuration_1)
{
LEDState_1 = LOW;// change the state of LED
rememberTime_1 = millis();// remember Current millis() time
}//if
}
else
{
if( (millis()- rememberTime_1) >= offDuration_1)
{
LEDState_1 = HIGH;// change the state of LED
rememberTime_1 = millis();// remember Current millis() time
}//if else
}//if
// LED blink with millis()
digitalWrite(fog_light_low_beam,LEDState_1);// turn the LED ON or OFF
digitalWrite(fog_light_low_beam_indicator,LEDState_1);// turn the LED ON or OFF
if( LEDState_2 ==LOW )
{
if( (millis() - rememberTime_2) >= onDuration_2)
{
LEDState_2 = HIGH;// change the state of LED
rememberTime_2 = millis();// remember Current millis() time
}
}
else
{
if( (millis()- rememberTime_2) >= offDuration_2)
{
LEDState_2 = LOW;// change the state of LED
rememberTime_2 = millis();// remember Current millis() time
}//if
}//if else
// LED blink with millis()
digitalWrite(fog_light_high_beam,LEDState_2);// turn the LED ON or OFF
digitalWrite(fog_light_high_beam_indicator,LEDState_2);// turn the LED ON or OFF
}
else
{
if (!start_police_lights_now)
{
digitalWrite(fog_light_high_beam,LEDoff);
digitalWrite(fog_light_high_beam_indicator,LEDoff);
Short_Button_Press_Allowed = ENABLED;
}//if
}//if else
} //end void
void run_police_lights_2()
{
if(start_police_lights_now)
{
if (timerEvent(stage1))
{
for (auto LedPinStage1 : LedPinsStage1) toogleLedPin(LedPinStage1);
resetTimer(stage1);
static int counter=0;
if(!(++counter%=numberOfFlashs1<<1)) startTimer(stage2),stoppTimer(stage1);
}
if (timerEvent(stage2))
{
startTimer(stage3),stoppTimer(stage2);
}
if (timerEvent(stage3))
{
for (auto LedPinStage3 : LedPinsStage3) toogleLedPin(LedPinStage3);
resetTimer(stage3);
static int counter=0;
if(!(++counter%=numberOfFlashs3<<1)) startTimer(stage1),stoppTimer(stage3);
}
}
else
{
if (!start_police_lights_now)
{
digitalWrite(fog_light_high_beam,LEDoff);
digitalWrite(fog_light_high_beam_indicator,LEDoff);
Short_Button_Press_Allowed = ENABLED;
}//if
}//else
}//run_police_lights_2