TF_mini_mqtt_iobroker_Tom.ino
/* This example shows how to use the TFMini module.
The nodeMCU have an build in Watchdog and therefore it is necessary,
that you delete/disable all <<Serial.print>> commands from the TFMini.cpp.
Otherwise you will run into an restart loop, because the Watchdog become
activated...
Wiring:
TFMini -> nodeMCU
SDA -> D2 -> 4 -> Tx
SCL -> D1 -> 5 -> Rx
VCC -> 5V
GND -> GND
*/
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "TFMini.h"
#include <ESP8266WiFi.h>
#include "config.h"
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include "Adafruit_BMP085.h"
//#include "helper.h"
Adafruit_BMP085 bmp;
float tempBMP180;
float pressure;
// Setup software serial port
SoftwareSerial mySerial(3, 1); // connection to TFMini
TFMini tfmini; // tfmini access
unsigned long previousMillis = 0; // access time
const long interval = 100; // interval at which to measure (milliseconds)
WiFiClient wiFiClient;
PubSubClient client(wiFiClient);
byte clientStatus, prevClientStatus = 99;
/*
-----------------S E T U P-----------------
*/
void setup() {
// Step 1: Initialize hardware serial port (serial debug port)
Serial.begin(115200);
// wait for serial port to connect. Needed for native USB port only
while (!Serial);
// Step 2: Initialize the data rate for the SoftwareSerial port
mySerial.begin(TFMINI_BAUDRATE); // default boudrate is 115200
delay(10);
// Step 3: Initialize the TF Mini sensor
tfmini.begin(&mySerial);
Serial.println ("Initializing Serial and mySerial finished");
/* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default,
would try to act as both a client and an access-point and could cause
network-issues with your other WiFi-devices on your WiFi-network. */
// Set WIFI module to STA mode
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
// Wait
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
setupOTA();
// MQTT
client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
digitalWrite(TRIGGER_PIN, LOW);
delay(2);
}
void ensureMQTTConnection (){
if (!client.connected()) {
Serial.println("Attempting MQTT connection...");
// Attempt to connect
if (MQTT_SERVER_USER_ID != "" && MQTT_SERVER_PASS != ""){
client.connect(MQTT_CLIENT_NAME, MQTT_SERVER_USER_ID, MQTT_SERVER_PASS);
}
else (client.connect(MQTT_CLIENT_NAME));
if(client.connected()){
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setupOTA(){
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_SPIFFS
type = "filesystem";
}
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
}
/*
-----------------L O O P-----------------
*/
void loop() {
// we will not use an delay...
// but we wait some short time before taking the next measurement
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last measure time
previousMillis = currentMillis;
// Take one TF Mini distance measurement
uint16_t dist = tfmini.getDistance();
uint16_t strength = tfmini.getRecentSignalStrength();
// Display the measurement
Serial.print(dist);
Serial.print(" cm Signal: ");
Serial.println(strength);
//MQWW Connectionint
ensureMQTTConnection();
static unsigned long last = millis();
if (millis() - last >= IDLE_TIME *1000) {
last = millis();
int waterlevel = tfmini.getDistance();
char cdist[16];
itoa(waterlevel ,cdist, 10);
client.publish(MQTT_TOPIC_NAME_LEVEL_CM, cdist);
}
}
}
TFMini.cpp
/*
Arduino driver for Benewake TFMini time-of-flight distance sensor.
by Peter Jansen (December 11/2017)
This code is open source software in the public domain.
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The names of the contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
*/
#include "TFMini.h"
// Constructor
TFMini::TFMini() {
// Empty constructor
}
boolean TFMini::begin(Stream* _streamPtr) {
// Store reference to stream/serial object
streamPtr = _streamPtr;
// Clear state
distance = -1;
strength = -1;
state = READY;
// Set standard output mode
setStandardOutputMode();
return true;
}
// Public: The main function to measure distance.
uint16_t TFMini::getDistance() {
int numMeasurementAttempts = 0;
while (takeMeasurement() != 0) {
numMeasurementAttempts += 1;
if (numMeasurementAttempts > TFMINI_MAX_MEASUREMENT_ATTEMPTS) {
// Serial.println ("TF Mini error: too many measurement attempts");
// Serial.println ("Last error:");
if (state == ERROR_SERIAL_NOHEADER) //Serial.println("ERROR_SERIAL_NOHEADER");
if (state == ERROR_SERIAL_BADCHECKSUM) //Serial.println("ERROR_SERIAL_BADCHECKSUM");
if (state == ERROR_SERIAL_TOOMANYTRIES) //Serial.println("ERROR_SERIAL_TOOMANYTRIES");
state = ERROR_SERIAL_TOOMANYTRIES;
distance = -1;
strength = -1;
return -1;
}
}
if (state == MEASUREMENT_OK) {
return distance;
} else {
return -1;
}
}
// Public: Return the most recent signal strength measuremenet from the TF Mini
uint16_t TFMini::getRecentSignalStrength() {
return strength;
}
// Private: Set the TF Mini into the correct measurement mode
void TFMini::setStandardOutputMode() {
// Set to "standard" output mode (this is found in the debug documents)
streamPtr->write((uint8_t)0x42);
streamPtr->write((uint8_t)0x57);
streamPtr->write((uint8_t)0x02);
streamPtr->write((uint8_t)0x00);
streamPtr->write((uint8_t)0x00);
streamPtr->write((uint8_t)0x00);
streamPtr->write((uint8_t)0x01);
streamPtr->write((uint8_t)0x06);
delay(100);
}
// Private: Handles the low-level bits of communicating with the TFMini, and detecting some communication errors.
int TFMini::takeMeasurement() {
int numCharsRead = 0;
uint8_t lastChar = 0x00;
// Step 1: Read the serial stream until we see the beginning of the TF Mini header, or we timeout reading too many characters.
while (1) {
if (streamPtr->available()) {
uint8_t curChar = streamPtr->read();
if ((lastChar == 0x59) && (curChar == 0x59)) {
// Break to begin frame
break;
} else {
// We have not seen two 0x59's in a row -- store the current character and continue reading.
lastChar = curChar;
numCharsRead += 1;
}
}
// Error detection: If we read more than X characters without finding a frame header, then it's likely there is an issue with
// the Serial connection, and we should timeout and throw an error.
if (numCharsRead > TFMINI_MAXBYTESBEFOREHEADER) {
state = ERROR_SERIAL_NOHEADER;
distance = -1;
strength = -1;
if (TFMINI_DEBUGMODE == 1)// Serial.println("ERROR: no header");
return -1;
}
}
// Step 2: Read one frame from the TFMini
uint8_t frame[TFMINI_FRAME_SIZE];
uint8_t checksum = 0x59 + 0x59;
for (int i=0; i<TFMINI_FRAME_SIZE; i++) {
// Read one character
while (!streamPtr->available()) {
// wait for a character to become available
}
frame[i] = streamPtr->read();
// Store running checksum
if (i < TFMINI_FRAME_SIZE-2) {
checksum += frame[i];
}
}
// Step 2A: Compare checksum
// Last byte in the frame is an 8-bit checksum
uint8_t checksumByte = frame[TFMINI_FRAME_SIZE-1];
if (checksum != checksumByte) {
state = ERROR_SERIAL_BADCHECKSUM;
distance = -1;
strength = -1;
if (TFMINI_DEBUGMODE == 1)// Serial.println("ERROR: bad checksum");
return -1;
}
// Step 3: Interpret frame
uint16_t dist = (frame[1] << 8) + frame[0];
uint16_t st = (frame[3] << 8) + frame[2];
uint8_t reserved = frame[4];
uint8_t originalSignalQuality = frame[5];
// Step 4: Store values
distance = dist;
strength = st;
state = MEASUREMENT_OK;
// Return success
return 0;
}
TFMini.h
/*
Arduino driver for Benewake TFMini time-of-flight distance sensor.
by Peter Jansen (December 11/2017)
This code is open source software in the public domain.
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The names of the contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
*/
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// Defines
#define TFMINI_BAUDRATE 115200
#define TFMINI_DEBUGMODE 0
// The frame size is nominally 9 characters, but we don't include the first two 0x59's marking the start of the frame
#define TFMINI_FRAME_SIZE 7
// Timeouts
#define TFMINI_MAXBYTESBEFOREHEADER 30
#define TFMINI_MAX_MEASUREMENT_ATTEMPTS 10
// States
#define READY 0
#define ERROR_SERIAL_NOHEADER 1
#define ERROR_SERIAL_BADCHECKSUM 2
#define ERROR_SERIAL_TOOMANYTRIES 3
#define MEASUREMENT_OK 10
//
// Driver Class Definition
//
class TFMini {
public:
TFMini(void);
// Configuration
boolean begin(Stream* _streamPtr);
// Data collection
uint16_t getDistance();
uint16_t getRecentSignalStrength();
private:
Stream* streamPtr;
int state;
uint16_t distance;
uint16_t strength;
// Low-level communication
void setStandardOutputMode();
int takeMeasurement();
};
config.h
#define WIFI_SSID "Yacht" //enter SSID and pass without <>
#define WIFI_PASS "Tommyland78"
#define MQTT_SERVER_IP "192.168.1.2"
#define MQTT_SERVER_PORT 1883
#define MQTT_CLIENT_NAME "Yacht_Laser_Höhenmesser"
#define MQTT_SERVER_USER_ID "Administrator" // leave quotes empty, if no authentication is required
#define MQTT_SERVER_PASS "Tommyland78"
#define MQTT_TOPIC_NAME_LEVEL_CM "Schiff/Höhenmesser/Laser"
#define TRIGGER_PIN 12 //5 //~D1
#define ECHO_PIN 14 //4 //~D2
#define SENSOR_DISTANCE_TO_MAX_VOLUME 0 // in cm - minimum is 21
#define SENSOR_OFFSET 0 // use ruler and the mqtt topic cistern/level/cm to calibrate this value
#define IDLE_TIME 1 // in seconds
#define TIME_PERIOD_BETWEEN_READINGS 10 // in seconds
#define SAMPLE_SIZE 10
/** ===============ADVANCED SETTINGS==================== **/
#define TRIGGER_PULSE_WIDTH 15 // in microseconds - adjust this setting if your sensor doesn't send the pulse
#define READING_TIMEOUT 60 // in milliseconds - max is 60ms - post-pulse time period after which the MCU gives up waiting for a return signal
Files from sketch with the laser