Updated with reed relais and debouncing button
This commit is contained in:
57
include/Heartbeater.hpp
Normal file
57
include/Heartbeater.hpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class Heartbeater
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int _pin;
|
||||||
|
uint8_t _onState;
|
||||||
|
uint8_t _ledState;
|
||||||
|
uint8_t _inBeatCount;
|
||||||
|
unsigned long _beatInterval;
|
||||||
|
unsigned long _onInterval = 30;
|
||||||
|
unsigned long _offInterval = 150;
|
||||||
|
unsigned long _inBeatInterval = 0;
|
||||||
|
unsigned long _lastBeat;
|
||||||
|
unsigned long _lastInBeat;
|
||||||
|
unsigned long _beatCount = 0;
|
||||||
|
public:
|
||||||
|
explicit Heartbeater(const int pin, uint8_t onState = HIGH, unsigned long beatIntervalMillis = 2000UL)
|
||||||
|
: _pin(pin), _onState(onState), _beatInterval(beatIntervalMillis)
|
||||||
|
{
|
||||||
|
_ledState = !_onState;
|
||||||
|
pinMode(_pin, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
digitalWrite(_pin, _ledState); // each iteration of loop() will set the IO pins, even if they don't change, that's okay
|
||||||
|
|
||||||
|
// Toggle back and forth between the two LEDs
|
||||||
|
if ((millis() - _lastBeat) >= _beatInterval)
|
||||||
|
{
|
||||||
|
// time is up!
|
||||||
|
_inBeatCount = 0;
|
||||||
|
_lastBeat += _beatInterval;
|
||||||
|
_beatCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the heartbeat effect
|
||||||
|
if ((millis() - _lastInBeat) >= _inBeatInterval)
|
||||||
|
{
|
||||||
|
_lastInBeat = millis();
|
||||||
|
if (_inBeatCount < 2)
|
||||||
|
{
|
||||||
|
_ledState = !_ledState;
|
||||||
|
if (_ledState == _onState) {
|
||||||
|
_inBeatInterval = _onInterval;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_inBeatCount++;
|
||||||
|
_inBeatInterval = _offInterval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
139
lib/HomieNodes/ButtonNode.cpp
Normal file
139
lib/HomieNodes/ButtonNode.cpp
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
52
lib/HomieNodes/ButtonNode.hpp
Normal file
52
lib/HomieNodes/ButtonNode.hpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* ButtonNode.hpp
|
||||||
|
* Homie Node for a button with optional callback function
|
||||||
|
*
|
||||||
|
* Version: 1.0
|
||||||
|
* Author: Lübbe Onken (http://github.com/luebbe)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Homie.hpp>
|
||||||
|
|
||||||
|
#define DEFAULTPIN -1
|
||||||
|
|
||||||
|
class ButtonNode : public HomieNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::function<void(void)> TButtonPressCallback;
|
||||||
|
typedef std::function<void(bool)> TButtonChangeCallback;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char *cCaption = "• Button:";
|
||||||
|
const char *cIndent = " ◦ ";
|
||||||
|
|
||||||
|
TButtonPressCallback _buttonPressCallback;
|
||||||
|
TButtonChangeCallback _buttonChangeCallback;
|
||||||
|
int _buttonPin;
|
||||||
|
byte _lastReading = HIGH;
|
||||||
|
byte _buttonState = HIGH;
|
||||||
|
bool _buttonPressHandled = 0;
|
||||||
|
bool _buttonChangeHandled = 0;
|
||||||
|
unsigned long _buttonDownTime = 0;
|
||||||
|
unsigned long _minButtonDownTime = 90;
|
||||||
|
unsigned long _maxButtonDownTime = 2000;
|
||||||
|
unsigned long _lastDebounceTime = 0; // the last time the button pin was toggled
|
||||||
|
|
||||||
|
void handleButtonPress(unsigned long dt);
|
||||||
|
void handleButtonChange(bool down);
|
||||||
|
void printCaption();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void loop() override;
|
||||||
|
virtual void setup() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ButtonNode(const char *name, const int buttonPin = DEFAULTPIN, TButtonPressCallback buttonPressedCallback = NULL, TButtonChangeCallback buttonChangedCallback = NULL);
|
||||||
|
void onPress(TButtonPressCallback buttonCallback);
|
||||||
|
void onChange(TButtonChangeCallback buttonCallback);
|
||||||
|
void setMinButtonDownTime(unsigned short downTime);
|
||||||
|
void setMaxButtonDownTime(unsigned short downTime);
|
||||||
|
};
|
||||||
111
lib/HomieNodes/ContactNode.cpp
Normal file
111
lib/HomieNodes/ContactNode.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* ContactNode.cpp
|
||||||
|
* Homie Node for a Contact switch
|
||||||
|
*
|
||||||
|
* Version: 1.0
|
||||||
|
* Author: Lübbe Onken (http://github.com/luebbe)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ContactNode.hpp"
|
||||||
|
|
||||||
|
ContactNode::ContactNode(const char *name,
|
||||||
|
const int contactPin,
|
||||||
|
TContactCallback contactCallback)
|
||||||
|
: HomieNode(name, "ContactNode", "sensor")
|
||||||
|
{
|
||||||
|
_contactPin = contactPin;
|
||||||
|
_contactCallback = contactCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ContactNode::getContactPin()
|
||||||
|
{
|
||||||
|
return _contactPin;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte ContactNode::readPin()
|
||||||
|
{
|
||||||
|
return digitalRead(_contactPin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debounce input pin.
|
||||||
|
bool ContactNode::debouncePin(void)
|
||||||
|
{
|
||||||
|
byte inputState = readPin();
|
||||||
|
if (inputState != _lastInputState)
|
||||||
|
{
|
||||||
|
_stateChangedTime = millis();
|
||||||
|
_stateChangeHandled = false;
|
||||||
|
_lastInputState = inputState;
|
||||||
|
#ifdef DEBUG
|
||||||
|
Homie.getLogger() << "State Changed to " << inputState << endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned long dt = millis() - _stateChangedTime;
|
||||||
|
if (dt >= DEBOUNCE_TIME && !_stateChangeHandled)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
Homie.getLogger() << "State Stable for " << dt << "ms" << endl;
|
||||||
|
#endif
|
||||||
|
_stateChangeHandled = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContactNode::handleStateChange(bool open)
|
||||||
|
{
|
||||||
|
if (Homie.isConnected())
|
||||||
|
{
|
||||||
|
setProperty("open").send(open ? "true" : "false");
|
||||||
|
}
|
||||||
|
if (_contactCallback)
|
||||||
|
{
|
||||||
|
_contactCallback(open);
|
||||||
|
}
|
||||||
|
|
||||||
|
printCaption();
|
||||||
|
Homie.getLogger() << cIndent << "is " << (open ? "open" : "closed") << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContactNode::onChange(TContactCallback contactCallback)
|
||||||
|
{
|
||||||
|
_contactCallback = contactCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContactNode::printCaption()
|
||||||
|
{
|
||||||
|
Homie.getLogger() << cCaption << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContactNode::loop()
|
||||||
|
{
|
||||||
|
if (_contactPin > DEFAULTPIN)
|
||||||
|
{
|
||||||
|
if (debouncePin() && (_lastSentState != _lastInputState))
|
||||||
|
{
|
||||||
|
handleStateChange(_lastInputState == HIGH);
|
||||||
|
_lastSentState = _lastInputState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContactNode::setupPin()
|
||||||
|
{
|
||||||
|
pinMode(_contactPin, INPUT_PULLUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContactNode::setup()
|
||||||
|
{
|
||||||
|
advertise("open");
|
||||||
|
|
||||||
|
printCaption();
|
||||||
|
Homie.getLogger() << cIndent << "Pin: " << _contactPin << endl;
|
||||||
|
|
||||||
|
if (_contactPin > DEFAULTPIN)
|
||||||
|
{
|
||||||
|
setupPin();
|
||||||
|
}
|
||||||
|
}
|
||||||
47
lib/HomieNodes/ContactNode.hpp
Normal file
47
lib/HomieNodes/ContactNode.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* ContactNode.hpp
|
||||||
|
* Homie Node for a Contact switch
|
||||||
|
*
|
||||||
|
* Version: 1.0
|
||||||
|
* Author: Lübbe Onken (http://github.com/luebbe)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Homie.hpp>
|
||||||
|
|
||||||
|
#define DEFAULTPIN -1
|
||||||
|
#define DEBOUNCE_TIME 200
|
||||||
|
|
||||||
|
class ContactNode : public HomieNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::function<void(bool)> TContactCallback;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char *cCaption = "• Contact:";
|
||||||
|
const char *cIndent = " ◦ ";
|
||||||
|
|
||||||
|
TContactCallback _contactCallback;
|
||||||
|
int _contactPin;
|
||||||
|
// Use invalid values for last states to force sending initial state...
|
||||||
|
int _lastInputState = -1; // Input pin state.
|
||||||
|
int _lastSentState = -1; // Last pin state sent
|
||||||
|
bool _stateChangeHandled = false;
|
||||||
|
unsigned long _stateChangedTime = 0;
|
||||||
|
|
||||||
|
bool debouncePin(void);
|
||||||
|
void handleStateChange(bool open);
|
||||||
|
void printCaption();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int getContactPin();
|
||||||
|
virtual void loop() override;
|
||||||
|
virtual void setup() override;
|
||||||
|
virtual void setupPin();
|
||||||
|
virtual byte readPin();
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ContactNode(const char *name, const int contactPin = DEFAULTPIN, TContactCallback contactCallback = NULL);
|
||||||
|
void onChange(TContactCallback contactCallback);
|
||||||
|
};
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
/*
|
|
||||||
* BME280Node.cpp
|
|
||||||
* Homie Node for BME280 sensors using Adafruit BME280 library.
|
|
||||||
*
|
|
||||||
* Version: 1.1
|
|
||||||
* Author: Lübbe Onken (http://github.com/luebbe)
|
|
||||||
* Author: Markus Haack (http://github.com/mhaack)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "PingNode.hpp"
|
|
||||||
#include <Homie.h>
|
|
||||||
|
|
||||||
bool checkBounds(float value, float min, float max) {
|
|
||||||
return !isnan(value) && value >= min && value <= max;
|
|
||||||
}
|
|
||||||
|
|
||||||
PingNode::PingNode(const char *name, const int triggerPin, const int echoPin,
|
|
||||||
const int measurementInterval, const int publishInterval)
|
|
||||||
: SensorNode(name, "RCW-0001"),
|
|
||||||
_triggerPin(triggerPin), _echoPin(echoPin),_lastMeasurement(0), _lastPublish(0)
|
|
||||||
{
|
|
||||||
_measurementInterval = (measurementInterval > MIN_INTERVAL) ? measurementInterval : MIN_INTERVAL;
|
|
||||||
_publishInterval = (publishInterval > int(_measurementInterval)) ? publishInterval : _measurementInterval;
|
|
||||||
setMicrosecondsToMetersFactor(20);
|
|
||||||
|
|
||||||
if (_triggerPin > DEFAULTPIN && _echoPin > DEFAULTPIN) {
|
|
||||||
sonar = new NewPing(_triggerPin,_echoPin,cMaxDistance*100.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
advertise(cDistanceTopic)
|
|
||||||
.setDatatype("float")
|
|
||||||
.setFormat("0:3")
|
|
||||||
.setUnit(cUnitMeter);
|
|
||||||
advertise(cPingTopic)
|
|
||||||
.setDatatype("float")
|
|
||||||
.setUnit(cUnitMicrosecond);
|
|
||||||
advertise(cStatusTopic)
|
|
||||||
.setDatatype("enum")
|
|
||||||
.setFormat("error, ok");
|
|
||||||
advertise(cChangedTopic)
|
|
||||||
.setName("Obstacle changed")
|
|
||||||
.setDatatype("boolean");
|
|
||||||
}
|
|
||||||
|
|
||||||
void PingNode::printCaption()
|
|
||||||
{
|
|
||||||
Homie.getLogger() << cCaption << " triggerpin[" << _triggerPin << "], echopin[" << _echoPin << "]:" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PingNode::send()
|
|
||||||
{
|
|
||||||
printCaption();
|
|
||||||
Homie.getLogger() << cIndent << "Ping: " << _ping_us << " " << cUnitMicrosecond << endl;
|
|
||||||
Homie.getLogger() << cIndent << "Distance: " << _distance << " " << cUnitMeter << endl;
|
|
||||||
bool valid = _distance > 0;
|
|
||||||
Homie.getLogger() << cIndent << "Status: " << (valid ? "ok" : "error") << endl;
|
|
||||||
bool changed = signalChange(_distance, _lastDistance);
|
|
||||||
Homie.getLogger() << cIndent << "Changed: " << (changed ? "true" : "false") << " " << endl;
|
|
||||||
if (Homie.isConnected())
|
|
||||||
{
|
|
||||||
setProperty(cStatusTopic).send(valid ? "ok" : "error");
|
|
||||||
if (valid) {
|
|
||||||
setProperty(cDistanceTopic).send(String(_distance));
|
|
||||||
setProperty(cPingTopic).send(String(_ping_us));
|
|
||||||
setProperty(cChangedTopic).send(changed ? "true": "false");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
_changeHandler();
|
|
||||||
}
|
|
||||||
if (valid) {
|
|
||||||
_lastDistance = _distance;
|
|
||||||
_distance = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void PingNode::loop()
|
|
||||||
{
|
|
||||||
if (sonar) {
|
|
||||||
if (millis() - _lastMeasurement >= _measurementInterval * 1000UL || _lastMeasurement == 0)
|
|
||||||
{
|
|
||||||
float ping_us = sonar->ping_median();
|
|
||||||
// Calculating the distance @ 10 °C from d = t_ping /2 * c => t_ping /2 * 337 [m/s] => t_ping_us / 1e-6 * 1/2 * 337
|
|
||||||
float newDistance = ping_us*_microseconds2meter;
|
|
||||||
fixRange(&newDistance, cMinDistance, cMaxDistance);
|
|
||||||
if (newDistance > 0) {
|
|
||||||
_ping_us = ping_us;
|
|
||||||
_distance = newDistance;
|
|
||||||
}
|
|
||||||
_lastMeasurement = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (millis() - _lastPublish >= _publishInterval * 1000UL || _lastPublish == 0)
|
|
||||||
if (_distance > 0) {
|
|
||||||
send();
|
|
||||||
_lastPublish = millis();
|
|
||||||
_distance = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PingNode::onReadyToOperate()
|
|
||||||
{
|
|
||||||
if (Homie.isConnected())
|
|
||||||
{
|
|
||||||
setProperty(cStatusTopic).send("ok");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void PingNode::setup()
|
|
||||||
{
|
|
||||||
printCaption();
|
|
||||||
Homie.getLogger() << cIndent << "Reading interval: " << _measurementInterval << " s" << endl;
|
|
||||||
Homie.getLogger() << cIndent << "Publish interval: " << _publishInterval << " s" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PingNode::setMicrosecondsToMetersFactor(float temperatureCelcius)
|
|
||||||
{
|
|
||||||
//float soundSpeed = 337.0; // @ 10°C
|
|
||||||
float soundSpeed = 331.4 + 0.6*temperatureCelcius;
|
|
||||||
printCaption();
|
|
||||||
Homie.getLogger() << cIndent
|
|
||||||
<< "SpeedOfSound: " << soundSpeed << " " << cUnitMetersPerSecond
|
|
||||||
<< " at " << temperatureCelcius << " " << cUnitDegrees << endl;
|
|
||||||
// Calculating the distance from d = t_ping /2 * c => t_ping /2 * 337 [m/s] => t_ping_us / 1e-6 * 1/2 * 337
|
|
||||||
_microseconds2meter = 0.5e-6 * soundSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
float PingNode::getRawEchoTime() {
|
|
||||||
// Clears the trigPin
|
|
||||||
digitalWrite(_triggerPin, LOW);
|
|
||||||
delayMicroseconds(2);
|
|
||||||
|
|
||||||
// Sets the trigPin on HIGH state for 10 micro seconds
|
|
||||||
digitalWrite(_triggerPin, HIGH);
|
|
||||||
delayMicroseconds(10);
|
|
||||||
digitalWrite(_triggerPin, LOW);
|
|
||||||
|
|
||||||
// Reads the echoPin, returns the sound wave travel time in microseconds
|
|
||||||
return pulseIn(_echoPin, HIGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PingNode::signalChange(float distance, float lastDistance) {
|
|
||||||
return fabs(distance - lastDistance) > cMinimumChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
PingNode& PingNode::setChangeHandler(const ChangeHandler& changeHandler) {
|
|
||||||
_changeHandler = changeHandler;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* BME280Node.h
|
|
||||||
* Homie Node for BME280 sensors using Adafruit BME280 library.
|
|
||||||
*
|
|
||||||
* Version: 1.1
|
|
||||||
* Author: Lübbe Onken (http://github.com/luebbe)
|
|
||||||
* Author: Markus Haack (http://github.com/mhaack)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "NewPing.h"
|
|
||||||
|
|
||||||
#include "SensorNode.hpp"
|
|
||||||
#include "constants.hpp"
|
|
||||||
|
|
||||||
#define DEFAULTPIN -1
|
|
||||||
|
|
||||||
class PingNode : public SensorNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::function<void()> ChangeHandler;
|
|
||||||
private:
|
|
||||||
const float cMinDistance = 0.0;
|
|
||||||
const float cMaxDistance = 3.0;
|
|
||||||
const float cMinimumChange = 0.2;
|
|
||||||
|
|
||||||
static const int MIN_INTERVAL = 1; // in seconds
|
|
||||||
const char *cCaption = "• RCW-0001 sensor";
|
|
||||||
const char *cIndent = " ◦ ";
|
|
||||||
|
|
||||||
int _triggerPin;
|
|
||||||
int _echoPin;
|
|
||||||
float _microseconds2meter;
|
|
||||||
|
|
||||||
unsigned long _measurementInterval;
|
|
||||||
unsigned long _lastMeasurement;
|
|
||||||
unsigned long _publishInterval;
|
|
||||||
unsigned long _lastPublish;
|
|
||||||
|
|
||||||
NewPing* sonar;
|
|
||||||
float _distance = NAN;
|
|
||||||
int _ping_us = 0;
|
|
||||||
float _lastDistance = 0;
|
|
||||||
ChangeHandler _changeHandler = [](){};
|
|
||||||
|
|
||||||
float getRawEchoTime();
|
|
||||||
void setMicrosecondsToMetersFactor(float temperatureCelcius);
|
|
||||||
bool signalChange(float distance, float lastDistance);
|
|
||||||
void printCaption();
|
|
||||||
void send();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void setup() override;
|
|
||||||
virtual void loop() override;
|
|
||||||
virtual void onReadyToOperate() override;
|
|
||||||
static const int DEFAULT_MEASUREMENT_INTERVAL = 1;
|
|
||||||
static const int DEFAULT_PUBLISH_INTERVAL = 5;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit PingNode(const char *name,
|
|
||||||
const int triggerPin = DEFAULTPIN,
|
|
||||||
const int echoPin = DEFAULTPIN,
|
|
||||||
const int measurementInterval = DEFAULT_MEASUREMENT_INTERVAL,
|
|
||||||
const int publishInterval = DEFAULT_PUBLISH_INTERVAL);
|
|
||||||
|
|
||||||
float getDistance() const { return _distance; }
|
|
||||||
void setTemperature(float temperatureCelcius) { setMicrosecondsToMetersFactor(temperatureCelcius); }
|
|
||||||
PingNode& setChangeHandler(const ChangeHandler& changeHandler);
|
|
||||||
};
|
|
||||||
@@ -15,7 +15,6 @@ framework = arduino
|
|||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
lib_deps =
|
lib_deps =
|
||||||
NewPing
|
|
||||||
Homie
|
Homie
|
||||||
DHT sensor library
|
DHT sensor library
|
||||||
Adafruit Unified Sensor
|
Adafruit Unified Sensor
|
||||||
|
|||||||
80
src/main.cpp
80
src/main.cpp
@@ -1,44 +1,48 @@
|
|||||||
#include <Homie.h>
|
#include <Homie.h>
|
||||||
|
|
||||||
#include "PingNode.hpp"
|
#include "RelayNode.hpp"
|
||||||
//#include "RelayNode.hpp"
|
|
||||||
#include "DHT22Node.hpp"
|
#include "DHT22Node.hpp"
|
||||||
|
#include "ButtonNode.hpp"
|
||||||
#define TURN_ON LOW
|
#include "ContactNode.hpp"
|
||||||
#define TURN_OFF HIGH
|
#include "Heartbeater.hpp"
|
||||||
|
// #include "PingNode.hpp"
|
||||||
const int trigPin = D1;
|
//const int trigPin = D1;
|
||||||
const int echoPin = D2;
|
//const int echoPin = D2;
|
||||||
const int relayPin = D5;
|
const int relayPin = D1;
|
||||||
|
const int contactPin = D2;
|
||||||
|
const int buttonPin = D5;
|
||||||
const int dhtPin = D7; ;
|
const int dhtPin = D7; ;
|
||||||
const int ledPin = LED_BUILTIN;
|
const int ledPin = LED_BUILTIN;
|
||||||
|
const int heartbeatPin = LED_BUILTIN;
|
||||||
|
|
||||||
unsigned long HEARTBEAT_INTERVAL = 5;
|
|
||||||
unsigned long lastHeartbeat = 0;
|
|
||||||
unsigned long TEMPERATURE_INTERVAL = 120;
|
unsigned long TEMPERATURE_INTERVAL = 120;
|
||||||
unsigned long lastTemperatureUpdate = 0;
|
unsigned long lastTemperatureUpdate = 0;
|
||||||
|
bool relayInverse = true;
|
||||||
|
|
||||||
|
//PingNode obstacleNode("obstacle",trigPin,echoPin);
|
||||||
PingNode obstacleNode("obstacle",trigPin,echoPin);
|
|
||||||
DHT22Node airNode("air",dhtPin,TEMPERATURE_INTERVAL);
|
DHT22Node airNode("air",dhtPin,TEMPERATURE_INTERVAL);
|
||||||
//RelayNode relayNode("relay",relayPin,ledPin);
|
RelayNode relayNode("relay",relayPin,ledPin,relayInverse);
|
||||||
|
ButtonNode buttonNode("button",buttonPin);
|
||||||
|
ContactNode contactNode("contact",contactPin);
|
||||||
|
Heartbeater heartbeater(heartbeatPin, heartbeatPin == LED_BUILTIN ? LOW : HIGH);
|
||||||
|
|
||||||
void signal_led(bool on = true);
|
void signal_led(bool on = true);
|
||||||
void heartbeat_led(int times = 2);
|
|
||||||
|
|
||||||
void changeHandler() {
|
void changeHandler() {
|
||||||
signal_led();
|
signal_led();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loopHandler() {
|
void buttonChangeHandler(bool down) {
|
||||||
if (millis() - lastHeartbeat > HEARTBEAT_INTERVAL * 1000UL || lastHeartbeat == 0) {
|
Homie.getLogger() << "Button changing relay to " << (down ? "on" : "off") << endl;
|
||||||
heartbeat_led();
|
relayNode.setRelay(down);
|
||||||
lastHeartbeat = millis();
|
}
|
||||||
}
|
|
||||||
if (millis() - lastTemperatureUpdate > TEMPERATURE_INTERVAL * 1000UL || lastTemperatureUpdate == 0) {
|
void loopHandler() {
|
||||||
obstacleNode.setTemperature(airNode.getTemperature());
|
heartbeater.loop();
|
||||||
lastTemperatureUpdate = millis();
|
// if (millis() - lastTemperatureUpdate > TEMPERATURE_INTERVAL * 1000UL || lastTemperatureUpdate == 0) {
|
||||||
}
|
// obstacleNode.setTemperature(airNode.getTemperature());
|
||||||
|
// lastTemperatureUpdate = millis();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
@@ -48,9 +52,10 @@ void setup() {
|
|||||||
pinMode(ledPin, OUTPUT);
|
pinMode(ledPin, OUTPUT);
|
||||||
|
|
||||||
Homie_setBrand("EtxeanIoT");
|
Homie_setBrand("EtxeanIoT");
|
||||||
Homie_setFirmware("etxean-garagesensor", "1.0.5");
|
Homie_setFirmware("etxean-garagesensor", "1.2.3");
|
||||||
Homie.setLoopFunction(loopHandler);
|
Homie.setLoopFunction(loopHandler);
|
||||||
obstacleNode.setChangeHandler(changeHandler);
|
// obstacleNode.setChangeHandler(changeHandler);
|
||||||
|
buttonNode.onChange(buttonChangeHandler);
|
||||||
Homie.setup();
|
Homie.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,25 +63,10 @@ void loop() {
|
|||||||
Homie.loop();
|
Homie.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint8_t TURN_ON = ledPin == LED_BUILTIN ? LOW : HIGH;
|
||||||
|
const uint8_t TURN_OFF = ledPin == LED_BUILTIN ? HIGH : LOW;
|
||||||
|
|
||||||
void signal_led(bool on)
|
void signal_led(bool on)
|
||||||
{
|
{
|
||||||
digitalWrite(ledPin, on ? TURN_ON : TURN_OFF);
|
digitalWrite(ledPin, on ? TURN_ON : TURN_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void heartbeat_led(int times)
|
|
||||||
{
|
|
||||||
for (int blink=0; blink<times; blink++)
|
|
||||||
{
|
|
||||||
signal_led(true);
|
|
||||||
delay(10);
|
|
||||||
signal_led(false);
|
|
||||||
delay(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void longbeat_led()
|
|
||||||
{
|
|
||||||
signal_led(true);
|
|
||||||
delay(500);
|
|
||||||
signal_led(false);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user