Button APIs

The Button class provides a simple way to read the state of a button. There are two ways to configure the functionality of the button.

The first uses Button::Config to configure the button to call a function when the button is pressed or released and uses the Interrupt class’ task and ISR for signaling. At any time, a user may also call the is_pressed method to read the current state of the button’s input pin.

The second uses Button::SimpleConfig to simply configure the button as an input with configurable pull-up or pull-down resistors and a configurable active state (high or low). In this configuration, the input is read manually any time the user calls the is_pressed method.

API Reference

Header File

Classes

class Button : protected espp::Interrupt

A class to handle a button connected to a GPIO.

This class uses the ESP-IDF GPIO interrupt handler to detect button presses and releases. It then calls the callback function with the event.

Simple Button Example (No Callback / Interrupt)

  // create the button
  espp::Button simple_button({
      .name = "Button 12",
      .gpio_num = GPIO_NUM_12,
      .active_level = espp::Interrupt::ActiveLevel::LOW,
      .pullup_enabled = false,
      .pulldown_enabled = false,
      .log_level = espp::Logger::Verbosity::WARN,
  });

  for (int i = 0; i < 10; i++) {
    logger.info("Button 12 state: {}", simple_button.is_pressed());
    std::this_thread::sleep_for(1s);
  }

Button Example (With Callback / Interrupt)

  static auto start = std::chrono::high_resolution_clock::now();
  std::string button_topic = "button/state";
  std::string button_component_name = "button";

  // create a button
  espp::Button button({
      .name = "Button 12",
      .interrupt_config =
          {
              .gpio_num = GPIO_NUM_12,
              .callback =
                  [&](const espp::Interrupt::Event &event) {
                    auto now = std::chrono::high_resolution_clock::now();
                    auto elapsed = std::chrono::duration<float>(now - start).count();
                    logger.info("[Callback][{:.3f}] Button {} state changed to: {}", elapsed,
                                event.gpio_num, event.active);
                    // serialize the event
                    std::error_code ec;
                    std::vector<uint8_t> buffer;
                    auto bytes_written = espp::serialize(event, buffer);
                    if (bytes_written > 0) {
                      // publish the event
                      espp::EventManager::get().publish(button_topic, buffer);
                    } else {
                      logger.error("Failed to serialize button state");
                    }
                  },
              .active_level = espp::Interrupt::ActiveLevel::LOW,
              .interrupt_type = espp::Interrupt::Type::ANY_EDGE,
              .pullup_enabled = false,
              .pulldown_enabled = false,
          },
      .task_config =
          {
              .name = "Button 12 task",
              .stack_size_bytes = 8192,
              .priority = 5,
          },
      .log_level = espp::Logger::Verbosity::WARN,
  });

  logger.info("Initial button state: {}", button.is_pressed());

  // register subscriber on the button topic
  auto &em = espp::EventManager::get();
  auto did_sub =
      em.add_subscriber(button_topic, "example subscriber", [&](const std::vector<uint8_t> &data) {
        auto now = std::chrono::high_resolution_clock::now();
        auto elapsed = std::chrono::duration<float>(now - start).count();
        // deserialize the data
        std::error_code ec;
        auto state = espp::deserialize<espp::Interrupt::Event>(data, ec);
        if (!ec) {
          logger.info("[Subscriber][{:.3f}]: button {} state changed to: {}", elapsed,
                      state.gpio_num, state.active);
        } else {
          logger.error("Failed to deserialize button state: {}", ec.message());
        }
      });
  logger.info("Subscribed: {}", did_sub);

  // create another button
  espp::Button button_2({
      .name = "Button 0",
      .interrupt_config =
          {
              .gpio_num = GPIO_NUM_0,
              .callback =
                  [&](const espp::Interrupt::Event &event) {
                    logger.info("Button {} state changed to: {}", event.gpio_num, event.active);
                  },
              .active_level = espp::Interrupt::ActiveLevel::LOW,
              .interrupt_type = espp::Interrupt::Type::ANY_EDGE,
              .pullup_enabled = false,
              .pulldown_enabled = false,
              .filter_type = espp::Interrupt::FilterType::PIN_GLITCH_FILTER,
          },
      .task_config =
          {
              .name = "Button 0 task",
              .stack_size_bytes = 8192,
              .priority = 5,
          },
      .log_level = espp::Logger::Verbosity::WARN,
  });

  while (true) {
    std::this_thread::sleep_for(1s);
  }

