diff --git a/include/ec.h b/include/ec.h index ca6de35..c77a2de 100644 --- a/include/ec.h +++ b/include/ec.h @@ -2,6 +2,12 @@ #define _EC_H_ #include +mqttValueTiming timing_ec_adc; +mqttValueTiming timing_ec_calibadc; +mqttValueTiming timing_ec_adcadjusted; +mqttValueTiming timing_ec_ec; +mqttValueTiming timing_ec_sc; + bool ec_flag_measurement_available=false; @@ -29,7 +35,7 @@ uint16_t ec_calib_array_pos=0; uint16_t ec_array[EC_ARRAY_SIZE]; uint16_t ec_array_pos=EC_ARRAY_SIZE; unsigned long last_measurement_ec=0; -#define EC_MEASUREMENT_INTERVAL 30000 //complete filtered measurement every x ms +#define EC_MEASUREMENT_INTERVAL 10*60*1000 //complete filtered measurement every x ms //One filtered measurement takes EC_READ_INTERVAL*EC_ARRAY_SIZE*4 #define EC_READ_INTERVAL 10 //interval of reading adc value inside a measurement. one reading takes about 9-10ms @@ -73,6 +79,33 @@ float ec_getECfromADC(float adc); float ec_calculateEC25(float pEC,float pTemp); void ec_setup() { + + timing_ec_adc.minchange=0.0; + timing_ec_adc.maxchange=250; + timing_ec_adc.mintime=10*000; + timing_ec_adc.maxtime=60*60*1000; + + timing_ec_calibadc.minchange=0.0; + timing_ec_calibadc.maxchange=250; + timing_ec_calibadc.mintime=10*000; + timing_ec_calibadc.maxtime=60*60*1000; + + timing_ec_adcadjusted.minchange=0.0; + timing_ec_adcadjusted.maxchange=2.0; + timing_ec_adcadjusted.mintime=10*000; + timing_ec_adcadjusted.maxtime=30*60*1000; + + timing_ec_ec.minchange=0.0; + timing_ec_ec.maxchange=50; + timing_ec_ec.mintime=10*000; + timing_ec_ec.maxtime=60*60*1000; + + timing_ec_sc.minchange=0.0; + timing_ec_sc.maxchange=50; + timing_ec_sc.mintime=10*000; + timing_ec_sc.maxtime=60*60*1000; + + ledcSetup(EC_PWM_CH, EC_FREQUENCY, EC_RESOLUTION); ledcAttachPin(EC_PIN_FREQ, EC_PWM_CH); ledcWrite(EC_PWM_CH, 127); //50% duty cycle @@ -86,11 +119,13 @@ void ec_loop(unsigned long loopmillis) { static unsigned long last_read_ec=0; + switch (ecstate) { case IDLE: - if (loopmillis>last_measurement_ec+EC_MEASUREMENT_INTERVAL && ecstate==IDLE) { //start measurement if idle + if (loopmillis>last_measurement_ec+EC_MEASUREMENT_INTERVAL || force_ec_measurement) { //start measurement if idle last_measurement_ec=loopmillis; + force_ec_measurement=false; ec_startMeasurement(); ec_connectProbe(true); @@ -135,6 +170,7 @@ void ec_loop(unsigned long loopmillis) { ec_array_pos++; } + } }else{ //measurement not running, then take calibration readings if (loopmillis>last_read_ec+EC_CALIB_READ_INTERVAL) { //take reading into array @@ -148,7 +184,9 @@ void ec_loop(unsigned long loopmillis) { ec_calib_array_pos++; ec_calib_array_pos%=EC_CALIB_ARRAY_SIZE; - + if (isValueArrayOK(ec_calib_array,EC_CALIB_ARRAY_SIZE,EC_ADC_UNAVAILABLE)){ + ec_calib_adc=getMean(ec_calib_array,EC_CALIB_ARRAY_SIZE); + } } } } @@ -201,7 +239,12 @@ float ec_getECfromADC(float adc) { _ec=mapf(adc,x0,x1,y0,y1); //linear approximation } - return _ec; + if (_ec>=0) { + return _ec; + }else{ + return 0; + } + } float ec_calculateEC25(float pEC,float pTemp) diff --git a/include/flow.h b/include/flow.h index d60a18f..7fe5e7f 100644 --- a/include/flow.h +++ b/include/flow.h @@ -1,6 +1,8 @@ #ifndef _FLOW_H_ #define _FLOW_H_ +mqttValueTiming timing_flow; + #define FLOW_PIN 19 uint16_t flow_counter=0; //maximum counts/s measured with Eden 128 Pump was 171 void IRAM_ATTR isr_flow(); @@ -15,8 +17,13 @@ uint32_t flow_counter_sum=0; void flow_setup() { - pinMode(FLOW_PIN, INPUT_PULLUP); - attachInterrupt(FLOW_PIN, isr_flow, CHANGE); + timing_flow.minchange=0.0; + timing_flow.maxchange=0.5; + timing_flow.mintime=1*000; + timing_flow.maxtime=30*60*1000; + + pinMode(FLOW_PIN, INPUT_PULLUP); + attachInterrupt(FLOW_PIN, isr_flow, CHANGE); } void flow_loop(unsigned long loopmillis) { diff --git a/include/soilmoisture.h b/include/soilmoisture.h index 503fa31..c1d23cf 100644 --- a/include/soilmoisture.h +++ b/include/soilmoisture.h @@ -7,11 +7,14 @@ #define READINTERVAL_SM 100 +mqttValueTiming timing_soilmoisture_sm1; +mqttValueTiming timing_soilmoisture_sm2; +mqttValueTiming timing_soilmoisture_sm3; //Calibration values //high=adc value for sensor in air //low=adc value for sensor in NaCl solution at 25°C with 12880 uS/cm -float sm1_low=45555; +float sm1_low=4555; float sm1_high=11799; float sm2_low=3235; float sm2_high=16050; @@ -43,6 +46,23 @@ uint8_t sm_readchannel=0; void sm_setup() { + + timing_soilmoisture_sm1.minchange=0.0; + timing_soilmoisture_sm1.maxchange=0.05; + timing_soilmoisture_sm1.mintime=2*1000; + timing_soilmoisture_sm1.maxtime=60*60*1000; + + timing_soilmoisture_sm2.minchange=0.0; + timing_soilmoisture_sm2.maxchange=0.05; + timing_soilmoisture_sm2.mintime=2*1000; + timing_soilmoisture_sm2.maxtime=60*60*1000; + + timing_soilmoisture_sm3.minchange=0.0; + timing_soilmoisture_sm3.maxchange=0.05; + timing_soilmoisture_sm3.mintime=2*1000; + timing_soilmoisture_sm3.maxtime=60*60*1000; + + for (uint16_t i=0;i #include @@ -38,6 +41,15 @@ float tempCmean_air=DEVICE_DISCONNECTED_C; void temperature_setup() { + timing_temperature_reservoir.minchange=0.0; + timing_temperature_reservoir.maxchange=0.5; + timing_temperature_reservoir.mintime=2*1000; + timing_temperature_reservoir.maxtime=60*60*1000; + + timing_temperature_air.minchange=0.0; + timing_temperature_air.maxchange=0.5; + timing_temperature_air.mintime=2*1000; + timing_temperature_air.maxtime=60*60*1000; //initialize mean array for (uint16_t i=0;i #include "wifi_settings.h" +#include "helpfunctions.h" + + +struct mqttValueTiming{ + float minchange; + float maxchange; + unsigned long mintime; + unsigned long maxtime; + float lastvalue=0; + unsigned long lasttime=0; +}; WiFiClient net; MQTTClient client; +bool sendallnext_flag=false; +bool enableTiming=true; + +bool force_ec_measurement=false; + +void publishValueTimed(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis); +void publishValue(String topic,float value,uint8_t decimals); + void connect() { Serial.print("checking wifi..."); - while (WiFi.status() != WL_CONNECTED) { + uint8_t timeout=0; + while (WiFi.status() != WL_CONNECTED && timeout<10) { + timeout++; Serial.print("."); - delay(1000); + delay(500); } + + if (WiFi.status() == WL_CONNECTED) + { + Serial.print("\nconnecting..."); + timeout=0; + #define CONNECT_TIMEOUT 5 + while (!client.connect(client_id, "public", "public") && timeout=CONNECT_TIMEOUT) { + Serial.println("\nconnection failed!"); + }else{ + Serial.println("\nconnected!"); + client.subscribe((String)client_id+"/sendall"); + client.subscribe((String)client_id+"/ec/trigger"); + // client.unsubscribe("/hello"); + } + - Serial.print("\nconnecting..."); - while (!client.connect(client_id, "public", "public")) { - Serial.print("."); - delay(1000); } - - Serial.println("\nconnected!"); - - client.subscribe("/hello"); - // client.unsubscribe("/hello"); } void messageReceived(String &topic, String &payload) { Serial.println("incoming: " + topic + " - " + payload); + if (topic==((String)client_id+"/sendall") && payload=="true") { + sendallnext_flag=true; + Serial.println("Send all values next time"); + } + if (topic==((String)client_id+"/ec/trigger") && payload=="true") { + force_ec_measurement=true; + Serial.println("Forced EC Measurement"); + } +} - // Note: Do not use the client in the callback to publish, subscribe or - // unsubscribe as it may cause deadlocks when other things arrive while - // sending and receiving acknowledgments. Instead, change a global variable, - // or push to a queue and handle it in the loop after calling `client.loop()`. +bool mqtt_loop(unsigned long loopmillis) { + static unsigned long last_client_loop=0; + #define CLIENT_LOOP_INTERVAL 10 //ms. fixes some wifi issues. from example https://registry.platformio.org/libraries/256dpi/MQTT/examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino + if (loopmillis >= last_client_loop+CLIENT_LOOP_INTERVAL) { + last_client_loop=loopmillis; + client.loop(); + + static unsigned long last_connection_try=0; + #define RETRY_CONNECTION 60000 + if (!client.connected()) { + if (loopmillis-last_connection_try>RETRY_CONNECTION) { + connect(); + } + }else{ + return true; + } + } + return false; +} + +void 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); + valuediff=constrain(valuediff,mqttvt.minchange,mqttvt.maxchange); + unsigned long sendafter=mapf(valuediff,mqttvt.minchange,mqttvt.maxchange,mqttvt.maxtime,mqttvt.mintime); //map valuediff to time when to send + /*Serial.println(); + Serial.print("timediff="); Serial.print(timediff); + Serial.print(" valuediff="); Serial.print(valuediff); + Serial.print(" sendafter="); Serial.println(sendafter);*/ + if (timediff>=sendafter || !enableTiming) { + mqttvt.lasttime=loopmillis; + mqttvt.lastvalue=value; + publishValue(topic,value,decimals); + } +} + +void publishValue(String topic,float value,uint8_t decimals) { + char buffer[16]; + dtostrf(value,1,decimals,buffer); + client.publish((String)client_id+"/"+topic, buffer); + Serial.print("Publish Topic="); Serial.print((String)client_id+"/"+topic); Serial.print(" Message="); Serial.println(buffer); } #endif \ No newline at end of file diff --git a/include/wifi_settings.h b/include/wifi_settings.h index d196ed0..45d18c8 100644 --- a/include/wifi_settings.h +++ b/include/wifi_settings.h @@ -1,6 +1,6 @@ -const char ssid[] = "ssid"; -const char pass[] = "pass"; +const char ssid[] = ""; +const char pass[] = ""; const char mqtt_host[] = "10.0.0.1"; const char client_id[] = "hydroponic"; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b17ed7d..e573086 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,13 @@ #include + #include "wifi_functions.h" - bool debug=true; //print Serial information + + #include "helpfunctions.h" #include "ADS1X15.h" @@ -15,6 +17,9 @@ ADS1115 ADS(0x48); // ######## Temperature #include "temperature.h" + + + // ######## EC #include "ec.h" @@ -31,6 +36,8 @@ ADS1115 ADS(0x48); #include "soilmoisture.h" + + unsigned long last_check=0; @@ -72,6 +79,9 @@ void setup() { Serial.println("Setup Flow"); flow_setup(); + Serial.println("Setup Soilmoisture"); + sm_setup(); + Serial.println("Finished Setup"); delay(200); @@ -96,6 +106,8 @@ void setup() { void loop() { unsigned long loopmillis=millis(); + enableTiming=true; //reactivate + ec_loop(loopmillis); @@ -208,10 +220,60 @@ void loop() { if (waterlevel_failcounter>0) { Serial.print(" fails="); Serial.print(waterlevel_failcounter); }*/ - Serial.println(); + Serial.println(); + + + + } + + if (mqtt_loop(loopmillis)) { + if (sendallnext_flag) { + sendallnext_flag=false; + enableTiming=false; + } + + if (tempCmean_reservoir!=DEVICE_DISCONNECTED_C) { + publishValueTimed("temperature/reservoir",tempCmean_reservoir,2,timing_temperature_reservoir,loopmillis); + } + if (tempCmean_air!=DEVICE_DISCONNECTED_C) { + publishValueTimed("temperature/air",tempCmean_air,2,timing_temperature_air,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); + } + + publishValueTimed("flow/flow",flow,2,timing_flow,loopmillis); + + + 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); + } + } + + + + + + }