Updated comments in Example 15 - RealPushButtons

Added description of different triggerTypes and the use of custom functions
This commit is contained in:
Gregg 2022-08-20 07:37:56 -05:00
parent a48746c2b3
commit f4698b8d59
2 changed files with 126 additions and 10 deletions

View File

@ -47,9 +47,9 @@ void setup() {
// Additionally, we want HomeKit to reflect any changes in the device as a result of such manual actions - HomeKit should know
// when the light has been turned on or off manually.
// One way to accomplish would be via custom code added to the loop() method of your derived Service that monitors the button,
// One way to accomplish would be via custom code added to the loop() method of your derived Service that monitors a pushbutton,
// checks when it is pressed, debounces button noise, performs some actions when pressed, and informs HomeKit of the actions with
// the setVal() method. Or you can use HomeSpan's built-in SpanButton() object.
// the setVal() method. Or you can simply use HomeSpan's built-in SpanButton() object.
// SpanButton() is a Service-level object, meaning it attaches itself to the last Service you define. Typically you would instantiate
// one of more SpanButton() objects directly inside the constructor for your derived Service.
@ -61,18 +61,21 @@ void setup() {
// It's fine to change this to a longer value, but a shorter value is not recommended as this may allow spurious triggers unless
// you debounce your switch with hardware.
// The SpanButton() constructor takes 4 arguments, in the following order:
// The SpanButton() constructor takes 5 arguments, in the following order:
//
// pin - the pin number to which the PushButton is attached (required)
// longTime - the minimum length of time (in milliseconds) the button needs to be pushed to be considered a LONG press (optional; default=2000 ms)
// singleTime - the minimum length of time (in milliseconds) the button needs to be pushed to be considered a SINGLE press (optional; default=5 ms)
// doubleTime - the maximum length of time (in milliseconds) between button presses to create a DOUBLE press (optional; default=200 ms)
// triggerType - the action that causes a trigger on the pin (optional; default=SpanButton::TRIGGER_ON_LOW). Built-in choices include:
//
// SpanButton::TRIGGER_ON_LOW: used for a button that connects pin to GROUND
// SpanButton::TRIGGER_ON_HIGH: used for a button that connects pin to VCC (typically +3.3V)
// SpanButton::TRIGGER_ON_TOUCH: used when a pin is connected to a touch pad/sensor
// When a SpanButton() is instantiated, it sets the specified pin on the ESP32 to be an INPUT with PULL-UP, meaning that the pin will
// normally return a value of HIGH when read. Your actual PushButton should be connected so that this pin is GROUNDED when the button
// is pressed.
// When a SpanButton() is first instantiated, HomeSpan configures the specified pin in accordance with the triggerType chosen.
// HomeSpan automatically polls all pins with associated SpanButton() objects and checks for LOW values, which indicates the button was
// Then, HomeSpan continuously polls all pins with associated SpanButton() objects and checks for triggers, which indicates the button was
// pressed, but not yet released. It then starts a timer. If the button is released after being pressed for less than singleTime milliseconds,
// nothing happens. If the button is released after being pressed for more than singleTime milliseconds, but for less than longTime milliseconds,
// a SINGLE press is triggered, unless you press once again within doubleTime milliseconds to trigger a DOUBLE press. If the button is held for more
@ -150,3 +153,115 @@ void loop(){
homeSpan.poll();
} // end of loop()
//////////////// ADDITIONAL NOTES ////////////////////////
// DEFAULT VALUES AND ALTERNATIVE CONSTRUCTORS
// --------------------------------------------
// As shown in this example, the following creates a SpanButton suitable for connecting pin 23 to GROUND via a pushbutton, and uses
// SpanButton's default values for longTime, singleTime, and doubleTime:
//
// new SpanButton(23);
//
// This is exactly the same as if you explicitly set each parameter to its default value:
//
// new SpanButton(23,2000,5,200,SpanButton::TRIGGER_ON_LOW); // equivalent to above
//
// If instead you want to create a SpanButton that connects pin 23 to VCC via a pushbutton using SpanButton::TRIGGER_ON-HIGH,
// you need to explictly set all the other parameters, even if you are satisfied with their default values, since triggerType
// is the last argument in the constructor:
//
// new SpanButton(23,2000,5,200,SpanButton::TRIGGER_ON_HIGH);
//
// Because this can be cumbersome, SpanButton includes an alternative constructor where triggerType is the second paramater, instead
// of the last. In this case triggerType is required, but longTime, singleTime, and doubleTime are still optional.
//
// For example, the following creates a SpanButton suitable for connecting pin 23 to a touch pad/sensor, and uses
// SpanButton's default values for longTime, singleTime, and doubleTime:
//
// new SpanButton(23,SpanButton::TRIGGER_ON_TOUCH);
//
// which is of course equivalent to:
//
// new SpanButton(23,SpanButton::TRIGGER_ON_TOUCH,2000,5,200);
// TOUCH PAD/SENSOR CALIBRATION
// ----------------------------
// SpanButton makes use of the ESP32's internal touch sensor peripheral to monitor pins for "touches". There are a number
// of paramaters that must be specified for touches to be accurately detected, depending on the exact size and shape of your
// touch pads. Upon instantiation of a SpanButton() with triggerType=SpanButton::TRIGGER_ON_TOUCH, SpanButton will conveniently
// perform an automatic calibration that sets an appropriate threshold level for detecting touches.
//
// However, if you need to, you can override this calibration process using the following two class-level functions:
//
// SpanButton::setTouchThreshold() - explicitly sets the threshold for detecting touches (i.e. overrides the auto-calibration)
// SpanButton::setTouchCycles() - explicitly sets the measurement and sleep times used by the ESP32's internal touch peripheral
//
// See the SpanButton secion of the Reference API for details on how to use these optional functions.
// THE triggerType FUNCTION
// -------------------------
// Though the three triggerType objects supported by SpanButton (SpanButton::TRIGGER_ON_LOW, etc.) may appear to be nothing more than
// constants, they are actually boolean functions that each accept a single integer argument. When SpanButton calls the triggerType function,
// it passes the pin number specified in the constructor as the integer argument, and the triggerType function returns TRUE if the
// "pushbutton" associated with the pin number is "pressed," or FALSE if it is not.
//
// For example, the definitions of SpanButton::TRIGGER_ON_LOW and SpanButton::TRIGGER_ON_HIGH are as follows:
//
// boolean TRIGGER_ON_LOW(int pinArg) { return( !digitalRead(pinArg) ); }
// boolean TRIGGER_ON_HIGH(int pinArg) { return( digitalRead(pinArg) ); }
//
// The definitions for SpanButton::TRIGGER_ON_TOUCH are more complicated since the ESP32 touch sensor library returns either a 2-byte
// or 4-byte numeric value when the state of pin configured as a touch sensor is read, rather than a simple 0 or 1. The triggerType
// function must therefore compare the value read from the touch sensor pin to some pre-computed "threshold" to determine whether or not
// the touch pad has in fact been touched. This is the threshold value that HomeSpan auto-calibrates for you as described above.
//
// Making things even more complex is that the ESP32 touch pins work in the reverse direction as touch pins on the ESP32-S2 and ESP32-S3.
// On the former, the values read from a touch sensor DECREASE when the touch pad is touched. On the latter, the values increase when the
// touch pad is touched. This means that for ESP32 devices, HomeSpan uses the following definition for SpanButton::TRIGGER_ON_TOUCH:
//
// boolean TRIGGER_ON_TOUCH(int pinArg) { return ( touchRead(pinArg) < threshold ); }
//
// whereas on ESP32-S2 and ESP32-S3 devices, HomeSpan uses a definition that flips the direction of the comparison:
//
// boolean TRIGGER_ON_TOUCH(int pinArg) { return ( touchRead(pinArg) > threshold ); }
//
// For ESP32-C3 devices, HomeSpan does not define TRIGGER_ON_TOUCH at all since there are no touch pins on an ESP32-C3 device! The compiler
// will throw an error if you try to create a SpanButton with triggerType=SpanButton::TRIGGER_ON_TOUCH, or if you call either of the
// calibration functions above.
//
// CREATING YOUR OWN triggerType FUNCTION
// --------------------------------------
// You are not limited to choosing among HomeSpan's three built-in triggerType functions. You can instead create your own triggerType function
// and pass it to SpanButton as the triggerType parameter in the SpanButton constructor. Your function must be of the form `boolean func(int)`,
// and should return TRUE if the "pushbutton" associated with the pin number that HomeSpan passes to your function as the integer argument
// has been "pressed", or FALSE if it has not. This allows you to expand the used of SpanButton to work with pin multiplexers, pin extenders,
// or any device that may require custom handling via a third-party library.
//
// For example, if you were using an MCP I/O Port Expander with the Adafruit mcp library, you could create a triggerType function for a pin
// on the MCP device that is connected to ground through a pushbutton as such:
//
// boolean MCP_READ(int mcpPin) { return ( !mcp.digitalRead(mcpPin); ) }
//
// And then simply pass MCP_READ to SpanButton as the triggerType parameter using any of the SpanButton constuctors:
//
// new SpanButton(23,MCP_READ); // uses default longTime, singleTime, and doubleTime
// new SpanButton(23,MCP_READ,2000,5,200); // expliclty sets longTime, singleTime, and doubletime
// new SpanButton(23,2000,5,200,MCP_READ); // alternative constructor with arguments in a different order
//
// Alternatively, you can use a lambda function as the triggerType parameter, thus creating your function on the fly when instantiating a SpanButton:
//
// new SpanButton(23,[](int mcpPin)->boolean{ return ( !mcp.digitalRead(mcpPin); ) }
//
// Note: If you create your own triggerType function, don't forget to perform any initialization of the "pin", or setup/configuration of a
// pin extender, etc., prior to instantiating a SpanButton that uses your custom function. HomeSpan cannot do this for you.
//

View File

@ -36,7 +36,8 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
// NEW! Below we create three SpanButton() objects. In the first we specify the pin number, as required, but allow SpanButton() to use
// its default values for a LONG press (2000 ms), a SINGLE press (5 ms), and a DOUBLE press (200 ms). In the second and third we change the
// default LONG press time to 500 ms, which works well for repeatedly increasing or decreasing the brightness.
// default LONG press time to 500 ms, which works well for repeatedly increasing or decreasing the brightness. Since we do not specify
// a triggerType, SpanButton uses the default TRIGGER_ON_TOUCH, which is suitable for a pushbutton that connects pin to GROUND when pressed.
// All of the logic for increasing/decreasing brightness, turning on/off power, and setting/resetting a favorite brightness level is found
// in the button() method below.