Public Types

using Event = Interrupt::Event

The event type for the button.

using InterruptType = Interrupt::Type

The type of interrupt for the button.

using ActiveLevel = Interrupt::ActiveLevel

The active level of the button.

using callback_t = Interrupt::event_callback_fn

The callback function type for the button.

Public Functions

inline explicit Button(const Config &config)

Construct a button.

This constructor is useful for buttons that require a custom task or interrupt configuration and need to register a callback function.

Parameters

config – The configuration for the button

inline explicit Button(const SimpleConfig &config)

Construct a button with a simple configuration.

This constructor is useful for simple buttons that don’t require a custom task or interrupt configuration and do not need to register a callback function.

Parameters

config – The simple configuration for the button

inline bool is_pressed() const

Whether the button is currently pressed.

Returns

True if the button is pressed, false otherwise

Protected Types

enum class Type

The type of interrupt to use for the GPIO.

Values:

enumerator ANY_EDGE

Interrupt on any edge.

enumerator RISING_EDGE

Interrupt on rising edge.

enumerator FALLING_EDGE

Interrupt on falling edge.

enumerator LOW_LEVEL

Interrupt on low level.

enumerator HIGH_LEVEL

Interrupt on high level.

typedef std::function<void(const Event&)> event_callback_fn

The callback for the event.

Protected Functions

inline size_t get_min_queue_size() const

Get the minimum number of free spaces in the queue.

This will return the minimum number of free spaces in the queue Over the lifetime of the object. This can be used to determine if the queue size is too small for the number of interrupts that are being received. It may also help indicate if the interrupt task priority is too low, preventing the queue from being serviced. Finally, it may also help to indicate if additional filtering may be needed on the interrupt line (either using the FilterType or with hardware filtering).

Returns

The minimum number of free spaces in the queue

inline void add_interrupt(const PinConfig &interrupt)

Add an interrupt to the interrupt handler.

Parameters

interrupt – The interrupt to add

inline bool is_active(const PinConfig &interrupt) const

Get the state of the interrupt.

This will check the raw logic level of the GPIO and return whether the interrupt is active or not according to the active level that was set in the configuration.

Parameters

interrupt – The interrupt to check

Returns

Whether the interrupt is active

inline std::vector<std::pair<int, bool>> get_active_states()

Get the state of all the interrupts.

Returns

A vector of the states of the interrupts as pairs of the GPIO number and whether the interrupt is active

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters

rate_limit – The rate limit to use for the logger

struct Config

The configuration for the button.

Public Members

std::string_view name = {"Button"}

Name of the button.

int isr_core_id = -1

The core ID to run the interrupt service routine on.

Interrupt::PinConfig interrupt_config

Configuration for the GPIO interrupt.

Task::BaseConfig task_config = {}

Configuration for the button task.

espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN

Log level for this class.

struct SimpleConfig

The simple configuration for the button.

This is a simplified configuration for the button that only requires the GPIO number and the active level of the button. This is useful for simple buttons that don’t require a custom task or interrupt configuration and do not need to register a callback function.

Public Members

std::string_view name = {"Button"}

Name of the button.

gpio_num_t gpio_num

The GPIO number for the button.

ActiveLevel active_level = ActiveLevel::LOW

The active level of the button.

bool pullup_enabled = true

Whether to enable the internal pullup resistor for the button

bool pulldown_enabled = false

Whether to enable the internal pulldown resistor for the button

espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN

Log level for this class.