Uno+WiFi Hydroponics Controller
A simple cheap hydroponics controller with remote monitoring capability.
Components and supplies
Arduino UNO Wifi Rev.3
8 Channel Relay Controller
Ultrasonic Sensor - HC-SR04 (Generic)
RTC module DS1307
DHT 22 arduino-compatible-temperature-and-humidity-sensor-module
Arduino Compatible DC Voltage Regulator
Duinotech-1-3-inch-monochrome-oled-display
Apps and platforms
Firebase
Project description
Code
Hydroponics WiFi
arduino
Connect to local WiFi connection. Connects to Firebase demo database. Receives and parse serial status data.
1#include <Arduino.h> 2#include <ESP8266WiFi.h> 3#include <Firebase_ESP_Client.h> 4#include <WiFiUdp.h> 5#include "addons/TokenHelper.h" // Provide the token generation process info. 6#include "addons/RTDBHelper.h" // Provide the RTDB payload printing info and other helper functions. 7 8#define WIFI_SSID "************" 9#define WIFI_PASSWORD "*************" 10#define API_KEY "************************" 11#define USER_EMAIL "*****************" 12#define USER_PASSWORD "****************" 13#define DATABASE_URL "https://esp-firebase-demo-cba62-default-rtdb.asia-southeast1.firebasedatabase.app/" 14 15// Define Firebase objects 16FirebaseData fbdo; // defines FirebaseData object. 17FirebaseAuth auth; // defines FirebaseData object needed for authentication. 18FirebaseConfig config; // defines FirebaseData object needed for configuration data. 19 20String uid; // Variable to save USER UID 21String databasePath; // Database main path (to be updated in setup with the user UID) 22String n0,n1,n2,n3,n4,n5,n6,n7,n8,n9; // Database child nodes 23String parentPath; // Parent Node (to be updated in every loop) 24const byte numChars = 220; // Max characters in serial string for parsing. 25char receivedChars[numChars]; 26char tempChars[numChars]; // temporary array for use when parsing 27char d1[numChars] = {0}, d2[numChars] = {0}, d3[numChars] = {0}, d4[numChars] = {0}, // variables to hold the parsed data 28 d5[numChars] = {0}, d6[numChars] = {0}, d7[numChars] = {0}, d8[numChars] = {0}, d9[numChars] = {0}, 29 d10[numChars] = {0}; 30boolean newData = false; 31 32FirebaseJson json; 33 34// Timer variables (send new readings every three minutes) 35unsigned long sendDataPrevMillis = 0; 36unsigned long timerDelay = 10000; 37 38// Initialize WiFi 39void initWiFi() { 40 WiFi.begin(WIFI_SSID, WIFI_PASSWORD); Serial.print("Connecting to WiFi .."); 41 while (WiFi.status() != WL_CONNECTED) { 42 Serial.print('.'); 43 delay(1000); 44 } 45 Serial.println(WiFi.localIP()); Serial.println(); 46} 47 48void setup() { 49 Serial.begin(115200); 50 initWiFi(); 51 config.api_key = API_KEY; // Assign the api key (required) 52 auth.user.email = USER_EMAIL; // Assign the user sign in credentials 53 auth.user.password = USER_PASSWORD; 54 config.database_url = DATABASE_URL; // Assign the RTDB URL (required) 55 Firebase.reconnectWiFi(true); 56 fbdo.setResponseSize(4096); 57 58 // Assign the callback function for the long running token generation task */ 59 config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h 60 61 // Assign the maximum retry of token generation 62 config.max_token_generation_retry = 5; 63 64 // Initialize the library with the Firebase authen and config 65 Firebase.begin(&config, &auth); 66 67 // Getting the user UID might take a few seconds 68 Serial.println("Getting User UID"); 69 while ((auth.token.uid) == "") { 70 Serial.print('.'); 71 delay(1000); 72 } 73 // Print user UID 74 uid = auth.token.uid.c_str(); 75 Serial.print("User UID: "); 76 Serial.println(uid); 77 78 // Update database path 79 databasePath = "/UsersData/" + uid + "/readings"; 80 81 // Update database path for data readings. 82 n0 = databasePath + "/a"; n1 = databasePath + "/b"; n2 = databasePath + "/c"; 83 n3 = databasePath + "/d"; n4 = databasePath + "/e"; n5 = databasePath + "/f"; 84 n6 = databasePath + "/g"; n7 = databasePath + "/h"; n8 = databasePath + "/i"; 85 n9 = databasePath + "/j"; 86} 87 88void loop() { 89 recvWithStartEndMarkers(); 90 if (newData == true) { 91 strcpy(tempChars, receivedChars); // this temporary copy is necessary to protect the original data 92 // because strtok() used in parseData() replaces the commas with \\0 93 parseData(); 94 SendData(); 95 newData = false; 96 } 97} 98 99void recvWithStartEndMarkers() { 100 static boolean recvInProgress = false; 101 static byte ndx = 0; 102 char startMarker = '<'; 103 char endMarker = '>'; 104 char rc; 105 106 while (Serial.available() > 0 && newData == false) { 107 rc = Serial.read(); 108 109 if (recvInProgress == true) { 110 if (rc != endMarker) { 111 receivedChars[ndx] = rc; 112 ndx++; 113 if (ndx >= numChars) { 114 ndx = numChars - 1; 115 } 116 } 117 else { 118 receivedChars[ndx] = '\\0'; // terminate the string 119 recvInProgress = false; 120 ndx = 0; 121 newData = true; 122 } 123 } 124 125 else if (rc == startMarker) { 126 recvInProgress = true; 127 } 128 } 129} 130 131//============ 132 133void parseData() { // split the data into its parts & assign to database child nodes. 134 135 char * strtokIndx; // this is used by strtok() as an index 136 137 strtokIndx = strtok(tempChars, ","); strcpy(d1, strtokIndx);json.set(n0.c_str(), String(d1)); 138 strtokIndx = strtok(NULL, ","); strcpy(d2, strtokIndx); json.set(n1.c_str(), String(d2)); 139 strtokIndx = strtok(NULL, ","); strcpy(d3, strtokIndx); json.set(n2.c_str(), String(d3)); 140 strtokIndx = strtok(NULL, ","); strcpy(d4, strtokIndx); json.set(n3.c_str(), String(d4)); 141 strtokIndx = strtok(NULL, ","); strcpy(d5, strtokIndx); json.set(n4.c_str(), String(d5)); 142 strtokIndx = strtok(NULL, ","); strcpy(d6, strtokIndx); json.set(n5.c_str(), String(d6)); 143 strtokIndx = strtok(NULL, ","); strcpy(d7, strtokIndx); json.set(n6.c_str(), String(d7)); 144 strtokIndx = strtok(NULL, ","); strcpy(d8, strtokIndx); json.set(n7.c_str(), String(d8)); 145 strtokIndx = strtok(NULL, ","); strcpy(d9, strtokIndx); json.set(n8.c_str(), String(d9)); 146 strtokIndx = strtok(NULL, ","); strcpy(d10, strtokIndx); json.set(n9.c_str(), String(d10)); 147 148} 149 150void SendData() { 151 // Send new readings to database 152 if (Firebase.ready() && (millis() - sendDataPrevMillis > timerDelay || sendDataPrevMillis == 0)) { 153 sendDataPrevMillis = millis(); 154 155 parentPath = databasePath + "/"; 156 157 Serial.printf("Set json... %s\ 158", Firebase.RTDB.setJSON(&fbdo, parentPath.c_str(), &json) ? "ok" : fbdo.errorReason().c_str()); 159 } 160}
Hydroponics_core
arduino
Collects sensor input, sets event times (using external RTC) and controls the digital outputs to the relay board. Displays system status on OLED. Prepares status words for transmission onto serial bus.
1#include <RTClib.h> 2#include <DHT_U.h> 3#include <U8glib.h> 4#include <NewPing.h> 5 6RTC_DS1307 rtc; //Real Time Clock. 7DHT_Unified dht(12, DHT22); //Temperature & Humidity Sensor 8U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9); //OLED Display. 9NewPing sonar(7, 8, 300); //Ultra-Sonic Transducer. 10 11int Pump = 2, CircFan = 3, TankFan = 4, LED = 5, CoolFan = 6; //Digital ports to 12VDC relay board. 12int LoadVolts = A2, PanelVolts = A3; // select the input pin for the potentiometer 13uint32_t delayMS; //DHT sensor delay. 14String dH[4] = {"", "<", ">", ","}; //Data Null,Header,Terminators,Seperator. 15String dM[10]; //Number of data messages to be placed on serial bus. 16 17void setup() { 18 19 pinMode(Pump, OUTPUT), pinMode(LED, OUTPUT), pinMode(CircFan, OUTPUT); 20 pinMode(CoolFan, OUTPUT), pinMode(TankFan, OUTPUT), pinMode(7, INPUT); 21 22 Serial.begin(115200); 23 rtc.begin(); 24 //rtc.adjust(DateTime(22, 05, 25, 10 , 14, 00)); 25 dht.begin(); 26 u8g.setRot180(); 27 sensor_t sensor; 28 dht.temperature().getSensor(&sensor); 29 dht.humidity().getSensor(&sensor); 30 delayMS = sensor.min_delay / 1000; 31} 32 33void loop() { 34 35 // Get date & time from RTC. 36 char Date[] = "hh:mm:ss"; 37 DateTime now = rtc.now(); now.toString(Date); 38 int nH = now.hour(), nM = now.minute(), nD = now.day(); 39 40 // Display Time and static text on OLED. 41 u8g.firstPage(); do { 42 u8g.setFont(u8g_font_6x10); u8g.setColorIndex(255); 43 u8g.drawStr(0, 10, "HYDROPONICS" ); u8g.drawStr(80, 10, (Date)); u8g.drawStr(66, 20, "Level"); 44 u8g.drawStr(116, 20, "cm"); u8g.drawCircle(119, 23, 1); u8g.drawStr(66, 30, "Temp"); u8g.drawStr(122, 30, "C"); 45 u8g.drawStr(66, 40, "Hum"); u8g.drawStr(110, 40, "%RH"); u8g.drawStr(66, 50, "Load"); u8g.drawStr(120, 50, "V"); 46 dM[0] = dH[0] + "Time " + (Date) + dH[3]; 47 48 // Hydroponic Gully Pump Timer. 49 if ((nH > (7)) && (nH < (22)) && (nM > (0)) && (nM < (5))) 50 { 51 digitalWrite (Pump, HIGH); 52 u8g.drawStr(0, 20, "Pump ON"); 53 dM[1] = "Gully Pump ON" + dH[3]; 54 } 55 else { 56 digitalWrite (Pump, LOW); 57 u8g.drawStr(0, 20, "Pump 00>05"); 58 dM[1] = "Gully Pump [00-05]" + dH[3]; 59 } 60 61 // Air Cooling Fans Timer. 62 if ((nH > (11)) && (nH < (17)) && (nM > (9)) && (nM < (15))) 63 { 64 digitalWrite (CoolFan, HIGH); 65 u8g.drawStr(0, 30, "Cool ON"); 66 dM[2] = "Cooling Fan ON" + dH[3]; 67 } 68 else { 69 digitalWrite (CoolFan, LOW); 70 u8g.drawStr(0, 30, "Cool 09>15"); 71 dM[2] = "Cooling Fans [09-15]" + dH[3]; 72 } 73 74 // Air Cirulation Fans Timer. 75 if ((nH > (6)) && (nH < (21)) && (nM > (24)) && (nM < (30))) 76 { 77 digitalWrite (CircFan, HIGH); 78 u8g.drawStr(0, 40, "Circ ON"); 79 dM[3] = "Circulation Fans ON" + dH[3]; 80 } 81 else { 82 digitalWrite (CircFan, LOW); 83 u8g.drawStr(0, 40, "Circ 24>30"); 84 dM[3] = "Circulation Fans [24-30]" + dH[3]; 85 } 86 87 // Tank Air Circulation Timer. 88 if ((nH > (7)) && (nH < (21)) && (nM > (34)) && (nM < (40))) 89 { 90 digitalWrite (TankFan, HIGH); 91 u8g.drawStr(0, 50, "Tank ON"); 92 dM[4] = "Tank Fan" + dH[3]; 93 } 94 else { 95 digitalWrite (TankFan, LOW); 96 u8g.drawStr(0, 50, "Tank 34>40"); 97 dM[4] = "Tank Fan [34-40]" + dH[3]; 98 } 99 100 // LED Panels Light Sensor Activation Timer. 101 if ((nH > (19)) && (nH < (20))) 102 { 103 digitalWrite (LED, HIGH); 104 u8g.drawStr(0, 60, "LEDs ON"); 105 dM[5] = "LED Light Sensor ON" + dH[3]; 106 } 107 else { 108 digitalWrite (LED, LOW); 109 u8g.drawStr(0, 60, "LEDs OFF"); 110 dM[5] = "LED Light Sensor OFF" + dH[3]; 111 } 112 113 // Read Temperature & Humidity. 114 sensors_event_t event; 115 char Temp[1], Hum[1]; 116 dht.temperature().getEvent(&event); 117 dtostrf(event.temperature, 0, 1, Temp); 118 u8g.drawStr(94, 30, Temp); 119 dM[6] = dH[0] + "Temperature " + (Temp) + " °C" + dH[3]; //Display Temperature. 120 121 dht.humidity().getEvent(&event); 122 dtostrf(event.relative_humidity, 0, 1, Hum); 123 u8g.drawStr(85, 40, Hum); 124 dM[7] = dH[0] + "Humidity " + (Hum) + " %RH" + dH[3];//Disply Humidity. 125 126 // Read Nutrient Tank Level. 127 char Lbuf[1]; 128 int uS = sonar.ping(); dtostrf((110 - (uS / US_ROUNDTRIP_CM)), 0, 0, Lbuf); 129 int level = (110 - (uS / US_ROUNDTRIP_CM)); 130 // Reset Ultra-Sonic Transducer in case of error. 131 if (uS == 0) 132 { u8g.drawStr(70, 20, "Level Error"); dM[8] = dH[0] + "Level Error" + dH[3]; 133 pinMode(7, OUTPUT); delay(20); digitalWrite(7, LOW); delay(20); pinMode(7, INPUT); delay(20); 134 } 135 else { 136 u8g.drawStr(98, 20, Lbuf); 137 dM[8] = dH[0] + "Tank Level " + (Lbuf) + " cm" + dH[3]; 138 } 139 140 // Read Load Voltage. 141 char LoadValue[1], PanelValue[1]; int LoadV, PanelV; 142 dtostrf(((analogRead(LoadVolts))* .0049 * 3), 0, 1, LoadValue); u8g.drawStr(92, 50, LoadValue); 143 dM[9] = dH[0] + "Load " + (LoadValue) + " VDC" + dH[3]; //Display Load Voltage. 144 145 } 146 while ( u8g.nextPage() ); 147 //Place data on serial bus. 148 Serial.print((dH[1]) + (dM[0]) + (dM[1]) + (dM[2]) + (dM[3]) + (dM[4]) + (dM[5]) + (dM[6]) + (dM[7]) + (dM[8]) + (dM[9]) + (dH[2])); 149 150}
Hydroponics WiFi
arduino
Connect to local WiFi connection. Connects to Firebase demo database. Receives and parse serial status data.
1#include <Arduino.h> 2#include <ESP8266WiFi.h> 3#include <Firebase_ESP_Client.h> 4#include <WiFiUdp.h> 5#include "addons/TokenHelper.h" // Provide the token generation process info. 6#include "addons/RTDBHelper.h" // Provide the RTDB payload printing info and other helper functions. 7 8#define WIFI_SSID "************" 9#define WIFI_PASSWORD "*************" 10#define API_KEY "************************" 11#define USER_EMAIL "*****************" 12#define USER_PASSWORD "****************" 13#define DATABASE_URL "https://esp-firebase-demo-cba62-default-rtdb.asia-southeast1.firebasedatabase.app/" 14 15// Define Firebase objects 16FirebaseData fbdo; // defines FirebaseData object. 17FirebaseAuth auth; // defines FirebaseData object needed for authentication. 18FirebaseConfig config; // defines FirebaseData object needed for configuration data. 19 20String uid; // Variable to save USER UID 21String databasePath; // Database main path (to be updated in setup with the user UID) 22String n0,n1,n2,n3,n4,n5,n6,n7,n8,n9; // Database child nodes 23String parentPath; // Parent Node (to be updated in every loop) 24const byte numChars = 220; // Max characters in serial string for parsing. 25char receivedChars[numChars]; 26char tempChars[numChars]; // temporary array for use when parsing 27char d1[numChars] = {0}, d2[numChars] = {0}, d3[numChars] = {0}, d4[numChars] = {0}, // variables to hold the parsed data 28 d5[numChars] = {0}, d6[numChars] = {0}, d7[numChars] = {0}, d8[numChars] = {0}, d9[numChars] = {0}, 29 d10[numChars] = {0}; 30boolean newData = false; 31 32FirebaseJson json; 33 34// Timer variables (send new readings every three minutes) 35unsigned long sendDataPrevMillis = 0; 36unsigned long timerDelay = 10000; 37 38// Initialize WiFi 39void initWiFi() { 40 WiFi.begin(WIFI_SSID, WIFI_PASSWORD); Serial.print("Connecting to WiFi .."); 41 while (WiFi.status() != WL_CONNECTED) { 42 Serial.print('.'); 43 delay(1000); 44 } 45 Serial.println(WiFi.localIP()); Serial.println(); 46} 47 48void setup() { 49 Serial.begin(115200); 50 initWiFi(); 51 config.api_key = API_KEY; // Assign the api key (required) 52 auth.user.email = USER_EMAIL; // Assign the user sign in credentials 53 auth.user.password = USER_PASSWORD; 54 config.database_url = DATABASE_URL; // Assign the RTDB URL (required) 55 Firebase.reconnectWiFi(true); 56 fbdo.setResponseSize(4096); 57 58 // Assign the callback function for the long running token generation task */ 59 config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h 60 61 // Assign the maximum retry of token generation 62 config.max_token_generation_retry = 5; 63 64 // Initialize the library with the Firebase authen and config 65 Firebase.begin(&config, &auth); 66 67 // Getting the user UID might take a few seconds 68 Serial.println("Getting User UID"); 69 while ((auth.token.uid) == "") { 70 Serial.print('.'); 71 delay(1000); 72 } 73 // Print user UID 74 uid = auth.token.uid.c_str(); 75 Serial.print("User UID: "); 76 Serial.println(uid); 77 78 // Update database path 79 databasePath = "/UsersData/" + uid + "/readings"; 80 81 // Update database path for data readings. 82 n0 = databasePath + "/a"; n1 = databasePath + "/b"; n2 = databasePath + "/c"; 83 n3 = databasePath + "/d"; n4 = databasePath + "/e"; n5 = databasePath + "/f"; 84 n6 = databasePath + "/g"; n7 = databasePath + "/h"; n8 = databasePath + "/i"; 85 n9 = databasePath + "/j"; 86} 87 88void loop() { 89 recvWithStartEndMarkers(); 90 if (newData == true) { 91 strcpy(tempChars, receivedChars); // this temporary copy is necessary to protect the original data 92 // because strtok() used in parseData() replaces the commas with \\0 93 parseData(); 94 SendData(); 95 newData = false; 96 } 97} 98 99void recvWithStartEndMarkers() { 100 static boolean recvInProgress = false; 101 static byte ndx = 0; 102 char startMarker = '<'; 103 char endMarker = '>'; 104 char rc; 105 106 while (Serial.available() > 0 && newData == false) { 107 rc = Serial.read(); 108 109 if (recvInProgress == true) { 110 if (rc != endMarker) { 111 receivedChars[ndx] = rc; 112 ndx++; 113 if (ndx >= numChars) { 114 ndx = numChars - 1; 115 } 116 } 117 else { 118 receivedChars[ndx] = '\\0'; // terminate the string 119 recvInProgress = false; 120 ndx = 0; 121 newData = true; 122 } 123 } 124 125 else if (rc == startMarker) { 126 recvInProgress = true; 127 } 128 } 129} 130 131//============ 132 133void parseData() { // split the data into its parts & assign to database child nodes. 134 135 char * strtokIndx; // this is used by strtok() as an index 136 137 strtokIndx = strtok(tempChars, ","); strcpy(d1, strtokIndx);json.set(n0.c_str(), String(d1)); 138 strtokIndx = strtok(NULL, ","); strcpy(d2, strtokIndx); json.set(n1.c_str(), String(d2)); 139 strtokIndx = strtok(NULL, ","); strcpy(d3, strtokIndx); json.set(n2.c_str(), String(d3)); 140 strtokIndx = strtok(NULL, ","); strcpy(d4, strtokIndx); json.set(n3.c_str(), String(d4)); 141 strtokIndx = strtok(NULL, ","); strcpy(d5, strtokIndx); json.set(n4.c_str(), String(d5)); 142 strtokIndx = strtok(NULL, ","); strcpy(d6, strtokIndx); json.set(n5.c_str(), String(d6)); 143 strtokIndx = strtok(NULL, ","); strcpy(d7, strtokIndx); json.set(n6.c_str(), String(d7)); 144 strtokIndx = strtok(NULL, ","); strcpy(d8, strtokIndx); json.set(n7.c_str(), String(d8)); 145 strtokIndx = strtok(NULL, ","); strcpy(d9, strtokIndx); json.set(n8.c_str(), String(d9)); 146 strtokIndx = strtok(NULL, ","); strcpy(d10, strtokIndx); json.set(n9.c_str(), String(d10)); 147 148} 149 150void SendData() { 151 // Send new readings to database 152 if (Firebase.ready() && (millis() - sendDataPrevMillis > timerDelay || sendDataPrevMillis == 0)) { 153 sendDataPrevMillis = millis(); 154 155 parentPath = databasePath + "/"; 156 157 Serial.printf("Set json... %s\ 158", Firebase.RTDB.setJSON(&fbdo, parentPath.c_str(), &json) ? "ok" : fbdo.errorReason().c_str()); 159 } 160}
Comments
Only logged in users can leave comments