add seconds waterlevel sensor
This commit is contained in:
parent
feeec8ffd4
commit
6e2b02e121
11
include/ec.h
11
include/ec.h
|
@ -96,6 +96,7 @@ void ec_connectProbe(bool, uint8_t);
|
||||||
void ec_releaseRelay();
|
void ec_releaseRelay();
|
||||||
float ec_getECfromADC(float adc, float ec_calibration_polynom[], size_t len_ec_calibration_polynom, float ec_calibration_linearize_below_adc, float ec_calibration_linear_lowADC, float ec_calibration_linear_lowEC);
|
float ec_getECfromADC(float adc, float ec_calibration_polynom[], size_t len_ec_calibration_polynom, float ec_calibration_linearize_below_adc, float ec_calibration_linear_lowADC, float ec_calibration_linear_lowEC);
|
||||||
float ec_calculateEC25(float pEC,float pTemp);
|
float ec_calculateEC25(float pEC,float pTemp);
|
||||||
|
bool ec_measurementRunning();
|
||||||
|
|
||||||
void ec_setup() {
|
void ec_setup() {
|
||||||
/*
|
/*
|
||||||
|
@ -218,12 +219,17 @@ void ec_loop(unsigned long loopmillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (ec_array_pos<EC_ARRAY_SIZE) { //measurement running
|
if (ec_measurementRunning()) { //measurement running
|
||||||
if (loopmillis>last_read_ec+EC_READ_INTERVAL) { //take reading into array
|
if (loopmillis>last_read_ec+EC_READ_INTERVAL) { //take reading into array
|
||||||
last_read_ec=loopmillis;
|
last_read_ec=loopmillis;
|
||||||
|
|
||||||
if (loopmillis>ec_last_change_relay+EC_RELAY_SWITCH_SETTLETIME) { //values have settled
|
if (loopmillis>ec_last_change_relay+EC_RELAY_SWITCH_SETTLETIME) { //values have settled
|
||||||
|
Serial.print("Get ADC Reading");
|
||||||
uint16_t value = ADS.readADC(EC_ADS_CHANNEL);
|
uint16_t value = ADS.readADC(EC_ADS_CHANNEL);
|
||||||
|
Serial.print(". Write to pos ");
|
||||||
|
Serial.println(ec_array_pos);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ec_array[ec_array_pos]=value;
|
ec_array[ec_array_pos]=value;
|
||||||
|
|
||||||
|
@ -326,5 +332,8 @@ float ec_calculateEC25(float pEC,float pTemp)
|
||||||
return pEC/(1.0+ec_tempadjust_alpa*(pTemp-25.0));
|
return pEC/(1.0+ec_tempadjust_alpa*(pTemp-25.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ec_measurementRunning() {
|
||||||
|
return (ec_array_pos<EC_ARRAY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -99,6 +99,9 @@ void temperature_setup() {
|
||||||
DeviceAddress _addr;
|
DeviceAddress _addr;
|
||||||
if (!oneWire.search(_addr)) {
|
if (!oneWire.search(_addr)) {
|
||||||
Serial.print("Error: Device not found");
|
Serial.print("Error: Device not found");
|
||||||
|
String _text="Error: Device not found. id=";
|
||||||
|
_text.concat(i);
|
||||||
|
publishInfo("error/temperature",_text);
|
||||||
}else{
|
}else{
|
||||||
Serial.print("Found device. Address:");
|
Serial.print("Found device. Address:");
|
||||||
printAddress(_addr);
|
printAddress(_addr);
|
||||||
|
@ -120,6 +123,7 @@ void temperature_loop(unsigned long loopmillis) {
|
||||||
if (loopmillis>last_read_ds18b20+READINTERVAL_DS18B20) {
|
if (loopmillis>last_read_ds18b20+READINTERVAL_DS18B20) {
|
||||||
if (loopmillis>last_read_ds18b20+READINTERVAL_DS18B20*10) { //timeout
|
if (loopmillis>last_read_ds18b20+READINTERVAL_DS18B20*10) { //timeout
|
||||||
Serial.println("Warn: Request Temperatures Timeout!");
|
Serial.println("Warn: Request Temperatures Timeout!");
|
||||||
|
publishInfo("error/temperature","Warn: Request Temperatures Timeout!");
|
||||||
flag_requestTemperatures=false;
|
flag_requestTemperatures=false;
|
||||||
}
|
}
|
||||||
if (!flag_requestTemperatures) {
|
if (!flag_requestTemperatures) {
|
||||||
|
@ -134,6 +138,7 @@ void temperature_loop(unsigned long loopmillis) {
|
||||||
if (tempC_reservoir_a == DEVICE_DISCONNECTED_C)
|
if (tempC_reservoir_a == DEVICE_DISCONNECTED_C)
|
||||||
{
|
{
|
||||||
Serial.print(" Error reading: "); printAddress(thermometerReservoirA);
|
Serial.print(" Error reading: "); printAddress(thermometerReservoirA);
|
||||||
|
publishInfo("error/temperature","Error reading thermometerReservoirA");
|
||||||
}else{
|
}else{
|
||||||
tempCmean_reservoir_a_array[tempCmean_pos]=tempC_reservoir_a;
|
tempCmean_reservoir_a_array[tempCmean_pos]=tempC_reservoir_a;
|
||||||
if (isValueArrayOKf(tempCmean_reservoir_a_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
|
if (isValueArrayOKf(tempCmean_reservoir_a_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
|
||||||
|
@ -148,6 +153,7 @@ void temperature_loop(unsigned long loopmillis) {
|
||||||
if (tempC_reservoir_b == DEVICE_DISCONNECTED_C)
|
if (tempC_reservoir_b == DEVICE_DISCONNECTED_C)
|
||||||
{
|
{
|
||||||
Serial.print(" Error reading: "); printAddress(thermometerReservoirB);
|
Serial.print(" Error reading: "); printAddress(thermometerReservoirB);
|
||||||
|
publishInfo("error/temperature","Error reading thermometerReservoirB");
|
||||||
}else{
|
}else{
|
||||||
tempCmean_reservoir_b_array[tempCmean_pos]=tempC_reservoir_b;
|
tempCmean_reservoir_b_array[tempCmean_pos]=tempC_reservoir_b;
|
||||||
if (isValueArrayOKf(tempCmean_reservoir_b_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
|
if (isValueArrayOKf(tempCmean_reservoir_b_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
|
||||||
|
@ -161,6 +167,7 @@ void temperature_loop(unsigned long loopmillis) {
|
||||||
if (tempC_case == DEVICE_DISCONNECTED_C)
|
if (tempC_case == DEVICE_DISCONNECTED_C)
|
||||||
{
|
{
|
||||||
Serial.print(" Error reading: "); printAddress(thermometerCase);
|
Serial.print(" Error reading: "); printAddress(thermometerCase);
|
||||||
|
publishInfo("error/temperature","Error reading thermometerCase");
|
||||||
}else{
|
}else{
|
||||||
tempCmean_case_array[tempCmean_pos]=tempC_case;
|
tempCmean_case_array[tempCmean_pos]=tempC_case;
|
||||||
if (isValueArrayOKf(tempCmean_case_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
|
if (isValueArrayOKf(tempCmean_case_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
|
||||||
|
|
|
@ -2,94 +2,332 @@
|
||||||
#define _WATERLEVEL_H_
|
#define _WATERLEVEL_H_
|
||||||
|
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <VL6180X.h>
|
#include <VL53L0X.h> //pololu/VL53L0X@^1.3.1
|
||||||
|
|
||||||
|
|
||||||
VL6180X sensor;
|
|
||||||
|
|
||||||
|
|
||||||
|
// +++++++++++++++ Common Parameters ++++++++++
|
||||||
|
|
||||||
|
#define READINTERVAL_WATERLEVEL 500
|
||||||
|
#define WATERLEVELMEAN_SIZE 16
|
||||||
|
#define WATERLEVELMEAN_FILTER_CUTOFF 4 //max value is around WATERLEVELMEAN_SIZE/2
|
||||||
|
|
||||||
|
|
||||||
|
#define WATERLEVEL_UNAVAILABLE -1 //-1 is also timeout value
|
||||||
|
|
||||||
|
|
||||||
|
// +++++++++++++++ VL53L0X +++++++++++++++
|
||||||
|
VL53L0X sensorA;
|
||||||
|
#define PIN_VL53L0X_XSHUT 19
|
||||||
|
// Uncomment this line to use long range mode. This
|
||||||
|
// increases the sensitivity of the sensor and extends its
|
||||||
|
// potential range, but increases the likelihood of getting
|
||||||
|
// an inaccurate reading because of reflections from objects
|
||||||
|
// other than the intended target. It works best in dark
|
||||||
|
// conditions.
|
||||||
|
|
||||||
|
//#define LONG_RANGE
|
||||||
|
|
||||||
|
// Uncomment ONE of these two lines to get
|
||||||
|
// - higher speed at the cost of lower accuracy OR
|
||||||
|
// - higher accuracy at the cost of lower speed
|
||||||
|
|
||||||
|
//#define HIGH_SPEED
|
||||||
|
#define HIGH_ACCURACY
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
float waterlevelAMean_array[WATERLEVELMEAN_SIZE];
|
||||||
|
uint16_t waterlevelAMean_array_pos=0;
|
||||||
|
float waterlevelA=WATERLEVEL_UNAVAILABLE; //distance from floor to water surface [mm]
|
||||||
|
float watervolumeA=WATERLEVEL_UNAVAILABLE; //calculated Volume in Reservoir
|
||||||
|
|
||||||
|
|
||||||
|
//Calibration
|
||||||
|
float waterlevelA_calib_offset=532.78; //c
|
||||||
|
float waterlevelA_calib_factor=-1.179; //m
|
||||||
|
|
||||||
|
|
||||||
|
float waterlevelA_calib_reservoirArea=20*20*3.1416; //area in cm^2. barrel diameter inside is 400mm
|
||||||
|
|
||||||
|
uint16_t distanceA_unsuccessful_count=0;
|
||||||
|
|
||||||
|
// +++++++++++++++ VL6180X +++++++++++++++
|
||||||
|
VL6180X sensorB;
|
||||||
// To try different scaling factors, change the following define.
|
// To try different scaling factors, change the following define.
|
||||||
// Valid scaling factors are 1, 2, or 3.
|
// Valid scaling factors are 1, 2, or 3.
|
||||||
#define SCALING 1
|
#define SCALING 1
|
||||||
|
|
||||||
|
|
||||||
#define READINTERVAL_WATERLEVEL 200
|
|
||||||
|
|
||||||
#define WATERLEVELMEAN_SIZE 32
|
|
||||||
#define WATERLEVELMEAN_FILTER_CUTOFF 8 //max value is around WATERLEVELMEAN_SIZE/2
|
float waterlevelBMean_array[WATERLEVELMEAN_SIZE];
|
||||||
float waterlevelMean_array[WATERLEVELMEAN_SIZE];
|
uint16_t waterlevelBMean_array_pos=0;
|
||||||
uint16_t waterlevelMean_array_pos=0;
|
float waterlevelB=WATERLEVEL_UNAVAILABLE; //distance from floor to water surface [mm]
|
||||||
#define WATERLEVEL_UNAVAILABLE -1
|
float watervolumeB=WATERLEVEL_UNAVAILABLE; //calculated Volume in Reservoir
|
||||||
float waterlevel=WATERLEVEL_UNAVAILABLE; //distance from floor to water surface [mm]
|
|
||||||
float watervolume=WATERLEVEL_UNAVAILABLE; //calculated Volume in Reservoir
|
|
||||||
|
|
||||||
|
|
||||||
//Calibration
|
//Calibration
|
||||||
float waterlevel_calib_offset_measured=86; //Sollwert
|
float waterlevelB_calib_offset=260.86; //c
|
||||||
float waterlevel_calib_offset_sensor=78; //Istwert
|
float waterlevelB_calib_factor=-1.107; //m
|
||||||
//raw reading is 78mm, ruler reads 86mm. VL8160 sensor is 169mm above bottom of reservoir.
|
|
||||||
|
|
||||||
float waterlevel_calib_reservoirArea=27*36.5; //area in cm^2
|
|
||||||
|
|
||||||
|
|
||||||
float waterlevel_heightToVolume(float distance);
|
float waterlevelB_calib_reservoirArea=56.5*36.5; //area in cm^2
|
||||||
|
|
||||||
|
uint16_t distanceB_unsuccessful_count=0;
|
||||||
|
|
||||||
|
|
||||||
mqttValueTiming timing_waterlevel;
|
|
||||||
|
|
||||||
|
float waterlevelA_heightToVolume(float distance);
|
||||||
|
float waterlevelB_heightToVolume(float distance);
|
||||||
|
|
||||||
|
|
||||||
|
mqttValueTiming timing_waterlevelA;
|
||||||
|
mqttValueTiming timing_waterlevelB;
|
||||||
|
|
||||||
void waterlevel_setup() {
|
void waterlevel_setup() {
|
||||||
|
|
||||||
timing_waterlevel.minchange=0.0;
|
|
||||||
timing_waterlevel.maxchange=3.0;
|
|
||||||
timing_waterlevel.mintime=30*000;
|
|
||||||
timing_waterlevel.maxtime=60*60*1000;
|
|
||||||
|
|
||||||
|
pinMode(PIN_VL53L0X_XSHUT, OUTPUT);
|
||||||
|
digitalWrite(PIN_VL53L0X_XSHUT, LOW); //pull to GND
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
|
|
||||||
sensor.init();
|
byte error, address;
|
||||||
sensor.configureDefault();
|
int nDevices;
|
||||||
sensor.setScaling(SCALING);
|
|
||||||
sensor.setTimeout(500);
|
delay(500);
|
||||||
|
Serial.println("Scanning...");
|
||||||
|
|
||||||
|
nDevices = 0;
|
||||||
|
for(address = 1; address < 127; address++ )
|
||||||
|
{
|
||||||
|
// The i2c_scanner uses the return value of
|
||||||
|
// the Write.endTransmisstion to see if
|
||||||
|
// a device did acknowledge to the address.
|
||||||
|
Wire.beginTransmission(address);
|
||||||
|
error = Wire.endTransmission();
|
||||||
|
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
Serial.print("I2C device found at address 0x");
|
||||||
|
if (address<16)
|
||||||
|
Serial.print("0");
|
||||||
|
Serial.print(address,HEX);
|
||||||
|
Serial.println(" !");
|
||||||
|
|
||||||
|
nDevices++;
|
||||||
|
}
|
||||||
|
else if (error==4)
|
||||||
|
{
|
||||||
|
Serial.print("Unknown error at address 0x");
|
||||||
|
if (address<16)
|
||||||
|
Serial.print("0");
|
||||||
|
Serial.println(address,HEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
timing_waterlevelA.minchange=0.0;
|
||||||
|
timing_waterlevelA.maxchange=3.0;
|
||||||
|
timing_waterlevelA.mintime=30*000;
|
||||||
|
timing_waterlevelA.maxtime=60*60*1000;
|
||||||
|
|
||||||
|
timing_waterlevelB.minchange=0.0;
|
||||||
|
timing_waterlevelB.maxchange=3.0;
|
||||||
|
timing_waterlevelB.mintime=30*000;
|
||||||
|
timing_waterlevelB.maxtime=60*60*1000;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Wire.begin();
|
||||||
|
Serial.print("I2C Clock Speed=");
|
||||||
|
Serial.println(Wire.getClock());
|
||||||
|
|
||||||
|
|
||||||
|
sensorB.setTimeout(1000);
|
||||||
|
Serial.println("init A");
|
||||||
|
sensorB.init();
|
||||||
|
Serial.println("set addr 0x2A");
|
||||||
|
sensorB.setAddress(0x2A); //change address
|
||||||
|
Serial.println("conf Default");
|
||||||
|
sensorB.configureDefault();
|
||||||
|
Serial.println("set scaling");
|
||||||
|
sensorB.setScaling(SCALING);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Serial.println("Connect second sensor now!");
|
||||||
|
delay(1000);
|
||||||
|
Serial.println("waiting 5s");
|
||||||
|
delay(5000);
|
||||||
|
Serial.println("done waiting");*/
|
||||||
|
|
||||||
|
|
||||||
|
// Stop driving this sensor's XSHUT low. This should allow the carrier
|
||||||
|
// board to pull it high. (We do NOT want to drive XSHUT high since it is
|
||||||
|
// not level shifted.) Then wait a bit for the sensor to start up.
|
||||||
|
pinMode(PIN_VL53L0X_XSHUT, INPUT);
|
||||||
|
delay(50);
|
||||||
|
|
||||||
|
|
||||||
|
sensorA.setTimeout(1000);
|
||||||
|
if (!sensorA.init())
|
||||||
|
{
|
||||||
|
Serial.println("Failed to detect and initialize sensorA!");
|
||||||
|
publishInfo("error/waterlevel","Failed to detect and initialize sensorA");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined LONG_RANGE
|
||||||
|
// lower the return signal rate limit (default is 0.25 MCPS)
|
||||||
|
sensorA.setSignalRateLimit(0.1);
|
||||||
|
// increase laser pulse periods (defaults are 14 and 10 PCLKs)
|
||||||
|
sensorA.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
|
||||||
|
sensorA.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined HIGH_SPEED
|
||||||
|
// reduce timing budget to 20 ms (default is about 33 ms)
|
||||||
|
sensorA.setMeasurementTimingBudget(20000);
|
||||||
|
#elif defined HIGH_ACCURACY
|
||||||
|
// increase timing budget to 200 ms
|
||||||
|
sensorA.setMeasurementTimingBudget(200000);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (uint16_t i=0;i<WATERLEVELMEAN_SIZE;i++) {
|
for (uint16_t i=0;i<WATERLEVELMEAN_SIZE;i++) {
|
||||||
waterlevelMean_array[i]=-1; //-1 is also timeout value
|
waterlevelAMean_array[i]=WATERLEVEL_UNAVAILABLE; //-1 is also timeout value
|
||||||
|
waterlevelBMean_array[i]=WATERLEVEL_UNAVAILABLE; //-1 is also timeout value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void waterlevel_loop(unsigned long loopmillis) {
|
void waterlevel_loop(unsigned long loopmillis) {
|
||||||
|
static uint8_t waterlevel_loop_select=0;
|
||||||
|
|
||||||
static unsigned long last_read_waterlevel;
|
switch(waterlevel_loop_select)
|
||||||
if (loopmillis>=last_read_waterlevel+READINTERVAL_WATERLEVEL) {
|
{
|
||||||
last_read_waterlevel=loopmillis;
|
case 0:
|
||||||
|
// ############ A
|
||||||
|
|
||||||
|
static unsigned long last_read_waterlevelA;
|
||||||
|
if (loopmillis>=last_read_waterlevelA+READINTERVAL_WATERLEVEL) {
|
||||||
|
last_read_waterlevelA=loopmillis;
|
||||||
|
|
||||||
|
|
||||||
uint16_t distance=sensor.readRangeSingleMillimeters();
|
uint16_t distance=sensorA.readRangeSingleMillimeters(); //error=65535
|
||||||
|
|
||||||
Serial.print("Distance reading:"); Serial.println(distance);
|
//Serial.print("Distance reading A="); Serial.print(distance);Serial.println();
|
||||||
|
|
||||||
if (distance!=WATERLEVEL_UNAVAILABLE) { //successful
|
|
||||||
waterlevelMean_array[waterlevelMean_array_pos]=distance;
|
if (distance!=WATERLEVEL_UNAVAILABLE && distance!=65535) { //successful
|
||||||
waterlevelMean_array_pos++;
|
waterlevelAMean_array[waterlevelAMean_array_pos]=distance;
|
||||||
waterlevelMean_array_pos%=WATERLEVELMEAN_SIZE;
|
waterlevelAMean_array_pos++;
|
||||||
|
waterlevelAMean_array_pos%=WATERLEVELMEAN_SIZE;
|
||||||
|
distanceA_unsuccessful_count=0;
|
||||||
|
}else{
|
||||||
|
distanceA_unsuccessful_count++;
|
||||||
|
if (distanceA_unsuccessful_count%20==0) {
|
||||||
|
String _text="Distance A unsuccessful count=";
|
||||||
|
_text.concat(distanceA_unsuccessful_count);
|
||||||
|
_text.concat(" distance=");
|
||||||
|
_text.concat(distance);
|
||||||
|
publishInfo("error/waterlevel",_text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValueArrayOKf(waterlevelMean_array,WATERLEVELMEAN_SIZE,WATERLEVEL_UNAVAILABLE)){
|
|
||||||
float _filteredDistance=getFilteredf(waterlevelMean_array,WATERLEVELMEAN_SIZE,WATERLEVELMEAN_FILTER_CUTOFF);
|
|
||||||
|
|
||||||
|
if (isValueArrayOKf(waterlevelAMean_array,WATERLEVELMEAN_SIZE,WATERLEVEL_UNAVAILABLE)){
|
||||||
|
float _filteredDistance=getFilteredf(waterlevelAMean_array,WATERLEVELMEAN_SIZE,WATERLEVELMEAN_FILTER_CUTOFF);
|
||||||
|
//Serial.print("Filtered reading A="); Serial.print(_filteredDistance);Serial.println();
|
||||||
|
|
||||||
//Invert distance and offset
|
//Invert distance and offset
|
||||||
waterlevel=(waterlevel_calib_offset_sensor+waterlevel_calib_offset_measured)-_filteredDistance;
|
waterlevelA=constrain(waterlevelA_calib_offset+waterlevelA_calib_factor*_filteredDistance,0,1000);
|
||||||
watervolume=waterlevel_heightToVolume(waterlevel);
|
watervolumeA=waterlevelA_heightToVolume(waterlevelA);
|
||||||
|
|
||||||
|
//float _meanWaterlevel=getMeanf(waterlevelMean,WATERLEVELMEAN_SIZE);
|
||||||
|
//Serial.print("\t Dist="); Serial.print(_filteredWaterlevel); Serial.print("mm"); Serial.print("(+- "); Serial.print((getMaxf(waterlevelMean,WATERLEVELMEAN_SIZE)-getMinf(waterlevelMean,WATERLEVELMEAN_SIZE))/2.0); Serial.print(")"); Serial.print(" [mean="); Serial.print(_meanWaterlevel); Serial.print("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
waterlevel_loop_select++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
// ############ B
|
||||||
|
|
||||||
|
static unsigned long last_read_waterlevelB;
|
||||||
|
if (loopmillis>=last_read_waterlevelB+READINTERVAL_WATERLEVEL) {
|
||||||
|
last_read_waterlevelB=loopmillis;
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t distance=sensorB.readRangeSingleMillimeters(); //out of range =255
|
||||||
|
|
||||||
|
//Serial.print("Distance reading B="); Serial.print(distance);Serial.println();
|
||||||
|
|
||||||
|
|
||||||
|
if (distance!=WATERLEVEL_UNAVAILABLE) { //successful
|
||||||
|
waterlevelBMean_array[waterlevelBMean_array_pos]=distance;
|
||||||
|
waterlevelBMean_array_pos++;
|
||||||
|
waterlevelBMean_array_pos%=WATERLEVELMEAN_SIZE;
|
||||||
|
distanceB_unsuccessful_count=0;
|
||||||
|
}else{
|
||||||
|
distanceB_unsuccessful_count++;
|
||||||
|
if (distanceB_unsuccessful_count%20==0) {
|
||||||
|
String _text="Distance B unsuccessful count=";
|
||||||
|
_text.concat(distanceB_unsuccessful_count);
|
||||||
|
_text.concat(" distance=");
|
||||||
|
_text.concat(distance);
|
||||||
|
publishInfo("error/waterlevel",_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (isValueArrayOKf(waterlevelBMean_array,WATERLEVELMEAN_SIZE,WATERLEVEL_UNAVAILABLE)){
|
||||||
|
float _filteredDistance=getFilteredf(waterlevelBMean_array,WATERLEVELMEAN_SIZE,WATERLEVELMEAN_FILTER_CUTOFF);
|
||||||
|
|
||||||
|
//Serial.print("Filtered reading B="); Serial.print(_filteredDistance);Serial.println();
|
||||||
|
//Invert distance and offset
|
||||||
|
waterlevelB=constrain(waterlevelB_calib_offset+waterlevelB_calib_factor*_filteredDistance,0,1000);
|
||||||
|
watervolumeB=waterlevelB_heightToVolume(waterlevelB);
|
||||||
|
|
||||||
|
|
||||||
//float _meanWaterlevel=getMeanf(waterlevelMean,WATERLEVELMEAN_SIZE);
|
//float _meanWaterlevel=getMeanf(waterlevelMean,WATERLEVELMEAN_SIZE);
|
||||||
//Serial.print("\t Dist="); Serial.print(_filteredWaterlevel); Serial.print("mm"); Serial.print("(+- "); Serial.print((getMaxf(waterlevelMean,WATERLEVELMEAN_SIZE)-getMinf(waterlevelMean,WATERLEVELMEAN_SIZE))/2.0); Serial.print(")"); Serial.print(" [mean="); Serial.print(_meanWaterlevel); Serial.print("]");
|
//Serial.print("\t Dist="); Serial.print(_filteredWaterlevel); Serial.print("mm"); Serial.print("(+- "); Serial.print((getMaxf(waterlevelMean,WATERLEVELMEAN_SIZE)-getMinf(waterlevelMean,WATERLEVELMEAN_SIZE))/2.0); Serial.print(")"); Serial.print(" [mean="); Serial.print(_meanWaterlevel); Serial.print("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
waterlevel_loop_select=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float waterlevel_heightToVolume(float distance){
|
float waterlevelA_heightToVolume(float distance){
|
||||||
return waterlevel_calib_reservoirArea/100 * distance/100; //area[cm^2] in dm^2 * height in dm = dm^3= L
|
return waterlevelA_calib_reservoirArea/100 * distance/100; //area[cm^2] in dm^2 * height in dm = dm^3= L
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float waterlevelB_heightToVolume(float distance){
|
||||||
|
return waterlevelB_calib_reservoirArea/100 * distance/100; //area[cm^2] in dm^2 * height in dm = dm^3= L
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,95 @@
|
||||||
|
#ifndef _WATERLEVEL_H_
|
||||||
|
#define _WATERLEVEL_H_
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <VL6180X.h> //https://github.com/pololu/vl6180x-arduino
|
||||||
|
|
||||||
|
|
||||||
|
VL6180X sensor;
|
||||||
|
// To try different scaling factors, change the following define.
|
||||||
|
// Valid scaling factors are 1, 2, or 3.
|
||||||
|
#define SCALING 1
|
||||||
|
|
||||||
|
|
||||||
|
#define READINTERVAL_WATERLEVEL 200
|
||||||
|
|
||||||
|
#define WATERLEVELMEAN_SIZE 32
|
||||||
|
#define WATERLEVELMEAN_FILTER_CUTOFF 8 //max value is around WATERLEVELMEAN_SIZE/2
|
||||||
|
float waterlevelMean_array[WATERLEVELMEAN_SIZE];
|
||||||
|
uint16_t waterlevelMean_array_pos=0;
|
||||||
|
#define WATERLEVEL_UNAVAILABLE -1
|
||||||
|
float waterlevel=WATERLEVEL_UNAVAILABLE; //distance from floor to water surface [mm]
|
||||||
|
float watervolume=WATERLEVEL_UNAVAILABLE; //calculated Volume in Reservoir
|
||||||
|
|
||||||
|
|
||||||
|
//Calibration
|
||||||
|
float waterlevel_calib_offset_measured=86; //Sollwert
|
||||||
|
float waterlevel_calib_offset_sensor=78; //Istwert
|
||||||
|
//raw reading is 78mm, ruler reads 86mm. VL8160 sensor is 169mm above bottom of reservoir.
|
||||||
|
|
||||||
|
float waterlevel_calib_reservoirArea=27*36.5; //area in cm^2
|
||||||
|
|
||||||
|
|
||||||
|
float waterlevel_heightToVolume(float distance);
|
||||||
|
|
||||||
|
|
||||||
|
mqttValueTiming timing_waterlevel;
|
||||||
|
|
||||||
|
void waterlevel_setup() {
|
||||||
|
|
||||||
|
timing_waterlevel.minchange=0.0;
|
||||||
|
timing_waterlevel.maxchange=3.0;
|
||||||
|
timing_waterlevel.mintime=30*000;
|
||||||
|
timing_waterlevel.maxtime=60*60*1000;
|
||||||
|
|
||||||
|
Wire.begin();
|
||||||
|
|
||||||
|
sensor.init();
|
||||||
|
sensor.configureDefault();
|
||||||
|
sensor.setScaling(SCALING);
|
||||||
|
sensor.setTimeout(500);
|
||||||
|
|
||||||
|
for (uint16_t i=0;i<WATERLEVELMEAN_SIZE;i++) {
|
||||||
|
waterlevelMean_array[i]=-1; //-1 is also timeout value
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void waterlevel_loop(unsigned long loopmillis) {
|
||||||
|
|
||||||
|
static unsigned long last_read_waterlevel;
|
||||||
|
if (loopmillis>=last_read_waterlevel+READINTERVAL_WATERLEVEL) {
|
||||||
|
last_read_waterlevel=loopmillis;
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t distance=sensor.readRangeSingleMillimeters();
|
||||||
|
|
||||||
|
Serial.print("Distance reading:"); Serial.println(distance);
|
||||||
|
|
||||||
|
if (distance!=WATERLEVEL_UNAVAILABLE) { //successful
|
||||||
|
waterlevelMean_array[waterlevelMean_array_pos]=distance;
|
||||||
|
waterlevelMean_array_pos++;
|
||||||
|
waterlevelMean_array_pos%=WATERLEVELMEAN_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isValueArrayOKf(waterlevelMean_array,WATERLEVELMEAN_SIZE,WATERLEVEL_UNAVAILABLE)){
|
||||||
|
float _filteredDistance=getFilteredf(waterlevelMean_array,WATERLEVELMEAN_SIZE,WATERLEVELMEAN_FILTER_CUTOFF);
|
||||||
|
|
||||||
|
|
||||||
|
//Invert distance and offset
|
||||||
|
waterlevel=(waterlevel_calib_offset_sensor+waterlevel_calib_offset_measured)-_filteredDistance;
|
||||||
|
watervolume=waterlevel_heightToVolume(waterlevel);
|
||||||
|
|
||||||
|
//float _meanWaterlevel=getMeanf(waterlevelMean,WATERLEVELMEAN_SIZE);
|
||||||
|
//Serial.print("\t Dist="); Serial.print(_filteredWaterlevel); Serial.print("mm"); Serial.print("(+- "); Serial.print((getMaxf(waterlevelMean,WATERLEVELMEAN_SIZE)-getMinf(waterlevelMean,WATERLEVELMEAN_SIZE))/2.0); Serial.print(")"); Serial.print(" [mean="); Serial.print(_meanWaterlevel); Serial.print("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float waterlevel_heightToVolume(float distance){
|
||||||
|
return waterlevel_calib_reservoirArea/100 * distance/100; //area[cm^2] in dm^2 * height in dm = dm^3= L
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -31,6 +31,7 @@ bool enableTiming=true;
|
||||||
|
|
||||||
bool publishValueTimed(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis);
|
bool publishValueTimed(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis);
|
||||||
void publishValue(String topic,float value,uint8_t decimals);
|
void publishValue(String topic,float value,uint8_t decimals);
|
||||||
|
void publishInfo(String topic,String text);
|
||||||
|
|
||||||
void connect() {
|
void connect() {
|
||||||
Serial.print("checking wifi...");
|
Serial.print("checking wifi...");
|
||||||
|
@ -97,6 +98,13 @@ bool mqtt_loop(unsigned long loopmillis) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool publishValueTimedOverride(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis) {
|
||||||
|
mqttvt.lasttime=loopmillis;
|
||||||
|
mqttvt.lastvalue=value;
|
||||||
|
publishValue(topic,value,decimals);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool publishValueTimed(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis) {
|
bool publishValueTimed(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis) {
|
||||||
unsigned long timediff=loopmillis-mqttvt.lasttime;
|
unsigned long timediff=loopmillis-mqttvt.lasttime;
|
||||||
float valuediff=abs(value-mqttvt.lastvalue);
|
float valuediff=abs(value-mqttvt.lastvalue);
|
||||||
|
@ -122,4 +130,9 @@ void publishValue(String topic,float value,uint8_t decimals) {
|
||||||
Serial.print("Publish Topic="); Serial.print((String)client_id+"/"+topic); Serial.print(" Message="); Serial.println(buffer);
|
Serial.print("Publish Topic="); Serial.print((String)client_id+"/"+topic); Serial.print(" Message="); Serial.println(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void publishInfo(String topic,String text) {
|
||||||
|
client.publish((String)client_id+"/"+topic, text);
|
||||||
|
Serial.print("Publish Topic="); Serial.print((String)client_id+"/"+topic); Serial.print(" Message="); Serial.println(text);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -20,4 +20,5 @@ lib_deps =
|
||||||
https://github.com/emilv/ArduinoSort/
|
https://github.com/emilv/ArduinoSort/
|
||||||
robtillaart/ADS1X15@^0.3.9
|
robtillaart/ADS1X15@^0.3.9
|
||||||
256dpi/MQTT@^2.5.1
|
256dpi/MQTT@^2.5.1
|
||||||
|
pololu/VL53L0X@^1.3.1
|
||||||
https://github.com/pololu/vl6180x-arduino
|
https://github.com/pololu/vl6180x-arduino
|
92
src/main.cpp
92
src/main.cpp
|
@ -1,10 +1,16 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*TODO
|
||||||
|
mqtt function_: valueerror quittieren
|
||||||
|
mqtt function: device reboot
|
||||||
|
check if sendallnext_flag does anything
|
||||||
|
Do not send first flow value (when filter aray is not full)
|
||||||
|
*/
|
||||||
|
|
||||||
#include "wifi_functions.h"
|
#include "wifi_functions.h"
|
||||||
|
|
||||||
bool debug=true; //print Serial information
|
bool debug=false; //print Serial information
|
||||||
bool mqtt=true;
|
bool mqtt=true;
|
||||||
bool eccalibrationoutput=false; //serial output for ec calibration
|
bool eccalibrationoutput=false; //serial output for ec calibration
|
||||||
/* Write to file with:
|
/* Write to file with:
|
||||||
|
@ -25,6 +31,8 @@ ADS1115 ADS(0x48);
|
||||||
#include "temperature.h"
|
#include "temperature.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ######## Water Level
|
||||||
|
#include "waterlevel.h"
|
||||||
|
|
||||||
|
|
||||||
// ######## EC
|
// ######## EC
|
||||||
|
@ -32,9 +40,6 @@ ADS1115 ADS(0x48);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ######## Water Level
|
|
||||||
#include "waterlevel.h"
|
|
||||||
|
|
||||||
|
|
||||||
// ######## Flow Rate
|
// ######## Flow Rate
|
||||||
#include "flow.h"
|
#include "flow.h"
|
||||||
|
@ -45,13 +50,16 @@ ADS1115 ADS(0x48);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool valueError=false;
|
||||||
|
|
||||||
unsigned long last_check=0;
|
unsigned long last_check=0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool valueError=false;
|
|
||||||
|
|
||||||
#define PIN_BUTTON 12
|
#define PIN_BUTTON 12
|
||||||
#define PIN_LED 13
|
#define PIN_LED 13
|
||||||
|
@ -69,9 +77,14 @@ void setup() {
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Serial.println("Setup Waterlevel");
|
||||||
|
waterlevel_setup();
|
||||||
|
|
||||||
//init ADS1115
|
//init ADS1115
|
||||||
if (!ADS.begin()) {
|
if (!ADS.begin()) {
|
||||||
Serial.println("Error:"); delay(2000); Serial.println("ADS1115 Init Error!");
|
Serial.println("Error:"); delay(2000); Serial.println("ADS1115 Init Error!");
|
||||||
|
publishInfo("error/general","ADS1115 Init Error");
|
||||||
}
|
}
|
||||||
ADS.setGain(0);
|
ADS.setGain(0);
|
||||||
|
|
||||||
|
@ -79,8 +92,6 @@ void setup() {
|
||||||
Serial.println("Setup EC");
|
Serial.println("Setup EC");
|
||||||
ec_setup();
|
ec_setup();
|
||||||
|
|
||||||
Serial.println("Setup Waterlevel");
|
|
||||||
waterlevel_setup(); //temporarily disabled
|
|
||||||
|
|
||||||
Serial.println("Setup Temperature");
|
Serial.println("Setup Temperature");
|
||||||
temperature_setup();
|
temperature_setup();
|
||||||
|
@ -125,7 +136,9 @@ void loop() {
|
||||||
|
|
||||||
temperature_loop(loopmillis);
|
temperature_loop(loopmillis);
|
||||||
|
|
||||||
|
if (!ec_measurementRunning()){ //skip tof read when ec measurement running, because vlxx sensor reading takes quite long per cycle
|
||||||
waterlevel_loop(loopmillis);
|
waterlevel_loop(loopmillis);
|
||||||
|
}
|
||||||
|
|
||||||
flow_loop(loopmillis);
|
flow_loop(loopmillis);
|
||||||
|
|
||||||
|
@ -198,6 +211,13 @@ void loop() {
|
||||||
digitalWrite(PIN_LED,valueError);
|
digitalWrite(PIN_LED,valueError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (distanceA_unsuccessful_count>20) {
|
||||||
|
valueError=true;
|
||||||
|
}
|
||||||
|
if (distanceB_unsuccessful_count>20) {
|
||||||
|
valueError=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
@ -262,9 +282,12 @@ void loop() {
|
||||||
Serial.print(ec25_B);
|
Serial.print(ec25_B);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
Serial.print("Waterlevel,Volume = ");
|
Serial.print("A Waterlevel,Volume = ");
|
||||||
Serial.print(waterlevel); Serial.print(",");
|
Serial.print(waterlevelA); Serial.print(",");
|
||||||
Serial.print(watervolume);
|
Serial.print(watervolumeA); Serial.println();
|
||||||
|
Serial.print("B Waterlevel,Volume = ");
|
||||||
|
Serial.print(waterlevelB); Serial.print(",");
|
||||||
|
Serial.print(watervolumeB);
|
||||||
|
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
|
@ -302,13 +325,38 @@ void loop() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
publishValueTimed("nft/flow/flow",flow_a,2,timing_flow_a,loopmillis);
|
|
||||||
publishValueTimed("db/flow/flow",flow_b,2,timing_flow_b,loopmillis);
|
|
||||||
|
|
||||||
if (waterlevel!=WATERLEVEL_UNAVAILABLE) {
|
|
||||||
bool _published=publishValueTimed("waterlevel/height",waterlevel,2,timing_waterlevel,loopmillis);
|
static float last_flow_a=0;
|
||||||
|
if (flow_a==0.0 && last_flow_a!=flow_a) {
|
||||||
|
publishValueTimedOverride("nft/flow",flow_a,2,timing_flow_a,loopmillis); //publish without waiting if flow is 0
|
||||||
|
}else{
|
||||||
|
publishValueTimed("nft/flow",flow_a,2,timing_flow_a,loopmillis);
|
||||||
|
}
|
||||||
|
last_flow_a=flow_a;
|
||||||
|
|
||||||
|
|
||||||
|
static float last_flow_b=0;
|
||||||
|
if (flow_b==0.0 && last_flow_b!=flow_b) {
|
||||||
|
publishValueTimedOverride("db/flow",flow_b,2,timing_flow_b,loopmillis); //publish without waiting if flow is 0
|
||||||
|
}else{
|
||||||
|
publishValueTimed("db/flow",flow_b,2,timing_flow_b,loopmillis);
|
||||||
|
}
|
||||||
|
last_flow_b=flow_b;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (waterlevelA!=WATERLEVEL_UNAVAILABLE) {
|
||||||
|
bool _published=publishValueTimed("nft/waterlevel/height",waterlevelA,2,timing_waterlevelA,loopmillis);
|
||||||
if (_published) { //use height for timing. send calculated volume with it
|
if (_published) { //use height for timing. send calculated volume with it
|
||||||
publishValue("waterlevel/volume",watervolume,2);
|
publishValue("nft/waterlevel/volume",watervolumeA,2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waterlevelB!=WATERLEVEL_UNAVAILABLE) {
|
||||||
|
bool _published=publishValueTimed("db/waterlevel/height",waterlevelB,2,timing_waterlevelB,loopmillis);
|
||||||
|
if (_published) { //use height for timing. send calculated volume with it
|
||||||
|
publishValue("db/waterlevel/volume",watervolumeB,2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,15 +370,15 @@ void loop() {
|
||||||
|
|
||||||
//Probe A
|
//Probe A
|
||||||
if (ec_adc_A!=0) {
|
if (ec_adc_A!=0) {
|
||||||
publishValue("nft/ec/adc",ec_adc_A,0);
|
publishValue("db/ec/adc",ec_adc_A,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ec_adc_adjusted_A!=0) {
|
if (ec_adc_adjusted_A!=0) {
|
||||||
publishValue("nft/ec/adcadjusted",ec_adc_adjusted_A,0);
|
publishValue("db/ec/adcadjusted",ec_adc_adjusted_A,0);
|
||||||
}
|
}
|
||||||
if (ec_A!=EC_UNAVAILABLE){
|
if (ec_A!=EC_UNAVAILABLE){
|
||||||
publishValue("nft/ec/ec",ec_A,0);
|
publishValue("db/ec/ec",ec_A,0);
|
||||||
publishValue("nft/ec/sc",ec25_A,0);
|
publishValue("db/ec/sc",ec25_A,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Probe B
|
//Probe B
|
||||||
|
@ -339,11 +387,11 @@ void loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ec_adc_adjusted_B!=0) {
|
if (ec_adc_adjusted_B!=0) {
|
||||||
publishValue("db/ec/adcadjusted",ec_adc_adjusted_B,0);
|
publishValue("nft/ec/adcadjusted",ec_adc_adjusted_B,0);
|
||||||
}
|
}
|
||||||
if (ec_B!=EC_UNAVAILABLE){
|
if (ec_B!=EC_UNAVAILABLE){
|
||||||
publishValue("db/ec/ec",ec_B,0);
|
publishValue("nft/ec/ec",ec_B,0);
|
||||||
publishValue("db/ec/sc",ec25_B,0);
|
publishValue("nft/ec/sc",ec25_B,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue