hydroponic-controller/src/main.cpp

467 lines
14 KiB
C++

#include <Arduino.h>
bool valueError=false;
unsigned long last_check=0;
#include "wifi_functions.h"
bool debug=false; //print Serial information
bool mqtt=true;
bool eccalibrationoutput=false; //serial output for ec calibration
/* Write to file with:
sudo stty -F /dev/ttyUSB0 115200
cat /dev/ttyUSB0 | tee received.txt
*/
bool valuesStabilized=false; //gets set true when values are stable (avaeraging arrays filled)
#include "helpfunctions.h"
#include "ADS1X15.h"
// ######## Temperature
#include "temperature.h"
// ######## Water Level
#include "waterlevel.h"
// ######## EC
ADS1115 ADS(0x48);
#include "ec.h"
// ######## Flow Rate
#include "flow.h"
// ######## Soilmoisture
//#include "soilmoisture.h"
#define PIN_BUTTON 12
#define PIN_LED 13
void setup() {
pinMode(PIN_BUTTON,INPUT_PULLUP);
pinMode(PIN_LED,OUTPUT);
digitalWrite(PIN_LED,LOW);
Serial.begin(115200);
if (mqtt) {
WiFi.begin(ssid, pass);
client.begin(mqtt_host, net);
client.onMessage(messageReceived);
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);
Serial.println("Setup EC");
ec_setup();
Serial.println("Setup Temperature");
temperature_setup();
Serial.println("Setup Flow");
flow_setup();
/*
Serial.println("Setup Soilmoisture");
sm_setup();
*/
Serial.println("Finished Setup");
delay(200);
//Test adc to ec function output
if (eccalibrationoutput) {
Serial.println();
Serial.print("adc"); Serial.print(","); Serial.print("ecA"); Serial.print(","); Serial.print("ecB"); Serial.println();
for (int i=728;i<14000;i+=100) {
//float _ec=ec_getECfromADC(i);
float _ecA=ec_getECfromADC(i, ec_calibration_polynom_A, sizeof(ec_calibration_polynom_A), ec_calibration_linearize_below_adc_A, ec_calibration_linear_lowADC_A, ec_calibration_linear_lowEC_A);
float _ecB=ec_getECfromADC(i, ec_calibration_polynom_B, sizeof(ec_calibration_polynom_B), ec_calibration_linearize_below_adc_B, ec_calibration_linear_lowADC_B, ec_calibration_linear_lowEC_B);
Serial.print(i); Serial.print(","); Serial.print(_ecA); Serial.print(","); Serial.print(_ecB); Serial.println();
}
delay(100000);
}
//Serial.println("time,tempReservoir,ECadcCalib,ECadc,ECadcAdjusted,EC,EC25");
//Serial.println("time,tempReservoir,ECadcCalib,ECadc,ECadcAdjusted");
}
void loop() {
unsigned long loopmillis=millis();
enableTiming=true; //reactivate
ec_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);
}
flow_loop(loopmillis);
//sm_loop(loopmillis);
static bool getReading=false;
if (!eccalibrationoutput) { //Is in normal operation mode
if (!digitalRead(PIN_BUTTON)) { //button pressed
valueError=false;
Serial.println("Reset ValueError flag by user");
digitalWrite(PIN_LED,valueError); //set led before delay to blink if error persists
delay(100);
}
static bool last_valueError=true;
if (!valuesStabilized) { //if values are not okay since boot
digitalWrite(PIN_LED,(loopmillis/250)%2==0); //blink led
}else{ //LED shows valueError flag status when values were okay once
if (last_valueError!=valueError) { //update led if valueerror flag changed
last_valueError=valueError;
digitalWrite(PIN_LED,valueError);
}
}
}
if (eccalibrationoutput && !digitalRead(PIN_BUTTON) && !getReading) { //Calibration UI
if (!isValueArrayOK(ec_calib_array,EC_CALIB_ARRAY_SIZE,EC_ADC_UNAVAILABLE)) {
for (uint8_t blink=0;blink<5;blink++) {
digitalWrite(PIN_LED,HIGH);
delay(100);
digitalWrite(PIN_LED,LOW);
delay(100);
}
}else{
getReading=true;
force_ec_measurement=true;
ec_flag_measurement_available=false;
digitalWrite(PIN_LED,HIGH);
}
}
if (eccalibrationoutput && ec_flag_measurement_available && getReading) { //Calibration UI
ec_flag_measurement_available=false;
getReading=false;
digitalWrite(PIN_LED,LOW);
Serial.print(loopmillis); Serial.print(",");
Serial.print(tempCmean_reservoir_a); Serial.print(",");
Serial.print(tempCmean_reservoir_b); Serial.print(",");
Serial.print(ec_calib_adc); Serial.print(",");
Serial.print(ec_adc_A); Serial.print(",");
Serial.print(ec_adc_adjusted_A); Serial.print(",");
Serial.print(ec_adc_B); Serial.print(",");
Serial.print(ec_adc_adjusted_B);
Serial.println();
}
if (loopmillis>last_check+2000) { //check values
last_check=loopmillis;
bool _noErrorsDuringLoop=true;
if (tempCmean_reservoir_a==DEVICE_DISCONNECTED_C || tempCmean_reservoir_b==DEVICE_DISCONNECTED_C || tempCmean_case==DEVICE_DISCONNECTED_C) {
if (!valueError && valuesStabilized) { //error just appeared
if (tempCmean_reservoir_a==DEVICE_DISCONNECTED_C) {
Serial.println("valueError tempCmean_reservoir_a");
publishInfo("error/temperature","valueError tempCmean_reservoir_a");
}
if (tempCmean_reservoir_b==DEVICE_DISCONNECTED_C) {
Serial.println("valueError tempCmean_reservoir_b");
publishInfo("error/temperature","valueError tempCmean_reservoir_b");
}
if (tempCmean_case==DEVICE_DISCONNECTED_C) {
Serial.println("valueError tempCmean_case");
publishInfo("error/temperature","valueError tempCmean_case");
}
}
valueError=true;
_noErrorsDuringLoop=false;
}
/*
if (sm_mean1==SM_DISCONNECTED || sm_mean2==SM_DISCONNECTED) {
valueError=true;
}*/
if (ec_A==EC_UNAVAILABLE || ec_B==EC_UNAVAILABLE){
if (!valueError && valuesStabilized) { //error just appeared
if (ec_A==EC_UNAVAILABLE){
Serial.println("valueError ecA");
publishInfo("error/ec","valueError ecA");
}
if (ec_B==EC_UNAVAILABLE){
Serial.println("valueError ecB");
publishInfo("error/ec","valueError ecB");
}
}
valueError=true;
_noErrorsDuringLoop=false;
}
if (distanceA_unsuccessful_count>20) {
if (!valueError && valuesStabilized) { //error just appeared
Serial.println("valueError distanceA");
publishInfo("error/waterlevel","valueError distanceA");
}
valueError=true;
_noErrorsDuringLoop=false;
}
if (distanceB_unsuccessful_count>20) {
if (!valueError && valuesStabilized) { //error just appeared
Serial.println("valueError distanceB");
publishInfo("error/waterlevel","valueError distanceB");
}
valueError=true;
_noErrorsDuringLoop=false;
}
if (_noErrorsDuringLoop && !valuesStabilized) {
valuesStabilized=true; //gets only set to true once
valueError=false; //clear error flag once after boot
Serial.println("Values Stable, clear error flag");
}
if (debug) {
Serial.println("_______________________");
Serial.print(millis()/1000.0,2); Serial.println(":");
Serial.print("temperature reservoir_a,reservoir_b = ");
Serial.print(tempCmean_reservoir_a); Serial.print(","); Serial.print(tempCmean_reservoir_b);
Serial.println();
/*
Serial.print("sm_mean 1,2,3 = ");
Serial.print(sm_mean1); Serial.print(",");
Serial.print(sm_mean2); Serial.print(",");
Serial.print(sm_mean3);
Serial.println();
*/
/*
Serial.print("sm_mean 1,2,3 = ");
Serial.print(getMean(sm_mean1array,SM_SIZE)); Serial.print(",");
Serial.print(getMean(sm_mean2array,SM_SIZE)); Serial.print(",");
Serial.print(getMean(sm_mean3array,SM_SIZE));
Serial.println();
Serial.print("sm_max 1,2,3 = ");
Serial.print(getMax(sm_mean1array,SM_SIZE)); Serial.print(",");
Serial.print(getMax(sm_mean2array,SM_SIZE)); Serial.print(",");
Serial.print(getMax(sm_mean3array,SM_SIZE));
Serial.println();
Serial.print("sm_min 1,2,3 = ");
Serial.print(getMin(sm_mean1array,SM_SIZE)); Serial.print(",");
Serial.print(getMin(sm_mean2array,SM_SIZE)); Serial.print(",");
Serial.print(getMin(sm_mean3array,SM_SIZE));
Serial.println();
//Serial.print(getMax(sm_mean3array,SM_SIZE)); Serial.println();
*/
Serial.print("Flow a= "); Serial.print(flow_a);
Serial.print(", b= "); Serial.print(flow_b);
Serial.println();
Serial.print("EC ec_calib_adc,ec_adc_A,ec_adc_adjusted_A = ");
Serial.print(ec_calib_adc); Serial.print(",");
Serial.print(ec_adc_A); Serial.print(",");
Serial.print(ec_adc_adjusted_A);
Serial.println();
Serial.print("EC ec_A,ec25_A = ");
Serial.print(ec_A); Serial.print(",");
Serial.print(ec25_A);
Serial.println();
Serial.print("EC ec_calib_adc,ec_adc_B,ec_adc_adjusted_B = ");
Serial.print(ec_calib_adc); Serial.print(",");
Serial.print(ec_adc_B); Serial.print(",");
Serial.print(ec_adc_adjusted_B);
Serial.println();
Serial.print("EC ec_B,ec25_B = ");
Serial.print(ec_B); Serial.print(",");
Serial.print(ec25_B);
Serial.println();
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();
}
if (mqtt && mqtt_loop(loopmillis)) {
if (sendallnext_flag) {
sendallnext_flag=false;
enableTiming=false;
}
if (tempCmean_reservoir_a!=DEVICE_DISCONNECTED_C) {
publishValueTimed("nft/temperature/reservoir",tempCmean_reservoir_a,2,timing_temperature_reservoir_a,loopmillis);
}
if (tempCmean_reservoir_b!=DEVICE_DISCONNECTED_C) {
publishValueTimed("db/temperature/reservoir",tempCmean_reservoir_b,2,timing_temperature_reservoir_b,loopmillis);
}
if (tempCmean_case!=DEVICE_DISCONNECTED_C) {
publishValueTimed("case/temperature",tempCmean_case,2,timing_temperature_case,loopmillis);
}
/*
if (sm_mean1!=SM_DISCONNECTED) {
publishValueTimed("soilmoisture/sm1",sm_mean1,3,timing_soilmoisture_sm1,loopmillis);
}
if (sm_mean2!=SM_DISCONNECTED) {
publishValueTimed("soilmoisture/sm2",sm_mean2,3,timing_soilmoisture_sm2,loopmillis);
}
if (sm_mean3!=SM_DISCONNECTED) {
publishValueTimed("soilmoisture/sm3",sm_mean3,3,timing_soilmoisture_sm3,loopmillis);
}
*/
static float last_flow_a=0;
if (valuesStabilized){
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 (valuesStabilized){
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("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);
}
}
if (ec_flag_measurement_available){
ec_flag_measurement_available=false;
if (ec_calib_adc!=0) {
publishValue("ec/eccalibadc",ec_calib_adc,0);
}
//Probe A
if (ec_adc_A!=0) {
publishValue("db/ec/adc",ec_adc_A,0);
}
if (ec_adc_adjusted_A!=0) {
publishValue("db/ec/adcadjusted",ec_adc_adjusted_A,0);
}
if (ec_A!=EC_UNAVAILABLE){
publishValue("db/ec/ec",ec_A,0);
publishValue("db/ec/sc",ec25_A,0);
}
//Probe B
if (ec_adc_B!=0) {
publishValue("nft/ec/adc",ec_adc_B,0);
}
if (ec_adc_adjusted_B!=0) {
publishValue("nft/ec/adcadjusted",ec_adc_adjusted_B,0);
}
if (ec_B!=EC_UNAVAILABLE){
publishValue("nft/ec/ec",ec_B,0);
publishValue("nft/ec/sc",ec25_B,0);
}
}
/*
if (ec_adc!=0) {
publishValueTimed("ec/adc",ec_adc,0,timing_ec_adc,loopmillis);
}
if (ec_calib_adc!=0) {
publishValueTimed("ec/eccalibadc",ec_calib_adc,0,timing_ec_calibadc,loopmillis);
}
if (ec_adc_adjusted!=0) {
publishValueTimed("ec/adcadjusted",ec_adc_adjusted,0,timing_ec_adcadjusted,loopmillis);
}
if (ec!=EC_UNAVAILABLE){
publishValueTimed("ec/ec",ec,0,timing_ec_ec,loopmillis);
publishValueTimed("ec/sc",ec25,0,timing_ec_sc,loopmillis);
}*/
}
}
}