Updated SpanButtton to recognize new Double Press event
button(int pin, boolean isLong) changed to button(int pin, int pressType), where pressType can be SpanButton::LONG, SpanButton::SINGLE, or SpanButton::DOUBLE. Updated Example 16 and confirmed everything works as expected. To do: Review all prior examples and update SpanButton when needed. Also need to update Zephyr Vent Hood code!
This commit is contained in:
parent
bde63bf79d
commit
e2f11630fa
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
struct DEV_ProgButton : Service::StatelessProgrammableSwitch { // Stateless Programmable Switch
|
struct DEV_ProgButton : Service::StatelessProgrammableSwitch { // Stateless Programmable Switch
|
||||||
|
|
||||||
int buttonPin; // pin with programmable pushbutton
|
|
||||||
SpanCharacteristic *switchEvent; // reference to the ProgrammableSwitchEvent Characteristic
|
SpanCharacteristic *switchEvent; // reference to the ProgrammableSwitchEvent Characteristic
|
||||||
|
|
||||||
DEV_ProgButton(int buttonPin, int index) : Service::StatelessProgrammableSwitch(){
|
DEV_ProgButton(int buttonPin, int index) : Service::StatelessProgrammableSwitch(){
|
||||||
|
|
@ -13,10 +12,9 @@ struct DEV_ProgButton : Service::StatelessProgrammableSwitch { // Stateles
|
||||||
switchEvent=new Characteristic::ProgrammableSwitchEvent(); // ProgrammableSwitchEvent Characteristic
|
switchEvent=new Characteristic::ProgrammableSwitchEvent(); // ProgrammableSwitchEvent Characteristic
|
||||||
new Characteristic::ServiceLabelIndex(index); // set service label index
|
new Characteristic::ServiceLabelIndex(index); // set service label index
|
||||||
|
|
||||||
new SpanButton(buttonPin); // create new SpanButton
|
new SpanButton(buttonPin); // create new SpanButton
|
||||||
this->buttonPin=buttonPin; // save button pin number
|
|
||||||
|
|
||||||
Serial.print("Configuring Programmable Pushbutton: Pin="); // initialization message
|
Serial.print("Configuring Programmable Pushbutton: Pin="); // initialization message
|
||||||
Serial.print(buttonPin);
|
Serial.print(buttonPin);
|
||||||
Serial.print(" Index=");
|
Serial.print(" Index=");
|
||||||
Serial.print(index);
|
Serial.print(index);
|
||||||
|
|
@ -24,15 +22,17 @@ struct DEV_ProgButton : Service::StatelessProgrammableSwitch { // Stateles
|
||||||
|
|
||||||
} // end constructor
|
} // end constructor
|
||||||
|
|
||||||
void button(int pin, boolean isLong) override {
|
void button(int pin, int pressType) override {
|
||||||
|
|
||||||
LOG1("Found button press on pin: "); // always a good idea to log messages
|
LOG1("Found button press on pin: "); // always a good idea to log messages
|
||||||
LOG1(pin);
|
LOG1(pin);
|
||||||
LOG1(" type: ");
|
LOG1(" type: ");
|
||||||
LOG1(isLong?"LONG":"SHORT");
|
LOG1(pressType);
|
||||||
|
LOG1(" ");
|
||||||
|
LOG1(pressType==SpanButton::LONG?"LONG":(pressType==SpanButton::SINGLE)?"SINGLE":"DOUBLE");
|
||||||
LOG1("\n");
|
LOG1("\n");
|
||||||
|
|
||||||
switchEvent->setVal(isLong?2:0); // set the value of the switchEvent Characteristic to 2 for long press or 0 for short press
|
switchEvent->setVal(pressType); // set the value of the switchEvent Characteristic
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1209,10 +1209,10 @@ void HAPClient::callServiceLoops(){
|
||||||
|
|
||||||
void HAPClient::checkPushButtons(){
|
void HAPClient::checkPushButtons(){
|
||||||
|
|
||||||
for(int i=0;i<homeSpan.PushButtons.size();i++){ // loop over all defined pushbuttons
|
for(int i=0;i<homeSpan.PushButtons.size();i++){ // loop over all defined pushbuttons
|
||||||
SpanButton *sb=homeSpan.PushButtons[i]; // temporary pointer to SpanButton
|
SpanButton *sb=homeSpan.PushButtons[i]; // temporary pointer to SpanButton
|
||||||
if(sb->pushButton->triggered(sb->shortTime,sb->longTime)){ // if the underlying PushButton is triggered
|
if(sb->pushButton->triggered(sb->singleTime,sb->longTime,sb->doubleTime)){ // if the underlying PushButton is triggered
|
||||||
sb->service->button(sb->pin,sb->pushButton->longPress()); // call the Service's button() routine with pin and longPress() as parameters
|
sb->service->button(sb->pin,sb->pushButton->type()); // call the Service's button() routine with pin and type as parameters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ void Span::poll() {
|
||||||
|
|
||||||
if(controlButton.triggered(3000,10000)){
|
if(controlButton.triggered(3000,10000)){
|
||||||
statusLED.off();
|
statusLED.off();
|
||||||
if(controlButton.longPress()){
|
if(controlButton.type()==PushButton::LONG){
|
||||||
controlButton.wait();
|
controlButton.wait();
|
||||||
processSerialCommand("F"); // FACTORY RESET
|
processSerialCommand("F"); // FACTORY RESET
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -232,7 +232,7 @@ void Span::commandMode(){
|
||||||
delay(2000);
|
delay(2000);
|
||||||
} else
|
} else
|
||||||
if(controlButton.triggered(10,3000)){
|
if(controlButton.triggered(10,3000)){
|
||||||
if(!controlButton.longPress()){
|
if(controlButton.type()==PushButton::SINGLE){
|
||||||
mode++;
|
mode++;
|
||||||
if(mode==6)
|
if(mode==6)
|
||||||
mode=1;
|
mode=1;
|
||||||
|
|
@ -1530,9 +1530,9 @@ SpanRange::SpanRange(int min, int max, int step){
|
||||||
// SpanButton //
|
// SpanButton //
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
SpanButton::SpanButton(int pin, unsigned long longTime, unsigned long shortTime){
|
SpanButton::SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime){
|
||||||
|
|
||||||
homeSpan.configLog+="---->SpanButton: Pin " + String(pin);
|
homeSpan.configLog+="---->SpanButton: Pin=" + String(pin) + " Long/Single/Double=" + String(longTime) + "/" + String(singleTime) + "/" + String(doubleTime) + " ms";
|
||||||
|
|
||||||
if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){
|
if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){
|
||||||
homeSpan.configLog+=" *** ERROR! Can't create new PushButton without a defined Service! ***\n";
|
homeSpan.configLog+=" *** ERROR! Can't create new PushButton without a defined Service! ***\n";
|
||||||
|
|
@ -1545,11 +1545,12 @@ SpanButton::SpanButton(int pin, unsigned long longTime, unsigned long shortTime)
|
||||||
Serial.print("\n");
|
Serial.print("\n");
|
||||||
|
|
||||||
this->pin=pin;
|
this->pin=pin;
|
||||||
this->shortTime=shortTime;
|
|
||||||
this->longTime=longTime;
|
this->longTime=longTime;
|
||||||
|
this->singleTime=singleTime;
|
||||||
|
this->doubleTime=doubleTime;
|
||||||
service=homeSpan.Accessories.back()->Services.back();
|
service=homeSpan.Accessories.back()->Services.back();
|
||||||
|
|
||||||
if((void(*)(int,boolean))(service->*(&SpanService::button))==(void(*)(int,boolean))(&SpanService::button))
|
if((void(*)(int,int))(service->*(&SpanService::button))==(void(*)(int,int))(&SpanService::button))
|
||||||
homeSpan.configLog+=" *** WARNING: No button() method defined for this PushButton! ***";
|
homeSpan.configLog+=" *** WARNING: No button() method defined for this PushButton! ***";
|
||||||
|
|
||||||
pushButton=new PushButton(pin); // create underlying PushButton
|
pushButton=new PushButton(pin); // create underlying PushButton
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ struct SpanService{
|
||||||
|
|
||||||
virtual boolean update() {return(true);} // placeholder for code that is called when a Service is updated via a Controller. Must return true/false depending on success of update
|
virtual boolean update() {return(true);} // placeholder for code that is called when a Service is updated via a Controller. Must return true/false depending on success of update
|
||||||
virtual void loop(){} // loops for each Service - called every cycle and can be over-ridden with user-defined code
|
virtual void loop(){} // loops for each Service - called every cycle and can be over-ridden with user-defined code
|
||||||
virtual void button(int pin, boolean isLong){} // method called for a Service when a button attached to "pin" has a Short-Press or Long-Press, according to "isLong"
|
virtual void button(int pin, int pressType){} // method called for a Service when a button attached to "pin" has a Single, Double, or Long Press, according to pressType
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
@ -281,14 +281,21 @@ struct SpanBuf{ // temporary storage buffer for us
|
||||||
|
|
||||||
struct SpanButton{
|
struct SpanButton{
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SINGLE=0,
|
||||||
|
DOUBLE=1,
|
||||||
|
LONG=2
|
||||||
|
};
|
||||||
|
|
||||||
int pin; // pin number
|
int pin; // pin number
|
||||||
unsigned long shortTime; // time (in millis) required to register a short press
|
uint16_t singleTime; // minimum time (in millis) required to register a single press
|
||||||
unsigned long longTime; // time (in millis) required to register a long press
|
uint16_t longTime; // minimum time (in millis) required to register a long press
|
||||||
|
uint16_t doubleTime; // maximum time (in millis) between single presses to register a double press instead
|
||||||
SpanService *service; // Service to which this PushButton is attached
|
SpanService *service; // Service to which this PushButton is attached
|
||||||
|
|
||||||
PushButton *pushButton; // PushButton associated with this SpanButton
|
PushButton *pushButton; // PushButton associated with this SpanButton
|
||||||
|
|
||||||
SpanButton(int pin, unsigned long longTime=2000, unsigned long shortTime=5);
|
SpanButton(int pin, uint16_t longTime=2000, uint16_t singleTime=5, uint16_t doubleTime=200);
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
// Utils::readSerial - reads all characters from Serial port and saves only up to max specified
|
// Utils::readSerial - reads all characters from Serial port and saves only up to max specified
|
||||||
// Utils::mask - masks a string with asterisks (good for displaying passwords)
|
// Utils::mask - masks a string with asterisks (good for displaying passwords)
|
||||||
//
|
//
|
||||||
// class PushButton - tracks Long and Short presses of a pushbutton that connects a specified pin to ground
|
// class PushButton - tracks Single, Double, and Long Presses of a pushbutton that connects a specified pin to ground
|
||||||
// class Blinker - creates customized blinking patterns on an LED connected to a specified pin
|
// class Blinker - creates customized blinking patterns on an LED connected to a specified pin
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -77,54 +77,7 @@ void PushButton::init(uint8_t pin){
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
boolean PushButton::triggered(uint16_t shortTime, uint16_t longTime){
|
boolean PushButton::triggered(uint16_t singleTime, uint16_t longTime, uint16_t doubleTime){
|
||||||
|
|
||||||
switch(status){
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
if(!digitalRead(pin)){ // button is pressed
|
|
||||||
status=1;
|
|
||||||
shortAlarm=millis()+shortTime;
|
|
||||||
longAlarm=millis()+longTime;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
if(digitalRead(pin)){ // button is released
|
|
||||||
status=0;
|
|
||||||
if(millis()>shortAlarm){
|
|
||||||
isLongPress=false;
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
|
|
||||||
if(millis()>longAlarm){ // button is long-pressed
|
|
||||||
longAlarm=millis()+longTime;
|
|
||||||
status=3;
|
|
||||||
isLongPress=true;
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
if(digitalRead(pin)) // button has been released after a long press
|
|
||||||
status=0;
|
|
||||||
else if(millis()>longAlarm){
|
|
||||||
longAlarm=millis()+longTime;
|
|
||||||
isLongPress=true;
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////
|
|
||||||
|
|
||||||
boolean PushButton::triggered(uint16_t shortTime, uint16_t longTime, uint16_t doubleTime){
|
|
||||||
|
|
||||||
unsigned long cTime=millis();
|
unsigned long cTime=millis();
|
||||||
|
|
||||||
|
|
@ -133,15 +86,15 @@ boolean PushButton::triggered(uint16_t shortTime, uint16_t longTime, uint16_t do
|
||||||
case 0:
|
case 0:
|
||||||
if(doubleCheck && cTime>doubleAlarm){
|
if(doubleCheck && cTime>doubleAlarm){
|
||||||
doubleCheck=false;
|
doubleCheck=false;
|
||||||
pressType=0;
|
pressType=SINGLE;
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!digitalRead(pin)){ // button is pressed
|
if(!digitalRead(pin)){ // button is pressed
|
||||||
shortAlarm=cTime+shortTime;
|
singleAlarm=cTime+singleTime;
|
||||||
if(!doubleCheck){
|
if(!doubleCheck){
|
||||||
status=1;
|
status=1;
|
||||||
doubleAlarm=shortAlarm+doubleTime;
|
doubleAlarm=singleAlarm+doubleTime;
|
||||||
longAlarm=cTime+longTime;
|
longAlarm=cTime+longTime;
|
||||||
} else {
|
} else {
|
||||||
status=4;
|
status=4;
|
||||||
|
|
@ -153,7 +106,7 @@ boolean PushButton::triggered(uint16_t shortTime, uint16_t longTime, uint16_t do
|
||||||
case 2:
|
case 2:
|
||||||
if(digitalRead(pin)){ // button is released
|
if(digitalRead(pin)){ // button is released
|
||||||
status=0;
|
status=0;
|
||||||
if(cTime>shortAlarm){
|
if(cTime>singleAlarm){
|
||||||
doubleCheck=true;
|
doubleCheck=true;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
|
@ -161,7 +114,7 @@ boolean PushButton::triggered(uint16_t shortTime, uint16_t longTime, uint16_t do
|
||||||
if(cTime>longAlarm){ // button is long-pressed
|
if(cTime>longAlarm){ // button is long-pressed
|
||||||
longAlarm=cTime+longTime;
|
longAlarm=cTime+longTime;
|
||||||
status=3;
|
status=3;
|
||||||
pressType=1;
|
pressType=LONG;
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -171,7 +124,7 @@ boolean PushButton::triggered(uint16_t shortTime, uint16_t longTime, uint16_t do
|
||||||
status=0;
|
status=0;
|
||||||
else if(cTime>longAlarm){
|
else if(cTime>longAlarm){
|
||||||
longAlarm=cTime+longTime;
|
longAlarm=cTime+longTime;
|
||||||
pressType=1;
|
pressType=LONG;
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -181,9 +134,9 @@ boolean PushButton::triggered(uint16_t shortTime, uint16_t longTime, uint16_t do
|
||||||
status=0;
|
status=0;
|
||||||
} else
|
} else
|
||||||
|
|
||||||
if(cTime>shortAlarm){ // button is still pressed
|
if(cTime>singleAlarm){ // button is still pressed
|
||||||
status=5;
|
status=5;
|
||||||
pressType=2;
|
pressType=DOUBLE;
|
||||||
doubleCheck=false;
|
doubleCheck=false;
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +156,7 @@ boolean PushButton::triggered(uint16_t shortTime, uint16_t longTime, uint16_t do
|
||||||
|
|
||||||
boolean PushButton::primed(){
|
boolean PushButton::primed(){
|
||||||
|
|
||||||
if(millis()>shortAlarm && status==1){
|
if(millis()>singleAlarm && status==1){
|
||||||
status=2;
|
status=2;
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
@ -213,12 +166,6 @@ boolean PushButton::primed(){
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
boolean PushButton::longPress(){
|
|
||||||
return(isLongPress);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////
|
|
||||||
|
|
||||||
int PushButton::type(){
|
int PushButton::type(){
|
||||||
return(pressType);
|
return(pressType);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
44
src/Utils.h
44
src/Utils.h
|
|
@ -44,13 +44,18 @@ class PushButton{
|
||||||
int status;
|
int status;
|
||||||
uint8_t pin;
|
uint8_t pin;
|
||||||
boolean doubleCheck;
|
boolean doubleCheck;
|
||||||
uint32_t shortAlarm;
|
uint32_t singleAlarm;
|
||||||
uint32_t doubleAlarm;
|
uint32_t doubleAlarm;
|
||||||
uint32_t longAlarm;
|
uint32_t longAlarm;
|
||||||
int pressType;
|
int pressType;
|
||||||
boolean isLongPress;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SINGLE=0,
|
||||||
|
DOUBLE=1,
|
||||||
|
LONG=2
|
||||||
|
};
|
||||||
|
|
||||||
PushButton();
|
PushButton();
|
||||||
PushButton(uint8_t pin);
|
PushButton(uint8_t pin);
|
||||||
|
|
@ -78,29 +83,34 @@ class PushButton{
|
||||||
// Resets state of PushButton. Should be called once before any loops that will
|
// Resets state of PushButton. Should be called once before any loops that will
|
||||||
// repeatedly check the button for a trigger event.
|
// repeatedly check the button for a trigger event.
|
||||||
|
|
||||||
boolean triggered(uint16_t shortTime, uint16_t longTime, uint16_t doubleTime);
|
boolean triggered(uint16_t singleTime, uint16_t longTime, uint16_t doubleTime=0);
|
||||||
boolean triggered(uint16_t shortTime, uint16_t longTime);
|
|
||||||
|
|
||||||
// Returns true if button has been triggered by either a Long Press or Short Press, where a
|
// Returns true if button has been triggered by an press event based on the following parameters:
|
||||||
// Long Press is a press and hold for at least longTime milliseconds, and a Short Press is
|
|
||||||
// a press and release of at least shortTime milliseconds but less than longTime milliseconds.
|
// singleTime: the minimum time required for the button to be pressed to trigger a Single Press
|
||||||
//
|
// doubleTime: the maximum time allowed between button presses to qualify as a Double Press
|
||||||
// shortTime: the minimum time required for the button to be pressed before releasing to trigger a Short Press
|
// longTime: the minimum time required for the button to be pressed and held to trigger a Long Press
|
||||||
// longtime: the minimum time required for the button to be pressed and held to trigger a Long Press
|
|
||||||
//
|
// All times are in milliseconds (ms). Trigger Rules:
|
||||||
// If shortTime>longTime, only Long Press triggers will occur. Once triggered() returns true, if will subsequently
|
|
||||||
// return false until there is a new trigger. After a Long Press, the button must be released to permit a subsequent
|
// * If button is pressed and continuously held, a Long Press will be triggered every longTime ms until the
|
||||||
// trigger.
|
// button is released.
|
||||||
|
// * If button is pressed for more than singleTime ms but less than longTime ms and then released, a Single Press
|
||||||
|
// will be triggered, UNLESS
|
||||||
|
// * The button is pressed a second time within doubleTime ms AND held again for at least singleTime ms, in which case
|
||||||
|
// a DoublePress will be triggered. No further events will occur until the button is released.
|
||||||
|
// * If singleTime>longTime, only Long Press triggers can occur.
|
||||||
|
// * If doubleTime=0, Double Presses cannot occur.
|
||||||
|
// * Once triggered() returns true, if will subsequently return false until there is a new trigger event.
|
||||||
|
|
||||||
boolean primed();
|
boolean primed();
|
||||||
|
|
||||||
// Returns true if button has been pressed and held for greater than shortTime, but has not yet been released.
|
// Returns true if button has been pressed and held for greater than singleTime, but has not yet been released.
|
||||||
// After returning true, subsequent calls will always return false until the button has been released and reset.
|
// After returning true, subsequent calls will always return false until the button has been released and reset.
|
||||||
|
|
||||||
boolean longPress();
|
|
||||||
int type();
|
int type();
|
||||||
|
|
||||||
// Returns true if last trigger event was a Long Press, or false if last trigger was a Short Press
|
// Returns 0=Single Press, 1=Double Press, or 2=Long Press
|
||||||
|
|
||||||
void wait();
|
void wait();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue