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();
|
||||
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);
|
||||
bool ec_measurementRunning();
|
||||
|
||||
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
|
||||
last_read_ec=loopmillis;
|
||||
|
||||
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);
|
||||
Serial.print(". Write to pos ");
|
||||
Serial.println(ec_array_pos);
|
||||
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
bool ec_measurementRunning() {
|
||||
return (ec_array_pos<EC_ARRAY_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -99,6 +99,9 @@ void temperature_setup() {
|
|||
DeviceAddress _addr;
|
||||
if (!oneWire.search(_addr)) {
|
||||
Serial.print("Error: Device not found");
|
||||
String _text="Error: Device not found. id=";
|
||||
_text.concat(i);
|
||||
publishInfo("error/temperature",_text);
|
||||
}else{
|
||||
Serial.print("Found device. Address:");
|
||||
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*10) { //timeout
|
||||
Serial.println("Warn: Request Temperatures Timeout!");
|
||||
publishInfo("error/temperature","Warn: Request Temperatures Timeout!");
|
||||
flag_requestTemperatures=false;
|
||||
}
|
||||
if (!flag_requestTemperatures) {
|
||||
|
@ -134,6 +138,7 @@ void temperature_loop(unsigned long loopmillis) {
|
|||
if (tempC_reservoir_a == DEVICE_DISCONNECTED_C)
|
||||
{
|
||||
Serial.print(" Error reading: "); printAddress(thermometerReservoirA);
|
||||
publishInfo("error/temperature","Error reading thermometerReservoirA");
|
||||
}else{
|
||||
tempCmean_reservoir_a_array[tempCmean_pos]=tempC_reservoir_a;
|
||||
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)
|
||||
{
|
||||
Serial.print(" Error reading: "); printAddress(thermometerReservoirB);
|
||||
publishInfo("error/temperature","Error reading thermometerReservoirB");
|
||||
}else{
|
||||
tempCmean_reservoir_b_array[tempCmean_pos]=tempC_reservoir_b;
|
||||
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)
|
||||
{
|
||||
Serial.print(" Error reading: "); printAddress(thermometerCase);
|
||||
publishInfo("error/temperature","Error reading thermometerCase");
|
||||
}else{
|
||||
tempCmean_case_array[tempCmean_pos]=tempC_case;
|
||||
if (isValueArrayOKf(tempCmean_case_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
|
||||
|
|
|
@ -2,94 +2,332 @@
|
|||
#define _WATERLEVEL_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.
|
||||
// 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
|
||||
|
||||
float waterlevelBMean_array[WATERLEVELMEAN_SIZE];
|
||||
uint16_t waterlevelBMean_array_pos=0;
|
||||
float waterlevelB=WATERLEVEL_UNAVAILABLE; //distance from floor to water surface [mm]
|
||||
float watervolumeB=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 waterlevelB_calib_offset=260.86; //c
|
||||
float waterlevelB_calib_factor=-1.107; //m
|
||||
|
||||
|
||||
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() {
|
||||
|
||||
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();
|
||||
|
||||
sensor.init();
|
||||
sensor.configureDefault();
|
||||
sensor.setScaling(SCALING);
|
||||
sensor.setTimeout(500);
|
||||
byte error, address;
|
||||
int nDevices;
|
||||
|
||||
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++) {
|
||||
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) {
|
||||
static uint8_t waterlevel_loop_select=0;
|
||||
|
||||
static unsigned long last_read_waterlevel;
|
||||
if (loopmillis>=last_read_waterlevel+READINTERVAL_WATERLEVEL) {
|
||||
last_read_waterlevel=loopmillis;
|
||||
switch(waterlevel_loop_select)
|
||||
{
|
||||
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;
|
||||
waterlevelMean_array_pos++;
|
||||
waterlevelMean_array_pos%=WATERLEVELMEAN_SIZE;
|
||||
|
||||
if (distance!=WATERLEVEL_UNAVAILABLE && distance!=65535) { //successful
|
||||
waterlevelAMean_array[waterlevelAMean_array_pos]=distance;
|
||||
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(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
|
||||
waterlevelA=constrain(waterlevelA_calib_offset+waterlevelA_calib_factor*_filteredDistance,0,1000);
|
||||
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;
|
||||
|
||||
if (isValueArrayOKf(waterlevelMean_array,WATERLEVELMEAN_SIZE,WATERLEVEL_UNAVAILABLE)){
|
||||
float _filteredDistance=getFilteredf(waterlevelMean_array,WATERLEVELMEAN_SIZE,WATERLEVELMEAN_FILTER_CUTOFF);
|
||||
case 1:
|
||||
|
||||
// ############ B
|
||||
|
||||
static unsigned long last_read_waterlevelB;
|
||||
if (loopmillis>=last_read_waterlevelB+READINTERVAL_WATERLEVEL) {
|
||||
last_read_waterlevelB=loopmillis;
|
||||
|
||||
|
||||
//Invert distance and offset
|
||||
waterlevel=(waterlevel_calib_offset_sensor+waterlevel_calib_offset_measured)-_filteredDistance;
|
||||
watervolume=waterlevel_heightToVolume(waterlevel);
|
||||
uint16_t distance=sensorB.readRangeSingleMillimeters(); //out of range =255
|
||||
|
||||
//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("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);
|
||||
//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){
|
||||
return waterlevel_calib_reservoirArea/100 * distance/100; //area[cm^2] in dm^2 * height in dm = dm^3= L
|
||||
float waterlevelA_heightToVolume(float distance){
|
||||
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
|
|
@ -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);
|
||||
void publishValue(String topic,float value,uint8_t decimals);
|
||||
void publishInfo(String topic,String text);
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
|
@ -97,6 +98,13 @@ bool mqtt_loop(unsigned long loopmillis) {
|
|||
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) {
|
||||
unsigned long timediff=loopmillis-mqttvt.lasttime;
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
|
@ -20,4 +20,5 @@ lib_deps =
|
|||
https://github.com/emilv/ArduinoSort/
|
||||
robtillaart/ADS1X15@^0.3.9
|
||||
256dpi/MQTT@^2.5.1
|
||||
pololu/VL53L0X@^1.3.1
|
||||
https://github.com/pololu/vl6180x-arduino
|
94
src/main.cpp
94
src/main.cpp
|
@ -1,10 +1,16 @@
|
|||
#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"
|
||||
|
||||
bool debug=true; //print Serial information
|
||||
bool debug=false; //print Serial information
|
||||
bool mqtt=true;
|
||||
bool eccalibrationoutput=false; //serial output for ec calibration
|
||||
/* Write to file with:
|
||||
|
@ -25,6 +31,8 @@ ADS1115 ADS(0x48);
|
|||
#include "temperature.h"
|
||||
|
||||
|
||||
// ######## Water Level
|
||||
#include "waterlevel.h"
|
||||
|
||||
|
||||
// ######## EC
|
||||
|
@ -32,9 +40,6 @@ ADS1115 ADS(0x48);
|
|||
|
||||
|
||||
|
||||
// ######## Water Level
|
||||
#include "waterlevel.h"
|
||||
|
||||
|
||||
// ######## Flow Rate
|
||||
#include "flow.h"
|
||||
|
@ -45,13 +50,16 @@ ADS1115 ADS(0x48);
|
|||
|
||||
|
||||
|
||||
|
||||
bool valueError=false;
|
||||
|
||||
unsigned long last_check=0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool valueError=false;
|
||||
|
||||
|
||||
#define PIN_BUTTON 12
|
||||
#define PIN_LED 13
|
||||
|
@ -69,9 +77,14 @@ void setup() {
|
|||
connect();
|
||||
}
|
||||
|
||||
|
||||
Serial.println("Setup Waterlevel");
|
||||
waterlevel_setup();
|
||||
|
||||
//init ADS1115
|
||||
if (!ADS.begin()) {
|
||||
Serial.println("Error:"); delay(2000); Serial.println("ADS1115 Init Error!");
|
||||
publishInfo("error/general","ADS1115 Init Error");
|
||||
}
|
||||
ADS.setGain(0);
|
||||
|
||||
|
@ -79,8 +92,6 @@ void setup() {
|
|||
Serial.println("Setup EC");
|
||||
ec_setup();
|
||||
|
||||
Serial.println("Setup Waterlevel");
|
||||
waterlevel_setup(); //temporarily disabled
|
||||
|
||||
Serial.println("Setup Temperature");
|
||||
temperature_setup();
|
||||
|
@ -125,7 +136,9 @@ void loop() {
|
|||
|
||||
temperature_loop(loopmillis);
|
||||
|
||||
waterlevel_loop(loopmillis);
|
||||
if (!ec_measurementRunning()){ //skip tof read when ec measurement running, because vlxx sensor reading takes quite long per cycle
|
||||
waterlevel_loop(loopmillis);
|
||||
}
|
||||
|
||||
flow_loop(loopmillis);
|
||||
|
||||
|
@ -198,6 +211,13 @@ void loop() {
|
|||
digitalWrite(PIN_LED,valueError);
|
||||
}
|
||||
|
||||
if (distanceA_unsuccessful_count>20) {
|
||||
valueError=true;
|
||||
}
|
||||
if (distanceB_unsuccessful_count>20) {
|
||||
valueError=true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (debug) {
|
||||
|
@ -262,9 +282,12 @@ void loop() {
|
|||
Serial.print(ec25_B);
|
||||
Serial.println();
|
||||
|
||||
Serial.print("Waterlevel,Volume = ");
|
||||
Serial.print(waterlevel); Serial.print(",");
|
||||
Serial.print(watervolume);
|
||||
Serial.print("A Waterlevel,Volume = ");
|
||||
Serial.print(waterlevelA); Serial.print(",");
|
||||
Serial.print(watervolumeA); Serial.println();
|
||||
Serial.print("B Waterlevel,Volume = ");
|
||||
Serial.print(waterlevelB); Serial.print(",");
|
||||
Serial.print(watervolumeB);
|
||||
|
||||
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
|
||||
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
|
||||
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) {
|
||||
publishValue("nft/ec/adcadjusted",ec_adc_adjusted_A,0);
|
||||
publishValue("db/ec/adcadjusted",ec_adc_adjusted_A,0);
|
||||
}
|
||||
if (ec_A!=EC_UNAVAILABLE){
|
||||
publishValue("nft/ec/ec",ec_A,0);
|
||||
publishValue("nft/ec/sc",ec25_A,0);
|
||||
publishValue("db/ec/ec",ec_A,0);
|
||||
publishValue("db/ec/sc",ec25_A,0);
|
||||
}
|
||||
|
||||
//Probe B
|
||||
|
@ -339,11 +387,11 @@ void loop() {
|
|||
}
|
||||
|
||||
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){
|
||||
publishValue("db/ec/ec",ec_B,0);
|
||||
publishValue("db/ec/sc",ec25_B,0);
|
||||
publishValue("nft/ec/ec",ec_B,0);
|
||||
publishValue("nft/ec/sc",ec25_B,0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue