Files
garagesensor/lib/HomieNodes/ButtonNode.cpp
2020-04-08 22:44:37 +02:00

140 lines
3.2 KiB
C++

/*
* ButtonNode.cpp
* Homie Node for a button with optional callback function
*
* Version: 1.0
* Author: Lübbe Onken (http://github.com/luebbe)
*/
#include "ButtonNode.hpp"
ButtonNode::ButtonNode(const char *name,
const int buttonPin,
TButtonPressCallback buttonPressCallback,
TButtonChangeCallback buttonChangeCallback)
: HomieNode(name, "ButtonNode", "sensor")
{
_buttonPin = buttonPin;
_buttonPressCallback = buttonPressCallback;
_buttonChangeCallback = buttonChangeCallback;
}
void ButtonNode::handleButtonPress(unsigned long dt)
{
if (Homie.isConnected())
{
setProperty("duration").send(String(dt));
}
printCaption();
Homie.getLogger() << cIndent << "pressed: " << dt << " ms" << endl;
if (_buttonPressCallback)
{
_buttonPressCallback();
}
}
void ButtonNode::handleButtonChange(bool down) {
if (Homie.isConnected())
{
setProperty("down").send(down ? "true" : "false");
}
printCaption();
Homie.getLogger() << cIndent << (down ? "down" : "up") << endl;
if (_buttonChangeCallback)
{
_buttonChangeCallback(down);
}
}
void ButtonNode::onPress(TButtonPressCallback buttonCallback)
{
_buttonPressCallback = buttonCallback;
}
void ButtonNode::onChange(TButtonChangeCallback buttonCallback)
{
_buttonChangeCallback = buttonCallback;
}
void ButtonNode::setMinButtonDownTime(unsigned short downTime)
{
_minButtonDownTime = downTime;
}
void ButtonNode::setMaxButtonDownTime(unsigned short downTime)
{
_maxButtonDownTime = downTime;
}
void ButtonNode::printCaption()
{
Homie.getLogger() << cCaption << endl;
}
void ButtonNode::loop()
{
// Detect a single press between 90ms and 900ms
// This could be improved to detect multiple quick or long presses
// and:
// a) report them via MQTT
// b) react by calling different callbacks
if (_buttonPin > DEFAULTPIN)
{
byte reading = digitalRead(_buttonPin);
if (reading != _lastReading) {
// reset the debouncing timer
_lastDebounceTime = millis();
}
if ((millis() - _lastDebounceTime) > _minButtonDownTime) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
if (reading != _buttonState)
{
_buttonState = reading;
if (_buttonState == LOW)
{
handleButtonChange(true);
_buttonChangeHandled = true;
_buttonDownTime = millis();
_buttonPressHandled = false;
}
else
{
handleButtonChange(false);
_buttonChangeHandled = true;
unsigned long dt = millis() - _buttonDownTime;
if (dt >= _minButtonDownTime && dt <= _maxButtonDownTime && !_buttonPressHandled)
{
handleButtonPress(dt);
_buttonPressHandled = true;
}
}
}
}
_lastReading = reading;
}
}
void ButtonNode::setup()
{
advertise("down").setDatatype("boolean");
advertise("duration").setDatatype("integer").setUnit("ms");
printCaption();
Homie.getLogger() << cIndent << "Pin: " << _buttonPin << endl;
if (_buttonPin > DEFAULTPIN)
{
pinMode(_buttonPin, INPUT_PULLUP);
}
}