148 lines
4.3 KiB
C++
148 lines
4.3 KiB
C++
/*
|
|
* 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(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*0.0001685;
|
|
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;
|
|
// 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;
|
|
}
|